waveterm/frontend/app/store/wshrouter.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

153 lines
4.8 KiB
TypeScript

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { handleWaveEvent } from "@/app/store/wps";
import * as util from "@/util/util";
import debug from "debug";
const dlog = debug("wave:router");
const SysRouteName = "sys";
type RouteInfo = {
rpcId: string;
sourceRouteId: string;
destRouteId: string;
};
function makeWindowRouteId(windowId: string): string {
return `window:${windowId}`;
}
function makeFeBlockRouteId(feBlockId: string): string {
return `feblock:${feBlockId}`;
}
class WshRouter {
routeMap: Map<string, AbstractWshClient>; // routeid -> client
upstreamClient: AbstractWshClient;
rpcMap: Map<string, RouteInfo>; // rpcid -> routeinfo
constructor(upstreamClient: AbstractWshClient) {
this.routeMap = new Map();
this.rpcMap = new Map();
if (upstreamClient == null) {
throw new Error("upstream client cannot be null");
}
this.upstreamClient = upstreamClient;
}
reannounceRoutes() {
for (const [routeId, client] of this.routeMap) {
const announceMsg: RpcMessage = {
command: "routeannounce",
data: routeId,
source: routeId,
};
this.upstreamClient.recvRpcMessage(announceMsg);
}
}
// returns true if the message was sent
_sendRoutedMessage(msg: RpcMessage, destRouteId: string) {
const client = this.routeMap.get(destRouteId);
if (client) {
client.recvRpcMessage(msg);
return;
}
// there should always an upstream client
if (!this.upstreamClient) {
throw new Error(`no upstream client for message: ${msg}`);
}
this.upstreamClient?.recvRpcMessage(msg);
}
_registerRouteInfo(reqid: string, sourceRouteId: string, destRouteId: string) {
dlog("registering route info", reqid, sourceRouteId, destRouteId);
if (util.isBlank(reqid)) {
return;
}
const routeInfo: RouteInfo = {
rpcId: reqid,
sourceRouteId: sourceRouteId,
destRouteId: destRouteId,
};
this.rpcMap.set(reqid, routeInfo);
}
recvRpcMessage(msg: RpcMessage) {
dlog("router received message", msg);
// we are a terminal node by definition, so we don't need to process with announce/unannounce messages
if (msg.command == "routeannounce" || msg.command == "routeunannounce") {
return;
}
// handle events
if (msg.command == "eventrecv") {
handleWaveEvent(msg.data);
return;
}
if (!util.isBlank(msg.command)) {
// send + register routeinfo
if (!util.isBlank(msg.reqid)) {
this._registerRouteInfo(msg.reqid, msg.source, msg.route);
}
this._sendRoutedMessage(msg, msg.route);
return;
}
if (!util.isBlank(msg.reqid)) {
const routeInfo = this.rpcMap.get(msg.reqid);
if (!routeInfo) {
// no route info, discard
dlog("no route info for reqid, discarding", msg);
return;
}
this._sendRoutedMessage(msg, routeInfo.destRouteId);
return;
}
if (!util.isBlank(msg.resid)) {
const routeInfo = this.rpcMap.get(msg.resid);
if (!routeInfo) {
// no route info, discard
dlog("no route info for resid, discarding", msg);
return;
}
this._sendRoutedMessage(msg, routeInfo.sourceRouteId);
if (!msg.cont) {
dlog("deleting route info", msg.resid);
this.rpcMap.delete(msg.resid);
}
return;
}
dlog("bad rpc message recevied by router, no command, reqid, or resid (discarding)", msg);
}
registerRoute(routeId: string, client: AbstractWshClient) {
if (routeId == SysRouteName) {
throw new Error(`Cannot register route with reserved name (${routeId})`);
}
dlog("registering route: ", routeId);
// announce
const announceMsg: RpcMessage = {
command: "routeannounce",
data: routeId,
source: routeId,
};
this.upstreamClient.recvRpcMessage(announceMsg);
this.routeMap.set(routeId, client);
}
unregisterRoute(routeId: string) {
dlog("unregister route: ", routeId);
// unannounce
const unannounceMsg: RpcMessage = {
command: "routeunannounce",
data: routeId,
source: routeId,
};
this.upstreamClient?.recvRpcMessage(unannounceMsg);
this.routeMap.delete(routeId);
}
}
export { makeFeBlockRouteId, makeWindowRouteId, WshRouter };