From a76abeada896d2511f60218c7f3d94ff4500a2cf Mon Sep 17 00:00:00 2001 From: dfbb <2337668+dfbb@users.noreply.github.com> Date: Sun, 17 May 2026 13:13:02 +0800 Subject: [PATCH] feat(emain): wire remote mode into Electron main process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Switch auth injector to X-Remote-Password in remote mode (emain.ts, emain-tabview.ts) - Skip dock menu, auto-updater, and global hotkeys in remote mode - Set window title to "Wave — [remote: host:port]" in remote mode - Use waveapp-remote-.log for log files in remote mode - Return null from get-data-dir / get-config-dir IPC in remote mode - Add config key constants for remote:password/listenport/bindaddr --- emain/emain-log.ts | 21 ++++++++++++++++----- emain/emain-platform.ts | 4 ++-- emain/emain-tabview.ts | 10 ++++++++-- emain/emain-window.ts | 8 +++++++- emain/emain.ts | 29 +++++++++++++++++++++-------- pkg/wconfig/metaconsts.go | 4 ++++ 6 files changed, 58 insertions(+), 18 deletions(-) diff --git a/emain/emain-log.ts b/emain/emain-log.ts index 91241b522..addd537fe 100644 --- a/emain/emain-log.ts +++ b/emain/emain-log.ts @@ -5,18 +5,29 @@ import fs from "fs"; import path from "path"; import { format } from "util"; import winston from "winston"; -import { getWaveDataDir, isDev } from "./emain-platform"; +import { getRemoteState, getWaveDataDir, isDev } from "./emain-platform"; const oldConsoleLog = console.log; +function getLogBaseName(): string { + const remote = getRemoteState(); + if (remote.isRemote && remote.safeSuffix) { + return `waveapp-remote-${remote.safeSuffix}`; + } + return "waveapp"; +} + +const LogBaseName = getLogBaseName(); + function findHighestLogNumber(logsDir: string): number { if (!fs.existsSync(logsDir)) { return 0; } const files = fs.readdirSync(logsDir); let maxNum = 0; + const pattern = new RegExp(`^${LogBaseName}\\.(\\d+)\\.log$`); for (const file of files) { - const match = file.match(/^waveapp\.(\d+)\.log$/); + const match = file.match(pattern); if (match) { const num = parseInt(match[1], 10); if (num > maxNum) { @@ -67,7 +78,7 @@ function pruneOldLogs(logsDir: string): { pruned: string[]; error: any } { function rotateLogIfNeeded(): string | null { const waveDataDir = getWaveDataDir(); - const logFile = path.join(waveDataDir, "waveapp.log"); + const logFile = path.join(waveDataDir, `${LogBaseName}.log`); const logsDir = path.join(waveDataDir, "logs"); if (!fs.existsSync(logsDir)) { @@ -81,7 +92,7 @@ function rotateLogIfNeeded(): string | null { const stats = fs.statSync(logFile); if (stats.size > 10 * 1024 * 1024) { const nextNum = findHighestLogNumber(logsDir) + 1; - const rotatedPath = path.join(logsDir, `waveapp.${nextNum}.log`); + const rotatedPath = path.join(logsDir, `${LogBaseName}.${nextNum}.log`); fs.renameSync(logFile, rotatedPath); return rotatedPath; } @@ -103,7 +114,7 @@ try { } const loggerTransports: winston.transport[] = [ - new winston.transports.File({ filename: path.join(getWaveDataDir(), "waveapp.log"), level: "info" }), + new winston.transports.File({ filename: path.join(getWaveDataDir(), `${LogBaseName}.log`), level: "info" }), ]; if (isDev) { loggerTransports.push(new winston.transports.Console()); diff --git a/emain/emain-platform.ts b/emain/emain-platform.ts index c88af8be3..3ba0b35da 100644 --- a/emain/emain-platform.ts +++ b/emain/emain-platform.ts @@ -231,10 +231,10 @@ ipcMain.on("get-webview-preload", (event) => { event.returnValue = path.join(getElectronAppBasePath(), "preload", "preload-webview.cjs"); }); ipcMain.on("get-data-dir", (event) => { - event.returnValue = getWaveDataDir(); + event.returnValue = remoteState.isRemote ? null : getWaveDataDir(); }); ipcMain.on("get-config-dir", (event) => { - event.returnValue = getWaveConfigDir(); + event.returnValue = remoteState.isRemote ? null : getWaveConfigDir(); }); ipcMain.on("get-home-dir", (event) => { event.returnValue = app.getPath("home"); diff --git a/emain/emain-tabview.ts b/emain/emain-tabview.ts index 753a53ade..5ed1caf42 100644 --- a/emain/emain-tabview.ts +++ b/emain/emain-tabview.ts @@ -9,7 +9,8 @@ import { createNewWaveWindow, getWaveWindowById } from "emain/emain-window"; import path from "path"; import { configureAuthKeyRequestInjection } from "./authkey"; import { setWasActive } from "./emain-activity"; -import { getElectronAppBasePath, isDevVite, unamePlatform } from "./emain-platform"; +import { getElectronAppBasePath, getRemoteState, isDevVite, unamePlatform } from "./emain-platform"; +import { configureRemotePasswordInjection } from "./remoteauth"; import { decreaseZoomLevel, handleCtrlShiftFocus, @@ -353,7 +354,12 @@ export async function getOrCreateWebViewForTab(waveWindowId: string, tabId: stri tabView.webContents.on("blur", () => { handleCtrlShiftFocus(tabView.webContents, false); }); - configureAuthKeyRequestInjection(tabView.webContents.session); + const remote = getRemoteState(); + if (remote.isRemote) { + configureRemotePasswordInjection(tabView.webContents.session); + } else { + configureAuthKeyRequestInjection(tabView.webContents.session); + } return [tabView, false]; } diff --git a/emain/emain-window.ts b/emain/emain-window.ts index e3bfa8775..53fbe2cc2 100644 --- a/emain/emain-window.ts +++ b/emain/emain-window.ts @@ -17,7 +17,7 @@ import { setWasInFg, } from "./emain-activity"; import { log } from "./emain-log"; -import { getElectronAppBasePath, isDev, unamePlatform } from "./emain-platform"; +import { getElectronAppBasePath, getRemoteState, isDev, unamePlatform } from "./emain-platform"; import { getOrCreateWebViewForTab, getWaveTabViewByWebContentsId, WaveTabView } from "./emain-tabview"; import { delay, ensureBoundsAreVisible, waveKeyToElectronKey } from "./emain-util"; import { ElectronWshClient } from "./emain-wsh"; @@ -158,6 +158,11 @@ export class WaveBrowserWindow extends BaseWindow { console.log("create win", waveWindow.oid); const winBounds = calculateWindowBounds(waveWindow.winsize, waveWindow.pos, settings); + const remote = getRemoteState(); + const winTitle = + remote.isRemote && remote.target + ? `Wave — [remote: ${remote.target.host}:${remote.target.port}]` + : "Wave"; const winOpts: BaseWindowConstructorOptions = { x: winBounds.x, y: winBounds.y, @@ -166,6 +171,7 @@ export class WaveBrowserWindow extends BaseWindow { minWidth: MinWindowWidth, minHeight: MinWindowHeight, show: false, + title: winTitle, }; const isTransparent = settings?.["window:transparent"] ?? false; diff --git a/emain/emain.ts b/emain/emain.ts index 8b08178ae..b4e2f064f 100644 --- a/emain/emain.ts +++ b/emain/emain.ts @@ -10,6 +10,7 @@ import * as services from "../frontend/app/store/services"; import { initElectronWshrpc, shutdownWshrpc } from "../frontend/app/store/wshrpcutil-base"; import { fireAndForget, sleep } from "../frontend/util/util"; import { AuthKey, configureAuthKeyRequestInjection } from "./authkey"; +import { configureRemotePasswordInjection, setRemotePassword } from "./remoteauth"; import { getActivityState, getAndClearTermCommandsDurable, @@ -33,6 +34,7 @@ import { checkIfRunningUnderARM64Translation, getElectronAppBasePath, getElectronAppUnpackedBasePath, + getRemoteState, getWaveConfigDir, getWaveDataDir, isDev, @@ -398,13 +400,20 @@ async function appMain() { const ready = await getWaveSrvReady(); console.log("wavesrv ready signal received", ready, Date.now() - startTs, "ms"); await electronApp.whenReady(); - configureAuthKeyRequestInjection(electron.session.defaultSession); + const remote = getRemoteState(); + if (remote.isRemote) { + setRemotePassword(remote.password!); + configureRemotePasswordInjection(electron.session.defaultSession); + } else { + configureAuthKeyRequestInjection(electron.session.defaultSession); + } initIpcHandlers(); await sleep(10); // wait a bit for wavesrv to be ready try { initElectronWshClient(); - initElectronWshrpc(ElectronWshClient, { authKey: AuthKey }); + const wshOpts = remote.isRemote ? { remotePassword: remote.password! } : { authKey: AuthKey }; + initElectronWshrpc(ElectronWshClient, wshOpts); initMenuEventSubscriptions(); } catch (e) { console.log("error initializing wshrpc", e); @@ -420,8 +429,10 @@ async function appMain() { setTimeout(sendDisplaysTDataEvent, 5000); makeAndSetAppMenu(); - makeDockTaskbar(); - await configureAutoUpdater(); + if (!remote.isRemote) { + makeDockTaskbar(); + await configureAutoUpdater(); + } setGlobalIsStarting(false); if (fullConfig?.settings?.["window:maxtabcachesize"] != null) { setMaxTabCacheSize(fullConfig.settings["window:maxtabcachesize"]); @@ -453,11 +464,13 @@ async function appMain() { } }); }); - const rawGlobalHotKey = launchSettings?.["app:globalhotkey"]; - if (rawGlobalHotKey) { - registerGlobalHotkey(rawGlobalHotKey); + if (!remote.isRemote) { + const rawGlobalHotKey = launchSettings?.["app:globalhotkey"]; + if (rawGlobalHotKey) { + registerGlobalHotkey(rawGlobalHotKey); + } + initGlobalHotkeyEventSubscription(); } - initGlobalHotkeyEventSubscription(); } appMain().catch((e) => { diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go index 7d5bba5d9..a63f953ce 100644 --- a/pkg/wconfig/metaconsts.go +++ b/pkg/wconfig/metaconsts.go @@ -131,5 +131,9 @@ const ( ConfigKey_TsunamiSdkReplacePath = "tsunami:sdkreplacepath" ConfigKey_TsunamiSdkVersion = "tsunami:sdkversion" ConfigKey_TsunamiGoPath = "tsunami:gopath" + + ConfigKey_RemotePassword = "remote:password" + ConfigKey_RemoteListenPort = "remote:listenport" + ConfigKey_RemoteBindAddr = "remote:bindaddr" )