feat: rework Electron desktop app to run standalone-first with optional two-way sync to a remote Termix server

This commit is contained in:
LukeGus
2026-07-21 01:27:03 -05:00
parent f44d09eef7
commit 08825c256d
77 changed files with 3658 additions and 929 deletions
+67 -1
View File
@@ -20,6 +20,7 @@ const net = require("net");
const { URL } = require("url");
const { fork, spawn } = require("child_process");
const WebSocket = require("ws");
const remoteSync = require("./remote-sync.cjs");
// Portable mode: if a `.portable` marker exists next to the executable,
// store all data in a `data` folder beside the exe instead of %APPDATA%.
@@ -852,6 +853,7 @@ function startBackendServer() {
NODE_ENV: "production",
ELECTRON_EMBEDDED: "true",
PORT: "30001",
VERSION: app.getVersion(),
},
stdio: ["pipe", "pipe", "pipe", "ipc"],
});
@@ -1335,7 +1337,6 @@ ipcMain.handle("get-embedded-server-status", () => {
return {
running:
backendProcess !== null && !backendProcess.killed && !backendStartFailed,
embedded: !isDev,
dataDir: isDev ? null : getBackendDataDir(),
};
});
@@ -1442,6 +1443,70 @@ ipcMain.handle("save-server-config", (event, config) => {
}
});
// --- Remote sync (optional desktop <-> self-hosted server sync) ---
ipcMain.handle("get-desktop-settings", () => {
return remoteSync.getDesktopSettings();
});
ipcMain.handle("save-desktop-settings", (_event, settings) => {
return remoteSync.saveDesktopSettings(settings);
});
ipcMain.handle("get-remote-sync-config", () => {
return remoteSync.getRemoteSyncConfig();
});
ipcMain.handle("save-remote-sync-config", (_event, config) => {
return remoteSync.saveRemoteSyncConfig(config);
});
ipcMain.handle("clear-remote-sync-config", async () => {
const result = remoteSync.clearRemoteSyncConfig();
remoteSync.clearRemoteSyncJwt();
remoteSync.getRemoteSyncEngine()?.updateStatus({
connected: false,
syncing: false,
needsReauth: false,
lastError: null,
});
return result;
});
ipcMain.handle("save-remote-sync-jwt", (_event, token) => {
const result = remoteSync.saveRemoteSyncJwt(token);
if (result.success) {
remoteSync.getRemoteSyncEngine()?.updateStatus({
connected: true,
needsReauth: false,
lastError: null,
});
remoteSync.getRemoteSyncEngine()?.syncNow();
}
return result;
});
ipcMain.handle("get-remote-sync-jwt", () => {
return remoteSync.getRemoteSyncJwt();
});
ipcMain.handle("clear-remote-sync-jwt", () => {
return remoteSync.clearRemoteSyncJwt();
});
ipcMain.handle("get-remote-sync-status", () => {
return remoteSync.getRemoteSyncEngine()?.status || null;
});
ipcMain.handle("remote-sync-now", async () => {
return (await remoteSync.getRemoteSyncEngine()?.syncNow()) || null;
});
ipcMain.handle("notify-local-login", (_event, token) => {
remoteSync.getRemoteSyncEngine()?.setLocalJwt(token);
return { success: true };
});
function getC2STunnelConfigPath() {
return path.join(app.getPath("userData"), "c2s-tunnels.json");
}
@@ -2974,6 +3039,7 @@ app.whenReady().then(async () => {
createTray();
createWindow();
remoteSync.initRemoteSync(() => mainWindow);
logToFile("=== Startup complete ===");
});