Files
Electron.NET/ElectronNET.Host/main.js

324 lines
11 KiB
JavaScript
Raw Normal View History

2018-07-14 15:55:09 +08:00
const { app } = require('electron');
const { BrowserWindow } = require('electron');
const { protocol } = require('electron');
2017-10-06 02:09:43 +02:00
const path = require('path');
2020-04-30 22:31:12 +10:00
const cProcess = require('child_process').spawn;
const portscanner = require('portscanner');
2019-05-18 15:04:11 +02:00
const imageSize = require('image-size');
2019-01-02 19:48:14 +01:00
let io, server, browserWindows, ipc, apiProcess, loadURL;
2018-07-14 15:55:09 +08:00
let appApi, menu, dialogApi, notification, tray, webContents;
2019-05-20 01:08:26 +02:00
let globalShortcut, shellApi, screen, clipboard, autoUpdater;
2020-04-23 03:29:52 +02:00
let commandLine, browserView;
2020-05-11 12:59:21 -05:00
let powerMonitor;
let splashScreen, hostHook;
let mainWindowId, nativeTheme;
let dock;
let launchFile;
let launchUrl;
2018-06-14 10:47:08 +08:00
let manifestJsonFileName = 'electron.manifest.json';
2020-04-30 22:31:12 +10:00
let watchable = false;
if (app.commandLine.hasSwitch('manifest')) {
manifestJsonFileName = app.commandLine.getSwitchValue('manifest');
};
2020-04-30 22:31:12 +10:00
if (app.commandLine.hasSwitch('watch')) {
watchable = true;
};
let currentBinPath = path.join(__dirname.replace('app.asar', ''), 'bin');
let manifestJsonFilePath = path.join(currentBinPath, manifestJsonFileName);
// if watch is enabled lets change the path
if (watchable) {
currentBinPath = path.join(__dirname, '../../'); // go to project directory
manifestJsonFilePath = path.join(currentBinPath, manifestJsonFileName);
}
// handle macOS events for opening the app with a file, etc
app.on('will-finish-launching', () => {
app.on('open-file', (evt, file) => {
evt.preventDefault();
launchFile = file;
})
app.on('open-url', (evt, url) => {
evt.preventDefault();
launchUrl = url;
})
});
const manifestJsonFile = require(manifestJsonFilePath);
if (manifestJsonFile.singleInstance || manifestJsonFile.aspCoreBackendPort) {
const mainInstance = app.requestSingleInstanceLock();
app.on('second-instance', () => {
const windows = BrowserWindow.getAllWindows();
if (windows.length) {
if (windows[0].isMinimized()) {
windows[0].restore();
}
windows[0].focus();
}
2018-06-14 10:47:08 +08:00
});
2018-07-22 21:35:44 +02:00
if (!mainInstance) {
2018-06-14 10:47:08 +08:00
app.quit();
}
}
2017-10-06 02:09:43 +02:00
app.on('ready', () => {
// Fix ERR_UNKNOWN_URL_SCHEME using file protocol
// https://github.com/electron/electron/issues/23757
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = request.url.replace('file:///', '');
callback(pathname);
});
2018-07-22 21:35:44 +02:00
if (isSplashScreenEnabled()) {
startSplashScreen();
}
2020-11-14 19:15:54 -06:00
// Added default port as configurable for port restricted environments.
let defaultElectronPort = 8000;
if (manifestJsonFile.electronPort) {
2020-11-14 19:15:54 -06:00
defaultElectronPort = (manifestJsonFile.electronPort)
}
2020-11-14 19:15:54 -06:00
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(defaultElectronPort, 65535, 'localhost', function (error, port) {
2020-05-01 15:52:54 +02:00
console.log('Electron Socket IO Port: ' + port);
startSocketApiBridge(port);
});
});
app.on('quit', async (event, exitCode) => {
await server.close();
apiProcess.kill();
});
2018-07-22 21:35:44 +02:00
function isSplashScreenEnabled() {
if (manifestJsonFile.hasOwnProperty('splashscreen')) {
if (manifestJsonFile.splashscreen.hasOwnProperty('imageFile')) {
return Boolean(manifestJsonFile.splashscreen.imageFile);
2019-05-18 15:04:11 +02:00
}
}
return false;
2018-07-22 21:35:44 +02:00
}
function startSplashScreen() {
2019-05-18 15:04:11 +02:00
let imageFile = path.join(currentBinPath, manifestJsonFile.splashscreen.imageFile);
imageSize(imageFile, (error, dimensions) => {
if (error) {
2020-05-01 15:52:54 +02:00
console.log(`load splashscreen error:`);
console.error(error);
2019-05-18 15:04:11 +02:00
throw new Error(error.message);
}
2018-07-22 21:35:44 +02:00
splashScreen = new BrowserWindow({
2019-05-18 15:04:11 +02:00
width: dimensions.width,
height: dimensions.height,
2018-07-22 21:35:44 +02:00
transparent: true,
2019-05-18 15:04:11 +02:00
center: true,
2018-07-22 21:35:44 +02:00
frame: false,
closable: false,
2019-05-18 15:04:11 +02:00
skipTaskbar: true,
show: true
2018-07-22 21:35:44 +02:00
});
2019-05-18 15:04:11 +02:00
app.once('browser-window-focus', () => {
app.once('browser-window-focus', () => {
splashScreen.destroy();
});
2018-07-22 21:35:44 +02:00
});
2019-05-18 15:04:11 +02:00
const loadSplashscreenUrl = path.join(__dirname, 'splashscreen', 'index.html') + '?imgPath=' + imageFile;
splashScreen.loadURL('file://' + loadSplashscreenUrl);
splashScreen.once('closed', () => {
2018-07-22 21:35:44 +02:00
splashScreen = null;
});
2019-05-18 15:04:11 +02:00
});
2018-07-22 21:35:44 +02:00
}
function startSocketApiBridge(port) {
2019-01-02 19:48:14 +01:00
// instead of 'require('socket.io')(port);' we need to use this workaround
// otherwise the Windows Firewall will be triggered
server = require('http').createServer();
io = require('socket.io')();
io.attach(server);
server.listen(port, 'localhost');
server.on('listening', function () {
2020-05-01 15:52:54 +02:00
console.log('Electron Socket started on port %s at %s', server.address().port, server.address().address);
// Now that socket connection is established, we can guarantee port will not be open for portscanner
2020-04-30 22:31:12 +10:00
if (watchable) {
startAspCoreBackendWithWatch(port);
} else {
startAspCoreBackend(port);
}
2019-01-02 19:48:14 +01:00
});
// prototype
app['mainWindowURL'] = "";
app['mainWindow'] = null;
2019-01-02 19:48:14 +01:00
io.on('connection', (socket) => {
2020-05-27 00:43:28 +02:00
socket.on('disconnect', function (reason) {
console.log('Got disconnect! Reason: ' + reason);
try {
if (hostHook) {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
delete require.cache[require.resolve(hostHookScriptFilePath)];
hostHook = undefined;
}
} catch (error) {
console.error(error.message);
}
});
if (global['electronsocket'] === undefined) {
global['electronsocket'] = socket;
global['electronsocket'].setMaxListeners(0);
}
2020-05-01 15:52:54 +02:00
console.log('ASP.NET Core Application connected...', 'global.electronsocket', global['electronsocket'].id, new Date());
if (appApi === undefined) appApi = require('./api/app')(socket, app);
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app);
if (commandLine === undefined) commandLine = require('./api/commandLine')(socket, app);
if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(socket);
if (ipc === undefined) ipc = require('./api/ipc')(socket);
if (menu === undefined) menu = require('./api/menu')(socket);
if (dialogApi === undefined) dialogApi = require('./api/dialog')(socket);
if (notification === undefined) notification = require('./api/notification')(socket);
if (tray === undefined) tray = require('./api/tray')(socket);
if (webContents === undefined) webContents = require('./api/webContents')(socket);
if (globalShortcut === undefined) globalShortcut = require('./api/globalShortcut')(socket);
if (shellApi === undefined) shellApi = require('./api/shell')(socket);
if (screen === undefined) screen = require('./api/screen')(socket);
if (clipboard === undefined) clipboard = require('./api/clipboard')(socket);
if (browserView === undefined) browserView = require('./api/browserView').browserViewApi(socket);
if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(socket);
if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(socket);
if (dock === undefined) dock = require('./api/dock')(socket);
socket.on('register-app-open-file-event', (id) => {
electronSocket = socket;
app.on('open-file', (event, file) => {
event.preventDefault();
electronSocket.emit('app-open-file' + id, file);
});
if (launchFile) {
electronSocket.emit('app-open-file' + id, launchFile);
}
});
socket.on('register-app-open-url-event', (id) => {
electronSocket = socket;
app.on('open-url', (event, url) => {
event.preventDefault();
electronSocket.emit('app-open-url' + id, url);
});
if (launchUrl) {
electronSocket.emit('app-open-url' + id, launchUrl);
}
});
try {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
if (isModuleAvailable(hostHookScriptFilePath) && hostHook === undefined) {
const { HookService } = require(hostHookScriptFilePath);
hostHook = new HookService(socket, app);
hostHook.onHostReady();
}
} catch (error) {
2020-05-01 15:52:54 +02:00
console.error(error.message);
}
2019-01-02 19:48:14 +01:00
});
}
2017-10-06 02:09:43 +02:00
function isModuleAvailable(name) {
try {
require.resolve(name);
return true;
} catch (e) { }
return false;
}
function startAspCoreBackend(electronPort) {
2020-04-30 22:31:12 +10:00
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort)
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
2019-11-02 13:31:18 +01:00
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
}
2019-01-02 19:48:14 +01:00
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
2018-07-22 21:35:44 +02:00
let binaryFile = manifestJsonFile.executable;
2018-07-22 21:35:44 +02:00
const os = require('os');
if (os.platform() === 'win32') {
binaryFile = binaryFile + '.exe';
}
2018-02-09 23:22:03 +08:00
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
2020-04-30 22:31:12 +10:00
apiProcess = cProcess(binFilePath, parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
2017-10-06 03:27:16 +02:00
});
}
}
2020-04-30 22:31:12 +10:00
function startAspCoreBackendWithWatch(electronPort) {
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort)
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
}
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
2020-04-30 22:31:12 +10:00
var options = {
cwd: currentBinPath,
env: process.env,
2020-04-30 22:31:12 +10:00
};
apiProcess = cProcess('dotnet', parameters, options);
apiProcess.stdout.on('data', (data) => {
2020-05-01 15:52:54 +02:00
console.log(`stdout: ${data.toString()}`);
2020-04-30 22:31:12 +10:00
});
}
}
function getEnvironmentParameter() {
if (manifestJsonFile.environment) {
return '--environment=' + manifestJsonFile.environment;
}
return '';
}