Skip to content

Commit e5bc6cc

Browse files
committed
feat: make main window reload after restart, handle better backend start and restart
1 parent 8b64a88 commit e5bc6cc

4 files changed

Lines changed: 81 additions & 33 deletions

File tree

electron-app/src/ipc/handlers.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
getCurrentView,
2020
getMainWindow,
2121
loadView,
22+
reloadWindow,
2223
} from "../windows/mainWindow.js";
2324

2425
/**
@@ -61,7 +62,10 @@ function setupIpcHandlers() {
6162
ipcMain.handle("save-config", async (event, config) => {
6263
try {
6364
await writeConfig(config);
64-
restartBackend();
65+
await restartBackend();
66+
67+
reloadWindow();
68+
6569
return true;
6670
} catch (error) {
6771
logger.electron.error("Error saving config:", error);
@@ -96,7 +100,10 @@ function setupIpcHandlers() {
96100
ipcMain.handle("import-config", async () => {
97101
try {
98102
await importConfig();
99-
restartBackend();
103+
await restartBackend();
104+
105+
reloadWindow();
106+
100107
return true;
101108
} catch (error) {
102109
logger.electron.error("Error importing config:", error);

electron-app/src/processes/backend.js

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ const appPath = getAppPath();
2525
// Store the backend process instance
2626
let backendProcess = null;
2727

28+
// Common log window instance for all backend processes
29+
let storedLogWindow = null;
30+
2831
// Store error messages (keep last 10 lines to avoid memory issues)
2932
let lastBackendError = null;
3033

@@ -34,7 +37,13 @@ let lastBackendError = null;
3437
* @example
3538
* startBackend();
3639
*/
37-
function startBackend(logWindow = null) {
40+
async function startBackend(logWindow = null) {
41+
if (logWindow) {
42+
storedLogWindow = logWindow;
43+
}
44+
45+
const currentLogWindow = logWindow || storedLogWindow;
46+
3847
return new Promise((resolve, reject) => {
3948
// Get paths for binary and config
4049
const backendBin = getBinaryPath("backend");
@@ -69,9 +78,9 @@ function startBackend(logWindow = null) {
6978
logger.backend.info(`${data.toString().trim()}`);
7079

7180
// Send log message to log window
72-
if (logWindow) {
81+
if (currentLogWindow && !currentLogWindow.isDestroyed()) {
7382
const htmlData = convert.toHtml(data.toString().trim());
74-
logWindow.webContents.send("log", htmlData);
83+
currentLogWindow.webContents.send("log", htmlData);
7584
}
7685
});
7786

@@ -83,9 +92,9 @@ function startBackend(logWindow = null) {
8392
lastBackendError = errorMsg;
8493

8594
// Send error message to log window
86-
if (logWindow) {
95+
if (currentLogWindow && !currentLogWindow.isDestroyed()) {
8796
const htmlError = convert.toHtml(errorMsg);
88-
logWindow.webContents.send("log", htmlError);
97+
currentLogWindow.webContents.send("log", htmlError);
8998
}
9099
});
91100

@@ -102,7 +111,7 @@ function startBackend(logWindow = null) {
102111
// If the backend didn't fail in this period of time, resolve the promise
103112
setTimeout(() => {
104113
resolve(backendProcess);
105-
}, 4000);
114+
}, 2000);
106115

107116
// Handle process exit
108117
backendProcess.on("close", (code) => {
@@ -127,32 +136,46 @@ function startBackend(logWindow = null) {
127136
}
128137

129138
/**
130-
* Stops the backend process by sending a SIGTERM signal.
139+
* Stops the backend process by sending a SIGTERM and std.in.end() signal.
140+
* If the process does not exit gracefully after defined time, it will be force killed.
131141
* @returns {void}
132142
* @example
133143
* stopBackend();
134144
*/
135-
function stopBackend() {
136-
// Only stop if process exists and is still running
137-
if (backendProcess && !backendProcess.killed) {
138-
logger.backend.info("Stopping backend...");
139-
140-
backendProcess.stdin.end();
141-
142-
const fallbackTimer = setTimeout(() => {
143-
if (backendProcess && !backendProcess.killed) {
144-
logger.backend.warning(
145-
"Backend did not exit gracefully, force killing..."
146-
);
147-
backendProcess.kill("SIGKILL");
148-
}
149-
}, 2000);
145+
async function stopBackend() {
146+
return new Promise((resolve, reject) => {
147+
const localBackendProcess = backendProcess;
150148

151-
fallbackTimer.unref();
149+
// Only stop if process exists and is still running
150+
if (localBackendProcess && !localBackendProcess.killed) {
151+
logger.backend.info("Stopping backend...");
152152

153-
// Clear the process reference
154-
backendProcess = null;
155-
}
153+
localBackendProcess.once("close", () => {
154+
// Clear the process reference
155+
if (localBackendProcess === backendProcess) {
156+
backendProcess = null;
157+
}
158+
resolve();
159+
});
160+
161+
localBackendProcess.kill("SIGTERM");
162+
localBackendProcess.stdin.end();
163+
164+
const fallbackTimer = setTimeout(() => {
165+
if (localBackendProcess && !localBackendProcess.killed) {
166+
logger.backend.warning(
167+
"Backend did not exit gracefully, force killing..."
168+
);
169+
localBackendProcess.kill("SIGKILL");
170+
}
171+
}, 2000);
172+
173+
fallbackTimer.unref();
174+
} else {
175+
logger.backend.warning("Backend process not found, skipping stop...");
176+
resolve();
177+
}
178+
});
156179
}
157180

158181
/**
@@ -161,11 +184,18 @@ function stopBackend() {
161184
* @example
162185
* restartBackend();
163186
*/
164-
function restartBackend() {
187+
async function restartBackend() {
165188
// Stop current process first
166-
stopBackend();
189+
await stopBackend();
190+
167191
// Start a new process
168-
startBackend();
192+
try {
193+
await startBackend();
194+
logger.electron.info("Backend restarted successfully");
195+
} catch (error) {
196+
logger.electron.error("Failed to restart backend:", error);
197+
throw error; // Let the IPC handler know it failed
198+
}
169199
}
170200

171201
export { restartBackend, startBackend, stopBackend };

electron-app/src/windows/mainWindow.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ function loadView(view) {
9898
}
9999
}
100100

101+
/**
102+
* Reloads the main window.
103+
* @returns {void}
104+
* @example
105+
* reloadWindow();
106+
*/
107+
function reloadWindow() {
108+
if (mainWindow) {
109+
mainWindow.reload();
110+
}
111+
}
112+
101113
/**
102114
* Returns the name of the currently loaded view.
103115
* @returns {string} The current view name (e.g., "ethernet-view", "control-station").
@@ -124,4 +136,4 @@ function getMainWindow() {
124136
return mainWindow;
125137
}
126138

127-
export { createWindow, getCurrentView, getMainWindow, loadView };
139+
export { createWindow, getCurrentView, getMainWindow, loadView, reloadWindow };

frontend/testing-view/src/hooks/useAppMode.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export function useAppMode(
3131
// logger.testingView.log("[DEBUG] isDev", isDev);
3232
// logger.testingView.log("[DEBUG] isLoading", isLoading);
3333
// logger.testingView.log("[DEBUG] hasData", hasData);
34-
// logger.testingView.log("[DEBUG] backendConnected", backendConnected);
3534
// logger.testingView.log("[DEBUG] hasError", hasError);
3635

3736
if (isLoading || isRestarting) return "loading";

0 commit comments

Comments
 (0)