mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-21 22:45:20 +00:00
Change again socket reconnect logic
This commit is contained in:
@@ -25,6 +25,24 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public static bool SocketDebug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handle hard fails of connecting to the socket. The application must exit when this event is raised.
|
||||
/// The default behavior is to exit with code 0xDEAD
|
||||
/// </summary>
|
||||
public static event Action OnSocketConnectFail;
|
||||
|
||||
internal static bool TryRaiseOnSocketConnectFail()
|
||||
{
|
||||
if (OnSocketConnectFail is object)
|
||||
{
|
||||
OnSocketConnectFail();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when the user clicks on the dock on Mac
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace ElectronNET.API
|
||||
private static readonly SemaphoreSlim _socketSemaphoreHandlers = new(1, 1);
|
||||
|
||||
private static AsyncManualResetEvent _connectedSocketEvent = new AsyncManualResetEvent();
|
||||
private static TaskCompletionSource<SocketIO> _connectedSocketTask = new();
|
||||
|
||||
private static Dictionary<string, Action<SocketIOResponse>> _eventHandlers = new ();
|
||||
|
||||
@@ -109,7 +108,7 @@ namespace ElectronNET.API
|
||||
private static async Task<SocketIO> GetSocket()
|
||||
{
|
||||
await _connectedSocketEvent.WaitAsync();
|
||||
return await _connectedSocketTask.Task;
|
||||
return _socket;
|
||||
}
|
||||
|
||||
public static bool IsConnected => _waitForConnection is Task task && task.IsCompletedSuccessfully;
|
||||
@@ -435,84 +434,46 @@ namespace ElectronNET.API
|
||||
var socket = new SocketIO($"http://localhost:{BridgeSettings.SocketPort}", new SocketIOOptions()
|
||||
{
|
||||
EIO = 3,
|
||||
Reconnection = false,
|
||||
Reconnection = true,
|
||||
ReconnectionAttempts = int.MaxValue,
|
||||
ReconnectionDelay = 1000,
|
||||
ReconnectionDelay = 500,
|
||||
ReconnectionDelayMax = 5000,
|
||||
RandomizationFactor = 0.5,
|
||||
ConnectionTimeout = TimeSpan.FromSeconds(10)
|
||||
});
|
||||
|
||||
socket.JsonSerializer = new CamelCaseNewtonsoftJsonSerializer();
|
||||
|
||||
_connectedSocketEvent.Reset();
|
||||
|
||||
socket.OnConnected += (_, __) =>
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
_connectedSocketTask.TrySetResult(socket);
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} connected on port {0}!", BridgeSettings.SocketPort, socket.Id);
|
||||
}
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} connected on port {0}!", BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnReconnectAttempt += (_, __) =>
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
_connectedSocketTask = new();
|
||||
Log("ElectronNET socket {1} is trying to reconnect on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
}
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} is trying to reconnect on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnReconnectError += (_, ex) =>
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
Log("ElectronNET socket {1} failed to connect {0}", ex, socket.Id);
|
||||
_connectedSocketEvent.Reset();
|
||||
_connectedSocketTask = new();
|
||||
_socket = null;
|
||||
}
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {1} failed to connect {0}", ex, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnReconnected += (_, __) =>
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
_connectedSocketTask.TrySetResult(socket);
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} reconnected on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
}
|
||||
_connectedSocketEvent.Set();
|
||||
Log("ElectronNET socket {1} reconnected on port {0}...", BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
socket.OnDisconnected += (_, reason) =>
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
_connectedSocketEvent.Reset();
|
||||
_connectedSocketTask = new();
|
||||
_socket = null;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
EnsureSocketTaskIsCreated();
|
||||
});
|
||||
|
||||
Log("ElectronNET socket {2} disconnected with reason {0}, trying to reconnect on port {1}!", reason, BridgeSettings.SocketPort, socket.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Ignore
|
||||
}
|
||||
}
|
||||
_connectedSocketEvent.Reset();
|
||||
Log("ElectronNET socket {2} disconnected with reason {0}, trying to reconnect on port {1}!", reason, BridgeSettings.SocketPort, socket.Id);
|
||||
};
|
||||
|
||||
_socket = socket;
|
||||
@@ -521,23 +482,15 @@ namespace ElectronNET.API
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!socket.Connected)
|
||||
{
|
||||
if (_socket == socket)
|
||||
{
|
||||
await socket.ConnectAsync();
|
||||
_connectedSocketTask.TrySetResult(socket);
|
||||
_connectedSocketEvent.Set();
|
||||
}
|
||||
}
|
||||
return;
|
||||
await socket.ConnectAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
if (!socket.Connected)
|
||||
Console.WriteLine(e.ToString());
|
||||
|
||||
if(!App.TryRaiseOnSocketConnectFail())
|
||||
{
|
||||
LogError(e, "Failed to connect");
|
||||
Environment.Exit(0xDEAD);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -548,26 +501,6 @@ namespace ElectronNET.API
|
||||
{
|
||||
throw new Exception("Missing Socket Port");
|
||||
}
|
||||
|
||||
if(_backgroundMonitorThread is null)
|
||||
{
|
||||
_backgroundMonitorThread = new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(5_000);
|
||||
|
||||
if (HybridSupport.IsElectronActive)
|
||||
{
|
||||
EnsureSocketTaskIsCreated();
|
||||
}
|
||||
}
|
||||
});
|
||||
_backgroundMonitorThread.IsBackground = true;
|
||||
_backgroundMonitorThread.Name = "Monitor Electron Socket";
|
||||
_backgroundMonitorThread.Priority = ThreadPriority.Lowest;
|
||||
_backgroundMonitorThread.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -229,7 +229,7 @@ function startSocketApiBridge(port) {
|
||||
server = require('http').createServer();
|
||||
io = require('socket.io')();
|
||||
|
||||
io.attach(server, { pingTimeout: 5000, pingInterval: 10000 });
|
||||
io.attach(server, { pingTimeout: 10000, pingInterval: 5000 });
|
||||
|
||||
server.listen(port, 'localhost');
|
||||
server.on('listening', function () {
|
||||
@@ -263,50 +263,32 @@ function startSocketApiBridge(port) {
|
||||
}
|
||||
});
|
||||
|
||||
let firstTime = (global['electronsocket'] === undefined);
|
||||
//We only hook to events on app on the first initialization of each component
|
||||
let firstTime = (global['electronsocket'] == undefined);
|
||||
|
||||
if (firstTime) {
|
||||
console.log("First socket connection");
|
||||
global['electronsocket'] = socket;
|
||||
socket.setMaxListeners(0);
|
||||
}
|
||||
global['electronsocket'] = socket;
|
||||
socket.setMaxListeners(0);
|
||||
|
||||
console.log('.NET connected on socket ' + socket.id + ' on ' + new Date());
|
||||
|
||||
if (appApi === undefined) appApi = require('./api/app')(socket, app, firstTime);
|
||||
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app, firstTime);
|
||||
if (commandLine === undefined) commandLine = require('./api/commandLine')(socket, app);
|
||||
if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(socket, app);
|
||||
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 (nativeThemeApi === undefined) nativeThemeApi = require('./api/nativeTheme')(socket);
|
||||
if (dock === undefined) dock = require('./api/dock')(socket);
|
||||
|
||||
socket.on('register-app-open-file-event', (id) => {
|
||||
global['electronsocket'] = socket;
|
||||
|
||||
app.on('open-file', (event, file) => {
|
||||
|
||||
if (global['electronsocket'] === socket) {
|
||||
event.preventDefault();
|
||||
global['electronsocket'].emit('app-open-file' + id, file);
|
||||
}
|
||||
});
|
||||
|
||||
if (launchFile) {
|
||||
global['electronsocket'].emit('app-open-file' + id, launchFile);
|
||||
}
|
||||
});
|
||||
appApi = require('./api/app')(socket, app, firstTime);
|
||||
browserWindows = require('./api/browserWindows')(socket, app, firstTime);
|
||||
commandLine = require('./api/commandLine')(socket, app);
|
||||
autoUpdater = require('./api/autoUpdater')(socket, app);
|
||||
ipc = require('./api/ipc')(socket);
|
||||
menu = require('./api/menu')(socket);
|
||||
dialogApi = require('./api/dialog')(socket);
|
||||
notification = require('./api/notification')(socket);
|
||||
tray = require('./api/tray')(socket);
|
||||
webContents = require('./api/webContents')(socket);
|
||||
globalShortcut = require('./api/globalShortcut')(socket);
|
||||
shellApi = require('./api/shell')(socket);
|
||||
screen = require('./api/screen')(socket);
|
||||
clipboard = require('./api/clipboard')(socket);
|
||||
browserView = require('./api/browserView').browserViewApi(socket);
|
||||
powerMonitor = require('./api/powerMonitor')(socket);
|
||||
nativeThemeApi = require('./api/nativeTheme')(socket);
|
||||
dock = require('./api/dock')(socket);
|
||||
|
||||
socket.on('splashscreen-destroy', () => {
|
||||
if (splashScreen) {
|
||||
@@ -315,17 +297,29 @@ function startSocketApiBridge(port) {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('register-app-open-file-event', (id) => {
|
||||
global['electronsocket'] = socket;
|
||||
|
||||
app.on('open-file', (event, file) => {
|
||||
event.preventDefault();
|
||||
global['electronsocket'].emit('app-open-file' + id, file);
|
||||
});
|
||||
|
||||
if (launchFile) {
|
||||
socket.emit('app-open-file' + id, launchFile);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('register-app-open-url-event', (id) => {
|
||||
global['electronsocket'] = socket;
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
event.preventDefault();
|
||||
|
||||
global['electronsocket'].emit('app-open-url' + id, url);
|
||||
});
|
||||
|
||||
if (launchUrl) {
|
||||
global['electronsocket'].emit('app-open-url' + id, launchUrl);
|
||||
socket.emit('app-open-url' + id, launchUrl);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -415,7 +409,7 @@ function startAspCoreBackend(electronPort) {
|
||||
else if (os.platform() === 'darwin') {
|
||||
//There is a bug on the updater on macOS never quiting and starting the update process
|
||||
//We give Squirrel.Mac enough time to access the update file, and then just force-exit here
|
||||
setTimeout(() => app.exit(0), 10_000);
|
||||
setTimeout(() => app.exit(0), 30_000);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user