diff options
Diffstat (limited to 'packages/meshbay-client/src')
| -rw-r--r-- | packages/meshbay-client/src/main.js | 57 | ||||
| -rw-r--r-- | packages/meshbay-client/src/preload.js | 7 |
2 files changed, 64 insertions, 0 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js index 24c1b6a..2bdf550 100644 --- a/packages/meshbay-client/src/main.js +++ b/packages/meshbay-client/src/main.js @@ -738,6 +738,63 @@ function registerBridge() { return { installed: Boolean(bin) }; }); + // The systemd unit's own view of the node, for the status panel at the top + // of the Node page. Deliberately not `probeNode()`: that asks the daemon's + // own HTTP API, which cannot answer while the daemon is stopped or crash- + // looping — exactly the states this panel exists to show and act on. + ipcMain.handle('node:service-status', async () => { + if (process.platform !== 'linux') return { supported: false }; + return new Promise((resolve) => { + execFile('systemctl', ['--user', 'show', 'meshbay-node.service', + '--property=LoadState,ActiveState,SubState'], (err, stdout) => { + if (err) { + resolve({ supported: true, installed: false, activeState: 'unknown', + subState: '' }); + return; + } + const props = {}; + for (const line of stdout.split('\n')) { + const i = line.indexOf('='); + if (i > 0) props[line.slice(0, i)] = line.slice(i + 1); + } + resolve({ + supported: true, + installed: props.LoadState === 'loaded', + activeState: props.ActiveState || 'unknown', + subState: props.SubState || '', + }); + }); + }); + }); + + ipcMain.handle('node:service-stop', async () => { + if (process.platform !== 'linux') { + throw new Error('Service control is only supported on Linux'); + } + await new Promise((resolve, reject) => { + execFile('systemctl', ['--user', 'stop', 'meshbay-node'], + (err, _stdout, stderr) => { + if (err) return reject(new Error(stderr.trim() || err.message)); + resolve(); + }); + }); + return { stopped: true }; + }); + + ipcMain.handle('node:service-restart', async () => { + if (process.platform !== 'linux') { + throw new Error('Service control is only supported on Linux'); + } + await new Promise((resolve, reject) => { + execFile('systemctl', ['--user', 'restart', 'meshbay-node'], + (err, _stdout, stderr) => { + if (err) return reject(new Error(stderr.trim() || err.message)); + resolve(); + }); + }); + return { restarted: true }; + }); + async function probeNode() { const nc = readNodeConfig(); const dataDir = nc ? nc.dataDir diff --git a/packages/meshbay-client/src/preload.js b/packages/meshbay-client/src/preload.js index f240995..7ffdf66 100644 --- a/packages/meshbay-client/src/preload.js +++ b/packages/meshbay-client/src/preload.js @@ -91,6 +91,13 @@ contextBridge.exposeInMainWorld('meshbay', { call: (method, path, body) => ipcRenderer.invoke('node:call', method, path, body), pairingCode: () => ipcRenderer.invoke('node:pairing-code'), setPairingCode: (code) => ipcRenderer.invoke('node:set-pairing-code', code), + // The systemd unit's own state — reachable even while the daemon itself + // is stopped or crash-looping, which `call()` above is not. + service: { + status: () => ipcRenderer.invoke('node:service-status'), + stop: () => ipcRenderer.invoke('node:service-stop'), + restart: () => ipcRenderer.invoke('node:service-restart'), + }, }, // LAN cast relay. The main process runs a local HTTP server and the |