From bb8965fa912ca3dae943b66916ee5d460a0a14c1 Mon Sep 17 00:00:00 2001 From: theolivenbaum Date: Thu, 2 Sep 2021 17:24:07 +0200 Subject: [PATCH] remove semaphore in favor of unique events per window /view create request --- ElectronNET.API/WindowManager.cs | 148 ++++++++++++------------- ElectronNET.Host/api/browserView.js | 4 +- ElectronNET.Host/api/browserView.ts | 4 +- ElectronNET.Host/api/browserWindows.js | 9 +- ElectronNET.Host/api/browserWindows.ts | 8 +- 5 files changed, 85 insertions(+), 88 deletions(-) diff --git a/ElectronNET.API/WindowManager.cs b/ElectronNET.API/WindowManager.cs index 65aea6b..60f4a1c 100644 --- a/ElectronNET.API/WindowManager.cs +++ b/ElectronNET.API/WindowManager.cs @@ -40,7 +40,6 @@ namespace ElectronNET.API return _windowManager; } } - private readonly SemaphoreSlim _singleCreate = new SemaphoreSlim(1, 1); /// /// Quit when all windows are closed. (Default is true) @@ -96,76 +95,85 @@ namespace ElectronNET.API /// public async Task CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost") { - await _singleCreate.WaitAsync(); + BootstrapUpdateOpenIDsEvent(); - try + var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + var guid = Guid.NewGuid().ToString(); + + BridgeConnector.Once("BrowserWindowCreated" + guid, (id) => { - var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var browserWindow = new BrowserWindow(id); - BridgeConnector.On("BrowserWindowCreated", (id) => - { - BridgeConnector.Off("BrowserWindowCreated"); + _browserWindows[id] = browserWindow; - var browserWindow = new BrowserWindow(id); + taskCompletionSource.SetResult(browserWindow); + }); - _browserWindows[id] = browserWindow; - taskCompletionSource.SetResult(browserWindow); - }); + if (string.Equals(loadUrl, "HTTP://LOCALHOST", StringComparison.InvariantCultureIgnoreCase)) + { + loadUrl = $"{loadUrl}:{BridgeSettings.WebPort}"; + } - BridgeConnector.Off("BrowserWindowClosed"); - BridgeConnector.On("BrowserWindowClosed", (browserWindowIdsStillOpen) => - { - if (browserWindowIdsStillOpen.Any()) - { - foreach (var id in _browserWindows.Keys.ToArray()) - { - if (!browserWindowIdsStillOpen.Contains(id)) _browserWindows.TryRemove(id, out _); - } - } - else - { - _browserWindows.Clear(); - } - }); + // Workaround Windows 10 / Electron Bug + // https://github.com/electron/electron/issues/4045 + if (IsWindows10()) + { + options.Width += 14; + options.Height += 7; + } - if (string.Equals(loadUrl, "HTTP://LOCALHOST", StringComparison.InvariantCultureIgnoreCase)) - { - loadUrl = $"{loadUrl}:{BridgeSettings.WebPort}"; - } + if (options.X == -1 && options.Y == -1) + { + options.X = 0; + options.Y = 0; + BridgeConnector.Emit("createBrowserWindow", guid, JObject.FromObject(options, _jsonSerializer), loadUrl); + } + else + { // Workaround Windows 10 / Electron Bug // https://github.com/electron/electron/issues/4045 if (IsWindows10()) { - options.Width = options.Width + 14; - options.Height = options.Height + 7; + options.X -= 7; } - if (options.X == -1 && options.Y == -1) - { - options.X = 0; - options.Y = 0; - - BridgeConnector.Emit("createBrowserWindow", JObject.FromObject(options, _jsonSerializer), loadUrl); - } - else - { - // Workaround Windows 10 / Electron Bug - // https://github.com/electron/electron/issues/4045 - if (IsWindows10()) - { - options.X = options.X - 7; - } - - BridgeConnector.Emit("createBrowserWindow", JObject.FromObject(options, _keepDefaultValuesSerializer), loadUrl); - } - - return await taskCompletionSource.Task; + BridgeConnector.Emit("createBrowserWindow", guid, JObject.FromObject(options, _keepDefaultValuesSerializer), loadUrl); } - finally + + return await taskCompletionSource.Task; + } + + + private bool _hasClosedEvent = false; + private readonly object _hasClosedEventLock = new(); + private void BootstrapUpdateOpenIDsEvent() + { + if (!_hasClosedEvent) { - _singleCreate.Release(); + lock(_hasClosedEventLock) + { + if(!_hasClosedEvent) + { + BridgeConnector.On("BrowserWindowUpdateOpenIDs", (browserWindowIdsStillOpen) => + { + if (browserWindowIdsStillOpen.Any()) + { + foreach (var id in _browserWindows.Keys.ToArray()) + { + if (!browserWindowIdsStillOpen.Contains(id)) _browserWindows.TryRemove(id, out _); + } + } + else + { + _browserWindows.Clear(); + } + }); + _hasClosedEvent = true; + } + } } } @@ -194,32 +202,20 @@ namespace ElectronNET.API /// public async Task CreateBrowserViewAsync(BrowserViewConstructorOptions options) { - await _singleCreate.WaitAsync(); + var guid = Guid.NewGuid().ToString(); - try + var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + BridgeConnector.Once("BrowserViewCreated" + guid, (id) => { + var browserView = new BrowserView(id); + _browserViews[id] = browserView; + taskCompletionSource.SetResult(browserView); + }); - var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + BridgeConnector.Emit("createBrowserView", guid, JObject.FromObject(options, _keepDefaultValuesSerializer)); - BridgeConnector.On("BrowserViewCreated", (id) => - { - BridgeConnector.Off("BrowserViewCreated"); - - BrowserView browserView = new BrowserView(id); - - _browserViews[id] = browserView; - - taskCompletionSource.SetResult(browserView); - }); - - BridgeConnector.Emit("createBrowserView", JObject.FromObject(options, _keepDefaultValuesSerializer)); - - return await taskCompletionSource.Task; - } - finally - { - _singleCreate.Release(); - } + return await taskCompletionSource.Task; } private static JsonSerializer _jsonSerializer = new JsonSerializer() diff --git a/ElectronNET.Host/api/browserView.js b/ElectronNET.Host/api/browserView.js index b0d23cc..b992b17 100644 --- a/ElectronNET.Host/api/browserView.js +++ b/ElectronNET.Host/api/browserView.js @@ -7,7 +7,7 @@ let browserView, electronSocket; const proxyToCredentialsMap = (global['proxyToCredentialsMap'] = global['proxyToCredentialsMap'] || []); const browserViewApi = (socket) => { electronSocket = socket; - socket.on('createBrowserView', (options) => { + socket.on('createBrowserView', (guid, options) => { if (!hasOwnChildreen(options, 'webPreferences', 'nodeIntegration')) { options = { ...options, webPreferences: { nodeIntegration: true, contextIsolation: false } }; } @@ -20,7 +20,7 @@ const browserViewApi = (socket) => { proxyToCredentialsMap[options.proxy] = options.proxyCredentials; } browserViews.push(browserView); - electronSocket.emit('BrowserViewCreated', browserView['id']); + electronSocket.emit('BrowserViewCreated' + guid, browserView['id']); }); socket.on('browserView-getBounds', (id) => { const bounds = getBrowserViewById(id).getBounds(); diff --git a/ElectronNET.Host/api/browserView.ts b/ElectronNET.Host/api/browserView.ts index 6ccf33c..49cd240 100644 --- a/ElectronNET.Host/api/browserView.ts +++ b/ElectronNET.Host/api/browserView.ts @@ -7,7 +7,7 @@ const proxyToCredentialsMap: { [proxy: string]: string } = (global['proxyToCrede const browserViewApi = (socket: Socket) => { electronSocket = socket; - socket.on('createBrowserView', (options) => { + socket.on('createBrowserView', (guid, options) => { if (!hasOwnChildreen(options, 'webPreferences', 'nodeIntegration')) { options = { ...options, webPreferences: { nodeIntegration: true, contextIsolation: false } }; } @@ -25,7 +25,7 @@ const browserViewApi = (socket: Socket) => { browserViews.push(browserView); - electronSocket.emit('BrowserViewCreated', browserView['id']); + electronSocket.emit('BrowserViewCreated' + guid, browserView['id']); }); socket.on('browserView-getBounds', (id) => { diff --git a/ElectronNET.Host/api/browserWindows.js b/ElectronNET.Host/api/browserWindows.js index bbf86e3..458c4d9 100644 --- a/ElectronNET.Host/api/browserWindows.js +++ b/ElectronNET.Host/api/browserWindows.js @@ -175,7 +175,7 @@ module.exports = (socket, app) => { electronSocket.emit('browserWindow-new-window-for-tab' + id); }); }); - socket.on('createBrowserWindow', (options, loadUrl) => { + socket.on('createBrowserWindow', (guid, options, loadUrl) => { if (options.webPreferences && !('nodeIntegration' in options.webPreferences)) { options = { ...options, webPreferences: { ...options.webPreferences, nodeIntegration: true, contextIsolation: false } }; } @@ -188,7 +188,7 @@ module.exports = (socket, app) => { if (window) { window.reload(); windows.push(window); - electronSocket.emit('BrowserWindowCreated', window.id); + electronSocket.emit('BrowserWindowCreated' + guid, window.id); return; } } @@ -218,6 +218,7 @@ module.exports = (socket, app) => { readyToShowWindowsIds.push(window.id); } }); + window.on('closed', (sender) => { again: for (let index = 0; index < windows.length; index++) { @@ -234,7 +235,7 @@ module.exports = (socket, app) => { } const ids = []; windows.forEach(x => ids.push(x.id)); - electronSocket.emit('BrowserWindowClosed', ids); + electronSocket.emit('BrowserWindowUpdateOpenIDs', ids); }); if (loadUrl) { window.loadURL(loadUrl); @@ -250,7 +251,7 @@ module.exports = (socket, app) => { app['mainWindow'] = window; } windows.push(window); - electronSocket.emit('BrowserWindowCreated', window.id); + electronSocket.emit('BrowserWindowCreated' + guid, window.id); }); socket.on('browserWindowDestroy', (id) => { getWindowById(id)?.destroy(); diff --git a/ElectronNET.Host/api/browserWindows.ts b/ElectronNET.Host/api/browserWindows.ts index 14e0ce9..c1923a1 100644 --- a/ElectronNET.Host/api/browserWindows.ts +++ b/ElectronNET.Host/api/browserWindows.ts @@ -209,7 +209,7 @@ export = (socket: Socket, app: Electron.App) => { }); }); - socket.on('createBrowserWindow', (options, loadUrl) => { + socket.on('createBrowserWindow', (guid, options, loadUrl) => { if (options.webPreferences && !('nodeIntegration' in options.webPreferences)) { options = { ...options, webPreferences: { ...options.webPreferences, nodeIntegration: true, contextIsolation: false } }; } else if (!options.webPreferences) { @@ -222,7 +222,7 @@ export = (socket: Socket, app: Electron.App) => { if (window) { window.reload(); windows.push(window); - electronSocket.emit('BrowserWindowCreated', window.id); + electronSocket.emit('BrowserWindowCreated' + guid, window.id); return; } } else { @@ -261,7 +261,7 @@ export = (socket: Socket, app: Electron.App) => { } const ids = []; windows.forEach(x => ids.push(x.id)); - electronSocket.emit('BrowserWindowClosed', ids); + electronSocket.emit('BrowserWindowUpdateOpenIDs', ids); }); if (loadUrl) { @@ -281,7 +281,7 @@ export = (socket: Socket, app: Electron.App) => { } windows.push(window); - electronSocket.emit('BrowserWindowCreated', window.id); + electronSocket.emit('BrowserWindowCreated' + guid, window.id); }); socket.on('browserWindowDestroy', (id) => {