diff --git a/src/main/index.ts b/src/main/index.ts index 094aa60..a851a4c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -150,15 +150,19 @@ function updateTrayMenu(status: RelayStatus): void { const menu = Menu.buildFromTemplate([ { - label: status.running ? 'Relay: Running' : 'Relay: Stopped', + label: status.running + ? 'Relay: Running' + : status.waiting + ? 'Relay: Waiting for Discord…' + : 'Relay: Stopped', enabled: false }, { type: 'separator' }, { - label: status.running ? 'Stop Relay' : 'Start Relay', + label: status.running || status.waiting ? 'Stop Relay' : 'Start Relay', click: async () => { try { - if (status.running) { + if (status.running || status.waiting) { await relay.stop() } else { await relay.start() diff --git a/src/main/relay.ts b/src/main/relay.ts index 60c248c..c684057 100644 --- a/src/main/relay.ts +++ b/src/main/relay.ts @@ -7,6 +7,7 @@ import { platform, type ClaimedSocket, type ProcessInfo } from './platform' const MAX_SOCKETS = 10 const DISCOVERY_INTERVAL_MS = 3000 +const WAITING_RETRY_INTERVAL_MS = 3000 interface AppAsset { id: string @@ -101,6 +102,7 @@ export interface LastActivity { export interface RelayStatus { running: boolean + waiting: boolean unsupported: boolean instances: RelayInstance[] connectedClients: ConnectedClient[] @@ -120,8 +122,10 @@ export class RpcRelay extends EventEmitter { private connectedClients = new Map() private nextClientId = 1 private discoveryTimer: NodeJS.Timeout | null = null + private waitingTimer: NodeJS.Timeout | null = null private lastActivity: LastActivity | null = null private running = false + private waiting = false private lastError: string | null = null private restarting = false private mirrors = new Map() @@ -138,6 +142,7 @@ export class RpcRelay extends EventEmitter { return { running: this.running, + waiting: this.waiting, unsupported: !platform.isSupported, instances, connectedClients: [...this.connectedClients.values()], @@ -181,11 +186,13 @@ export class RpcRelay extends EventEmitter { this.claimed = platform.discoverAndClaim() if (this.claimed.length === 0) { - this.lastError = 'No running Discord clients found (no discord-ipc-N sockets)' - this.emitStatus() - throw new Error(this.lastError) + this.waitForDiscord() + return } + this.waiting = false + this.stopWaitingTimer() + const fake = platform.fakeSocketPath() platform.removeFakeSocket(fake) @@ -211,7 +218,13 @@ export class RpcRelay extends EventEmitter { } async stop(): Promise { - if (!this.running) return + this.stopWaitingTimer() + this.waiting = false + + if (!this.running) { + this.emitStatus() + return + } this.running = false this.stopDiscoveryTimer() @@ -236,6 +249,28 @@ export class RpcRelay extends EventEmitter { return this.claimed[0]?.index } + private waitForDiscord(): void { + this.waiting = true + this.lastError = null + this.emitStatus() + + if (this.waitingTimer) return + this.waitingTimer = setInterval(() => { + if (!this.waiting) return + void this.start().catch((err) => { + this.lastError = err instanceof Error ? err.message : String(err) + this.emitStatus() + }) + }, WAITING_RETRY_INTERVAL_MS) + } + + private stopWaitingTimer(): void { + if (this.waitingTimer) { + clearInterval(this.waitingTimer) + this.waitingTimer = null + } + } + private startDiscoveryTimer(): void { this.stopDiscoveryTimer() this.discoveryTimer = setInterval(() => this.discoverNewInstances(), DISCOVERY_INTERVAL_MS) diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 56c7de7..4ecf08c 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -7,6 +7,7 @@ import { Button, LinkButton } from './components/Button' const EMPTY_STATUS: RelayStatus = { running: false, + waiting: false, unsupported: false, instances: [], connectedClients: [], @@ -120,7 +121,7 @@ export function App(): React.JSX.Element { const toggleRelay = async (): Promise => { setLoading(true) try { - if (status.running) { + if (status.running || status.waiting) { await window.api.stop() } else { await window.api.start() @@ -227,11 +228,23 @@ export function App(): React.JSX.Element {
Relay - - {status.running ? 'Running' : 'Stopped'} + + {status.running ? 'Running' : status.waiting ? 'Waiting for Discord…' : 'Stopped'}
- toggleRelay()} disabled={loading} /> + toggleRelay()} + disabled={loading} + />