From ac77643fc403b1e449532134316f1e880fb91ea8 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 09:10:27 +0200 Subject: [PATCH 01/12] add variable to control kill behaviour --- ElectronNET.Host/main.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index cdb900c..5e74e52 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -101,7 +101,16 @@ app.on('ready', () => { app.on('quit', async (event, exitCode) => { await server.close(); - apiProcess.kill(); + + var shouldKill = true; + + if (manifestJsonFile.hasOwnProperty('killOnQuit')) { + shouldKill = manifestJsonFile.killOnQuit; + } + + if (shouldKill) { + apiProcess.kill(); + } }); function isSplashScreenEnabled() { @@ -141,7 +150,7 @@ function startSplashScreen() { if (manifestJsonFile.splashscreen.hasOwnProperty('timeout')) { var timeout = manifestJsonFile.splashscreen.timeout; setTimeout((t) => { - if (splashScreen != null ) { + if (splashScreen) { splashScreen.hide(); } }, timeout); From bad59463a93aeb0a84240ae696c6cd8a3b3a06c5 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 09:17:50 +0200 Subject: [PATCH 02/12] pass electron process id to child --- ElectronNET.Host/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 5e74e52..54ec5be 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -5,6 +5,7 @@ const path = require('path'); const cProcess = require('child_process').spawn; const portscanner = require('portscanner'); const { imageSize } = require('image-size'); + let io, server, browserWindows, ipc, apiProcess, loadURL; let appApi, menu, dialogApi, notification, tray, webContents; let globalShortcut, shellApi, screen, clipboard, autoUpdater; @@ -305,7 +306,7 @@ function startAspCoreBackend(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Port: ' + aspCoreBackendPort); loadURL = `http://localhost:${aspCoreBackendPort}`; - const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`]; + const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; let binaryFile = manifestJsonFile.executable; const os = require('os'); @@ -348,7 +349,7 @@ function startAspCoreBackendWithWatch(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort); loadURL = `http://localhost:${aspCoreBackendPort}`; - const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`]; + const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; var options = { cwd: currentBinPath, From 67c592a06071b2a179a422177bd14e2913f395b2 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 09:38:37 +0200 Subject: [PATCH 03/12] kill child process when electronize cli is killed --- ElectronNET.CLI/ProcessHelper.cs | 32 ++++++++++++++++++++++++++++++++ ElectronNET.CLI/Program.cs | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/ElectronNET.CLI/ProcessHelper.cs b/ElectronNET.CLI/ProcessHelper.cs index 9e0048f..c0290f3 100644 --- a/ElectronNET.CLI/ProcessHelper.cs +++ b/ElectronNET.CLI/ProcessHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.InteropServices; @@ -6,6 +7,33 @@ namespace ElectronNET.CLI { public class ProcessHelper { + private static ConcurrentDictionary _activeProcess = new(); + + public static void KillActive() + { + foreach(var kv in _activeProcess) + { + if (!kv.Key.HasExited) + { + try + { + kv.Key.CloseMainWindow(); + } + catch + { + + } + try + { + kv.Key.Kill(false); + } + catch + { + + } + } + } + } public static int CmdExecute(string command, string workingDirectoryPath, bool output = true, bool waitForExit = true) { using (Process cmd = new Process()) @@ -43,7 +71,11 @@ namespace ElectronNET.CLI if (waitForExit) { + _activeProcess[cmd] = true; + cmd.WaitForExit(); + + _activeProcess.TryRemove(cmd, out _); } return cmd.ExitCode; diff --git a/ElectronNET.CLI/Program.cs b/ElectronNET.CLI/Program.cs index b35ef6c..891b15e 100644 --- a/ElectronNET.CLI/Program.cs +++ b/ElectronNET.CLI/Program.cs @@ -19,6 +19,12 @@ namespace ElectronNET.CLI Environment.Exit(-1); } + Console.CancelKeyPress += (s,e) => + { + ProcessHelper.KillActive(); + Environment.Exit(-1); + }; + ICommand command = null; switch (args[0]) From e39e34234de5b2b2c12e0e0c0c856e6a1d04c534 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 09:54:00 +0200 Subject: [PATCH 04/12] Update ProcessHelper.cs --- ElectronNET.CLI/ProcessHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ElectronNET.CLI/ProcessHelper.cs b/ElectronNET.CLI/ProcessHelper.cs index c0290f3..5f7d6cc 100644 --- a/ElectronNET.CLI/ProcessHelper.cs +++ b/ElectronNET.CLI/ProcessHelper.cs @@ -25,7 +25,7 @@ namespace ElectronNET.CLI } try { - kv.Key.Kill(false); + kv.Key.Kill(true); } catch { From 8bbe6a96afb8be0f6cf9cad1900ad19b66ba05e3 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 10:34:36 +0200 Subject: [PATCH 05/12] Fix serialization of array of objects --- ElectronNET.API/App.cs | 21 +++++++++++++-------- ElectronNET.API/BrowserWindow.cs | 10 ++++++++-- ElectronNET.API/Dock.cs | 9 +++++++-- ElectronNET.API/Menu.cs | 10 ++++++++-- ElectronNET.API/Tray.cs | 24 +++++++++++++++--------- ElectronNET.API/WindowManager.cs | 1 + 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/ElectronNET.API/App.cs b/ElectronNET.API/App.cs index 0e13d05..274786c 100644 --- a/ElectronNET.API/App.cs +++ b/ElectronNET.API/App.cs @@ -581,7 +581,7 @@ namespace ElectronNET.API /// Options for the relaunch. public void Relaunch(RelaunchOptions relaunchOptions) { - BridgeConnector.EmitSync("appRelaunch", relaunchOptions); + BridgeConnector.EmitSync("appRelaunch", JObject.FromObject(relaunchOptions, _jsonSerializer)); } /// @@ -601,7 +601,7 @@ namespace ElectronNET.API /// public void Focus(FocusOptions focusOptions) { - BridgeConnector.Emit("appFocus", focusOptions); + BridgeConnector.Emit("appFocus", JObject.FromObject(focusOptions, _jsonSerializer)); } /// @@ -891,7 +891,7 @@ namespace ElectronNET.API /// Array of objects. /// The cancellation token. /// Whether the call succeeded. - public Task SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default) => BridgeConnector.OnResult("appSetUserTasks", "appSetUserTasksCompleted", cancellationToken, userTasks); + public Task SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default) => BridgeConnector.OnResult("appSetUserTasks", "appSetUserTasksCompleted", cancellationToken, JArray.FromObject(userTasks, _jsonSerializer)); /// /// Jump List settings for the application. @@ -918,7 +918,7 @@ namespace ElectronNET.API /// Array of objects. public void SetJumpList(JumpListCategory[] categories) { - BridgeConnector.Emit("appSetJumpList", categories); + BridgeConnector.Emit("appSetJumpList", JArray.FromObject(categories, _jsonSerializer)); } /// @@ -1054,7 +1054,7 @@ namespace ElectronNET.API /// /// The cancellation token. /// Result of import. Value of 0 indicates success. - public Task ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default) => BridgeConnector.OnResult("appImportCertificate", "appImportCertificateCompleted", cancellationToken, options); + public Task ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default) => BridgeConnector.OnResult("appImportCertificate", "appImportCertificateCompleted", cancellationToken, JObject.FromObject(options, _jsonSerializer)); /// /// Memory and cpu usage statistics of all the processes associated with the app. @@ -1120,7 +1120,7 @@ namespace ElectronNET.API /// The cancellation token. public Task GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default) => options is null ? BridgeConnector.OnResult("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken) - : BridgeConnector.OnResult("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken, options); + : BridgeConnector.OnResult("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken, JObject.FromObject(options, _jsonSerializer)); /// /// Set the app's login item settings. @@ -1130,7 +1130,7 @@ namespace ElectronNET.API /// public void SetLoginItemSettings(LoginSettings loginSettings) { - BridgeConnector.Emit("appSetLoginItemSettings", loginSettings); + BridgeConnector.Emit("appSetLoginItemSettings", JObject.FromObject(loginSettings, _jsonSerializer)); } /// @@ -1179,7 +1179,7 @@ namespace ElectronNET.API /// About panel options. public void SetAboutPanelOptions(AboutPanelOptions options) { - BridgeConnector.Emit("appSetAboutPanelOptions", options); + BridgeConnector.Emit("appSetAboutPanelOptions", JObject.FromObject(options, _jsonSerializer)); } /// @@ -1243,5 +1243,10 @@ namespace ElectronNET.API /// The event name /// The handler public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn); + + private readonly JsonSerializer _jsonSerializer = new JsonSerializer() + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + }; } } \ No newline at end of file diff --git a/ElectronNET.API/BrowserWindow.cs b/ElectronNET.API/BrowserWindow.cs index 8402d2f..0b8222c 100644 --- a/ElectronNET.API/BrowserWindow.cs +++ b/ElectronNET.API/BrowserWindow.cs @@ -1682,7 +1682,7 @@ namespace ElectronNET.API public void SetMenu(MenuItem[] menuItems) { menuItems.AddMenuItemsId(); - BridgeConnector.Emit("browserWindowSetMenu", Id, menuItems); + BridgeConnector.Emit("browserWindowSetMenu", Id, JArray.FromObject(menuItems, _jsonSerializer)); _items.AddRange(menuItems); BridgeConnector.Off("windowMenuItemClicked"); @@ -1788,7 +1788,7 @@ namespace ElectronNET.API }); thumbarButtons.AddThumbarButtonsId(); - BridgeConnector.Emit("browserWindowSetThumbarButtons", Id, thumbarButtons); + BridgeConnector.Emit("browserWindowSetThumbarButtons", Id, JArray.FromObject(thumbarButtons, _jsonSerializer)); _thumbarButtons.Clear(); _thumbarButtons.AddRange(thumbarButtons); @@ -2003,5 +2003,11 @@ namespace ElectronNET.API { BridgeConnector.Emit("browserWindow-setBrowserView", Id, browserView.Id); } + + private static readonly JsonSerializer _jsonSerializer = new JsonSerializer() + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; } } diff --git a/ElectronNET.API/Dock.cs b/ElectronNET.API/Dock.cs index 9706341..9c00b2d 100644 --- a/ElectronNET.API/Dock.cs +++ b/ElectronNET.API/Dock.cs @@ -138,7 +138,7 @@ namespace ElectronNET.API public void SetMenu(MenuItem[] menuItems) { menuItems.AddMenuItemsId(); - BridgeConnector.Emit("dock-setMenu", menuItems); + BridgeConnector.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer)); _items.AddRange(menuItems); BridgeConnector.Off("dockMenuItemClicked"); @@ -146,7 +146,6 @@ namespace ElectronNET.API MenuItem menuItem = _items.GetMenuItem(id); menuItem?.Click(); }); - } /// @@ -163,5 +162,11 @@ namespace ElectronNET.API { BridgeConnector.Emit("dock-setIcon", image); } + + private static readonly JsonSerializer _jsonSerializer = new JsonSerializer() + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; } } \ No newline at end of file diff --git a/ElectronNET.API/Menu.cs b/ElectronNET.API/Menu.cs index 76bba2e..aa98613 100644 --- a/ElectronNET.API/Menu.cs +++ b/ElectronNET.API/Menu.cs @@ -58,7 +58,7 @@ namespace ElectronNET.API menuItems.AddMenuItemsId(); menuItems.AddSubmenuTypes(); - BridgeConnector.Emit("menu-setApplicationMenu", menuItems); + BridgeConnector.Emit("menu-setApplicationMenu", JArray.FromObject(menuItems, _jsonSerializer)); _menuItems.AddRange(menuItems); BridgeConnector.Off("menuItemClicked"); @@ -87,7 +87,7 @@ namespace ElectronNET.API menuItems.AddMenuItemsId(); menuItems.AddSubmenuTypes(); - BridgeConnector.Emit("menu-setContextMenu", browserWindow.Id, menuItems); + BridgeConnector.Emit("menu-setContextMenu", browserWindow.Id, JArray.FromObject(menuItems, _jsonSerializer)); if (!_contextMenuItems.ContainsKey(browserWindow.Id)) { @@ -112,5 +112,11 @@ namespace ElectronNET.API { BridgeConnector.Emit("menu-contextMenuPopup", browserWindow.Id); } + + private JsonSerializer _jsonSerializer = new JsonSerializer() + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; } } diff --git a/ElectronNET.API/Tray.cs b/ElectronNET.API/Tray.cs index fb5db5c..c37f5fe 100644 --- a/ElectronNET.API/Tray.cs +++ b/ElectronNET.API/Tray.cs @@ -242,7 +242,7 @@ namespace ElectronNET.API public void Show(string image, MenuItem[] menuItems) { menuItems.AddMenuItemsId(); - BridgeConnector.Emit("create-tray", image, menuItems); + BridgeConnector.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer)); _items.Clear(); _items.AddRange(menuItems); @@ -324,33 +324,39 @@ namespace ElectronNET.API public Task IsDestroyedAsync() => BridgeConnector.OnResult("tray-isDestroyed", "tray-isDestroyedCompleted"); private const string ModuleName = "tray"; + /// /// Subscribe to an unmapped event on the module. /// /// The event name /// The handler - public void On(string eventName, Action fn) - => Events.Instance.On(ModuleName, eventName, fn); + public void On(string eventName, Action fn) => Events.Instance.On(ModuleName, eventName, fn); + /// /// Subscribe to an unmapped event on the module. /// /// The event name /// The handler - public void On(string eventName, Action fn) - => Events.Instance.On(ModuleName, eventName, fn); + public void On(string eventName, Action fn) => Events.Instance.On(ModuleName, eventName, fn); + /// /// Subscribe to an unmapped event on the module once. /// /// The event name /// The handler - public void Once(string eventName, Action fn) - => Events.Instance.Once(ModuleName, eventName, fn); + public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn); + /// /// Subscribe to an unmapped event on the module once. /// /// The event name /// The handler - public void Once(string eventName, Action fn) - => Events.Instance.Once(ModuleName, eventName, fn); + public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn); + + private JsonSerializer _jsonSerializer = new JsonSerializer() + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; } } diff --git a/ElectronNET.API/WindowManager.cs b/ElectronNET.API/WindowManager.cs index cf91098..e8869d3 100644 --- a/ElectronNET.API/WindowManager.cs +++ b/ElectronNET.API/WindowManager.cs @@ -150,6 +150,7 @@ namespace ElectronNET.API ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore }; + BridgeConnector.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl); } From 144a0a0ddc03271b95b9a46a1c9ae4b9b7daef9b Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 11:14:21 +0200 Subject: [PATCH 06/12] change argument name, detach process on creation --- ElectronNET.Host/main.js | 64 +++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 54ec5be..cc12ee6 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -103,13 +103,13 @@ app.on('ready', () => { app.on('quit', async (event, exitCode) => { await server.close(); - var shouldKill = true; + var detachedProcess = false; - if (manifestJsonFile.hasOwnProperty('killOnQuit')) { - shouldKill = manifestJsonFile.killOnQuit; + if (manifestJsonFile.hasOwnProperty('detachedProcess')) { + detachedProcess = manifestJsonFile.detachedProcess; } - if (shouldKill) { + if (!detachedProcess) { apiProcess.kill(); } }); @@ -305,8 +305,8 @@ function startAspCoreBackend(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Port: ' + aspCoreBackendPort); - loadURL = `http://localhost:${aspCoreBackendPort}`; - const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; + loadURL = 'http://localhost:${aspCoreBackendPort}'; + const parameters = [getEnvironmentParameter(), '/electronPort=${electronPort}', '/electronWebPort=${aspCoreBackendPort}', '/electronPID=${process.pid}']; let binaryFile = manifestJsonFile.executable; const os = require('os'); @@ -314,25 +314,38 @@ function startAspCoreBackend(electronPort) { binaryFile = binaryFile + '.exe'; } + var detachedProcess = false; + + if (manifestJsonFile.hasOwnProperty('detachedProcess')) { + detachedProcess = manifestJsonFile.detachedProcess; + } + let binFilePath = path.join(currentBinPath, binaryFile); - var options = { cwd: currentBinPath }; + + var options = { cwd: currentBinPath, detached: detachedProcess }; + apiProcess = cProcess(binFilePath, parameters, options); apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); + console.log('stdout: ${data.toString()}'); }); apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); + console.log('stderr: ${data.toString()}'); }); apiProcess.on('close', (code) => { - console.log(`ASP.NET Process exited with code ${code}`); + console.log('ASP.NET Process exited with code ${code}'); if (code != 0) { - console.log(`Will quit Electron, as exit code != 0 (got ${code})`); + console.log('Will quit Electron, as exit code != 0 (got ${code})'); app.exit(code); } }); + + if (detachedProcess) { + console.log('Detached from ASP.NET process'); + apiProcess.unref(); + } } } @@ -348,30 +361,39 @@ function startAspCoreBackendWithWatch(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort); - loadURL = `http://localhost:${aspCoreBackendPort}`; - const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; + loadURL = 'http://localhost:${aspCoreBackendPort}'; + const parameters = ['watch', 'run', getEnvironmentParameter(), '/electronPort=${electronPort}', '/electronWebPort=${aspCoreBackendPort}', '/electronPID=${process.pid}']; + + var detachedProcess = false; + + if (manifestJsonFile.hasOwnProperty('detachedProcess')) { + detachedProcess = manifestJsonFile.detachedProcess; + } + + var options = { cwd: currentBinPath, env: process.env, detached: detachedProcess }; - var options = { - cwd: currentBinPath, - env: process.env, - }; apiProcess = cProcess('dotnet', parameters, options); apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); + console.log('stdout: ${data.toString()}'); }); apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); + console.log('stderr: ${data.toString()}'); }); apiProcess.on('close', (code) => { - console.log(`ASP.NET Process exited with code ${code}`); + console.log('ASP.NET Process exited with code ${code}'); if (code != 0) { - console.log(`Will quit Electron, as exit code != 0 (got ${code})`); + console.log('Will quit Electron, as exit code != 0 (got ${code})'); app.exit(code); } }); + + if (detachedProcess) { + console.log('Detached from ASP.NET process'); + apiProcess.unref(); + } } } From 8b03a6b006366bda38f069594705ddb530f95425 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 11:27:46 +0200 Subject: [PATCH 07/12] remove stdio handling for detached case --- ElectronNET.Host/main.js | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index cc12ee6..3d74bd8 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -315,24 +315,30 @@ function startAspCoreBackend(electronPort) { } var detachedProcess = false; + var stdioopt = 'pipe'; if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; + if (detachedProcess) { + stdioopt = 'ignore'; + } } let binFilePath = path.join(currentBinPath, binaryFile); - var options = { cwd: currentBinPath, detached: detachedProcess }; + var options = { cwd: currentBinPath, detached: detachedProcess, stdio: stdioopt }; apiProcess = cProcess(binFilePath, parameters, options); - apiProcess.stdout.on('data', (data) => { - console.log('stdout: ${data.toString()}'); - }); + if (!detachedProcess) { + apiProcess.stdout.on('data', (data) => { + console.log('stdout: ${data.toString()}'); + }); - apiProcess.stderr.on('data', (data) => { - console.log('stderr: ${data.toString()}'); - }); + apiProcess.stderr.on('data', (data) => { + console.log('stderr: ${data.toString()}'); + }); + } apiProcess.on('close', (code) => { console.log('ASP.NET Process exited with code ${code}'); @@ -365,22 +371,28 @@ function startAspCoreBackendWithWatch(electronPort) { const parameters = ['watch', 'run', getEnvironmentParameter(), '/electronPort=${electronPort}', '/electronWebPort=${aspCoreBackendPort}', '/electronPID=${process.pid}']; var detachedProcess = false; + var stdioopt = 'pipe'; if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; + if (detachedProcess) { + stdioopt = 'ignore'; + } } - var options = { cwd: currentBinPath, env: process.env, detached: detachedProcess }; + var options = { cwd: currentBinPath, env: process.env, detached: detachedProcess, stdio: stdioopt }; apiProcess = cProcess('dotnet', parameters, options); - apiProcess.stdout.on('data', (data) => { - console.log('stdout: ${data.toString()}'); - }); + if (!detachedProcess) { + apiProcess.stdout.on('data', (data) => { + console.log('stdout: ${data.toString()}'); + }); - apiProcess.stderr.on('data', (data) => { - console.log('stderr: ${data.toString()}'); - }); + apiProcess.stderr.on('data', (data) => { + console.log('stderr: ${data.toString()}'); + }); + } apiProcess.on('close', (code) => { console.log('ASP.NET Process exited with code ${code}'); From efec886f73b5c1021fef4d2eb2324fa3f91255c1 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 11:33:32 +0200 Subject: [PATCH 08/12] Update main.js --- ElectronNET.Host/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 3d74bd8..d02f575 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -320,7 +320,7 @@ function startAspCoreBackend(electronPort) { if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; if (detachedProcess) { - stdioopt = 'ignore'; + stdioopt = ['ignore', 'pipe', 'pipe']; } } @@ -376,7 +376,7 @@ function startAspCoreBackendWithWatch(electronPort) { if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; if (detachedProcess) { - stdioopt = 'ignore'; + stdioopt = ['ignore', 'pipe', 'pipe']; } } From 64b91fc23543f145cdd7168a43a2b5a5563e2a97 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 13:04:23 +0200 Subject: [PATCH 09/12] Update main.js --- ElectronNET.Host/main.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index d02f575..b3bcd69 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -305,8 +305,8 @@ function startAspCoreBackend(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Port: ' + aspCoreBackendPort); - loadURL = 'http://localhost:${aspCoreBackendPort}'; - const parameters = [getEnvironmentParameter(), '/electronPort=${electronPort}', '/electronWebPort=${aspCoreBackendPort}', '/electronPID=${process.pid}']; + loadURL = `http://localhost:${aspCoreBackendPort}`; + const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; let binaryFile = manifestJsonFile.executable; const os = require('os'); @@ -332,18 +332,18 @@ function startAspCoreBackend(electronPort) { if (!detachedProcess) { apiProcess.stdout.on('data', (data) => { - console.log('stdout: ${data.toString()}'); + console.log(`stdout: ${data.toString()}`); }); apiProcess.stderr.on('data', (data) => { - console.log('stderr: ${data.toString()}'); + console.log(`stderr: ${data.toString()}`); }); } apiProcess.on('close', (code) => { - console.log('ASP.NET Process exited with code ${code}'); + console.log(`ASP.NET Process exited with code ${code}`); if (code != 0) { - console.log('Will quit Electron, as exit code != 0 (got ${code})'); + console.log(`Will quit Electron, as exit code != 0 (got ${code})`); app.exit(code); } }); @@ -367,8 +367,8 @@ function startAspCoreBackendWithWatch(electronPort) { function startBackend(aspCoreBackendPort) { console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort); - loadURL = 'http://localhost:${aspCoreBackendPort}'; - const parameters = ['watch', 'run', getEnvironmentParameter(), '/electronPort=${electronPort}', '/electronWebPort=${aspCoreBackendPort}', '/electronPID=${process.pid}']; + loadURL = `http://localhost:${aspCoreBackendPort}`; + const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`]; var detachedProcess = false; var stdioopt = 'pipe'; @@ -386,18 +386,18 @@ function startAspCoreBackendWithWatch(electronPort) { if (!detachedProcess) { apiProcess.stdout.on('data', (data) => { - console.log('stdout: ${data.toString()}'); + console.log(`stdout: ${data.toString()}`); }); apiProcess.stderr.on('data', (data) => { - console.log('stderr: ${data.toString()}'); + console.log(`stderr: ${data.toString()}`); }); } apiProcess.on('close', (code) => { - console.log('ASP.NET Process exited with code ${code}'); + console.log(`ASP.NET Process exited with code ${code}`); if (code != 0) { - console.log('Will quit Electron, as exit code != 0 (got ${code})'); + console.log(`Will quit Electron, as exit code != 0 (got ${code})`); app.exit(code); } }); From be41cae3bdeae806925898c683bd4e71c6dccb21 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 13:24:44 +0200 Subject: [PATCH 10/12] Update main.js --- ElectronNET.Host/main.js | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index b3bcd69..7379f25 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -330,15 +330,13 @@ function startAspCoreBackend(electronPort) { apiProcess = cProcess(binFilePath, parameters, options); - if (!detachedProcess) { - apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); - }); + apiProcess.stdout.on('data', (data) => { + console.log(`stdout: ${data.toString()}`); + }); - apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); - }); - } + apiProcess.stderr.on('data', (data) => { + console.log(`stderr: ${data.toString()}`); + }); apiProcess.on('close', (code) => { console.log(`ASP.NET Process exited with code ${code}`); @@ -384,15 +382,13 @@ function startAspCoreBackendWithWatch(electronPort) { apiProcess = cProcess('dotnet', parameters, options); - if (!detachedProcess) { - apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); - }); + apiProcess.stdout.on('data', (data) => { + console.log(`stdout: ${data.toString()}`); + }); - apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); - }); - } + apiProcess.stderr.on('data', (data) => { + console.log(`stderr: ${data.toString()}`); + }); apiProcess.on('close', (code) => { console.log(`ASP.NET Process exited with code ${code}`); From 48d54970457e04ab8e0b7650af3d118bb30d269d Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 13:33:50 +0200 Subject: [PATCH 11/12] Revert "Update main.js" This reverts commit be41cae3bdeae806925898c683bd4e71c6dccb21. --- ElectronNET.Host/main.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index 7379f25..b3bcd69 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -330,13 +330,15 @@ function startAspCoreBackend(electronPort) { apiProcess = cProcess(binFilePath, parameters, options); - apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); - }); + if (!detachedProcess) { + apiProcess.stdout.on('data', (data) => { + console.log(`stdout: ${data.toString()}`); + }); - apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); - }); + apiProcess.stderr.on('data', (data) => { + console.log(`stderr: ${data.toString()}`); + }); + } apiProcess.on('close', (code) => { console.log(`ASP.NET Process exited with code ${code}`); @@ -382,13 +384,15 @@ function startAspCoreBackendWithWatch(electronPort) { apiProcess = cProcess('dotnet', parameters, options); - apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); - }); + if (!detachedProcess) { + apiProcess.stdout.on('data', (data) => { + console.log(`stdout: ${data.toString()}`); + }); - apiProcess.stderr.on('data', (data) => { - console.log(`stderr: ${data.toString()}`); - }); + apiProcess.stderr.on('data', (data) => { + console.log(`stderr: ${data.toString()}`); + }); + } apiProcess.on('close', (code) => { console.log(`ASP.NET Process exited with code ${code}`); From 5e82ae42465ff5d3f3bce05fafe7fbaa92eeb632 Mon Sep 17 00:00:00 2001 From: rafael-aero Date: Wed, 25 Aug 2021 13:38:30 +0200 Subject: [PATCH 12/12] add socket events to emit console messages --- ElectronNET.API/IpcMain.cs | 21 +++++++++++++++++++++ ElectronNET.Host/main.js | 12 ++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ElectronNET.API/IpcMain.cs b/ElectronNET.API/IpcMain.cs index 1508078..eae3f3c 100644 --- a/ElectronNET.API/IpcMain.cs +++ b/ElectronNET.API/IpcMain.cs @@ -207,6 +207,27 @@ namespace ElectronNET.API } } + /// + /// Log a message to the console output pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json, + /// as in that case we can't open pipes to read the console output from the child process anymore + /// + /// Message to log + public static void ConsoleLog(string text) + { + BridgeConnector.Emit("console-stdout", text); + } + + /// + /// Log a message to the console error pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json, + /// as in that case we can't open pipes to read the console output from the child process anymore + /// + /// Message to log + + public static void ConsoleError(string text) + { + BridgeConnector.Emit("console-stderr", text); + } + private JsonSerializer _jsonSerializer = new JsonSerializer() { ContractResolver = new CamelCasePropertyNamesContractResolver(), diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index b3bcd69..862871b 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -271,6 +271,14 @@ function startSocketApiBridge(port) { } }); + socket.on('console-stdout', (data) => { + console.log(`stdout: ${data.toString()}`); + }); + + socket.on('console-stderr', (data) => { + console.log(`stderr: ${data.toString()}`); + }); + try { const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js'); @@ -320,7 +328,7 @@ function startAspCoreBackend(electronPort) { if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; if (detachedProcess) { - stdioopt = ['ignore', 'pipe', 'pipe']; + stdioopt = 'ignore'; } } @@ -376,7 +384,7 @@ function startAspCoreBackendWithWatch(electronPort) { if (manifestJsonFile.hasOwnProperty('detachedProcess')) { detachedProcess = manifestJsonFile.detachedProcess; if (detachedProcess) { - stdioopt = ['ignore', 'pipe', 'pipe']; + stdioopt = 'ignore'; } }