waveterm/frontend/app/store/wshrpcutil.ts
Evan Simkowitz 64084d3e27
Remove global.ts dependency from emain (#1003)
Removes global atoms dependency from emain by moving WOS to grab the
globalAtoms from window, if present. Also removes interdependency
between wshrpcutil and wps

Also adds showmenubar setting for Windows and Linux
2024-10-10 10:12:42 -07:00

161 lines
4.8 KiB
TypeScript

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { wpsReconnectHandler } from "@/app/store/wps";
import { WshClient } from "@/app/store/wshclient";
import { makeWindowRouteId, WshRouter } from "@/app/store/wshrouter";
import { getWSServerEndpoint } from "@/util/endpoints";
import { addWSReconnectHandler, ElectronOverrideOpts, globalWS, initGlobalWS, WSControl } from "./ws";
let DefaultRouter: WshRouter;
let WindowRpcClient: WshClient;
async function* rpcResponseGenerator(
openRpcs: Map<string, ClientRpcEntry>,
command: string,
reqid: string,
timeout: number
): AsyncGenerator<any, void, boolean> {
const msgQueue: RpcMessage[] = [];
let signalFn: () => void;
let signalPromise = new Promise<void>((resolve) => (signalFn = resolve));
let timeoutId: NodeJS.Timeout = null;
if (timeout > 0) {
timeoutId = setTimeout(() => {
msgQueue.push({ resid: reqid, error: "EC-TIME: timeout waiting for response" });
signalFn();
}, timeout);
}
const msgFn = (msg: RpcMessage) => {
msgQueue.push(msg);
signalFn();
// reset signal promise
signalPromise = new Promise<void>((resolve) => (signalFn = resolve));
};
openRpcs.set(reqid, {
reqId: reqid,
startTs: Date.now(),
command: command,
msgFn: msgFn,
});
yield null;
try {
while (true) {
while (msgQueue.length > 0) {
const msg = msgQueue.shift()!;
if (msg.error != null) {
throw new Error(msg.error);
}
if (!msg.cont && msg.data == null) {
return;
}
const shouldTerminate = yield msg.data;
if (shouldTerminate) {
sendRpcCancel(reqid);
return;
}
if (!msg.cont) {
return;
}
}
await signalPromise;
}
} finally {
openRpcs.delete(reqid);
if (timeoutId != null) {
clearTimeout(timeoutId);
}
}
}
function sendRpcCancel(reqid: string) {
const rpcMsg: RpcMessage = { reqid: reqid, cancel: true };
DefaultRouter.recvRpcMessage(rpcMsg);
}
function sendRpcResponse(msg: RpcMessage) {
DefaultRouter.recvRpcMessage(msg);
}
function sendRpcCommand(
openRpcs: Map<string, ClientRpcEntry>,
msg: RpcMessage
): AsyncGenerator<RpcMessage, void, boolean> {
DefaultRouter.recvRpcMessage(msg);
if (msg.reqid == null) {
return null;
}
const rtnGen = rpcResponseGenerator(openRpcs, msg.command, msg.reqid, msg.timeout);
rtnGen.next(); // start the generator (run the initialization/registration logic, throw away the result)
return rtnGen;
}
async function consumeGenerator(gen: AsyncGenerator<any, any, any>) {
let idx = 0;
try {
for await (const msg of gen) {
console.log("gen", idx, msg);
idx++;
}
const result = await gen.return(undefined);
console.log("gen done", result.value);
} catch (e) {
console.log("gen error", e);
}
}
if (globalThis.window != null) {
globalThis["consumeGenerator"] = consumeGenerator;
}
function initElectronWshrpc(electronClient: WshClient, eoOpts: ElectronOverrideOpts) {
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
const handleFn = (event: WSEventType) => {
DefaultRouter.recvRpcMessage(event.data);
};
initGlobalWS(getWSServerEndpoint(), "electron", handleFn, eoOpts);
globalWS.connectNow("connectWshrpc");
DefaultRouter.registerRoute(electronClient.routeId, electronClient);
addWSReconnectHandler(() => {
DefaultRouter.reannounceRoutes();
});
addWSReconnectHandler(wpsReconnectHandler);
}
function shutdownWshrpc() {
globalWS?.shutdown();
}
function initWshrpc(windowId: string): WSControl {
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
const handleFn = (event: WSEventType) => {
DefaultRouter.recvRpcMessage(event.data);
};
initGlobalWS(getWSServerEndpoint(), windowId, handleFn);
globalWS.connectNow("connectWshrpc");
WindowRpcClient = new WshClient(makeWindowRouteId(windowId));
DefaultRouter.registerRoute(WindowRpcClient.routeId, WindowRpcClient);
addWSReconnectHandler(() => {
DefaultRouter.reannounceRoutes();
});
addWSReconnectHandler(wpsReconnectHandler);
return globalWS;
}
class UpstreamWshRpcProxy implements AbstractWshClient {
recvRpcMessage(msg: RpcMessage): void {
const wsMsg: WSRpcCommand = { wscommand: "rpc", message: msg };
globalWS?.pushMessage(wsMsg);
}
}
export {
DefaultRouter,
initElectronWshrpc,
initWshrpc,
sendRpcCommand,
sendRpcResponse,
shutdownWshrpc,
WindowRpcClient,
};