annotate web/RdfDbChannel.ts @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents light9/web/RdfDbChannel.ts@cdfd2901918a
children ac55319a2eac
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
1 import debug from "debug";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
2 import { SubEvent } from "sub-events";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
3 import { SyncgraphPatchMessage } from "./patch";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
4 const log = debug("rdfdbclient");
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
5
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
6 class ChannelPinger {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
7 private timeoutId?: number;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
8 private lastMs: number = 0;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
9 constructor(private ws: WebSocket) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
10 this._pingLoop();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
11 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
12 lastPingMs(): number {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
13 return this.lastMs;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
14 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
15 pong() {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
16 this.lastMs = Date.now() + this.lastMs;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
17 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
18 _pingLoop() {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
19 if (this.ws.readyState !== this.ws.OPEN) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
20 return;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
21 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
22 this.ws.send("PING");
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
23 this.lastMs = -Date.now();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
24
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
25 if (this.timeoutId != null) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
26 clearTimeout(this.timeoutId);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
27 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
28 this.timeoutId = (setTimeout(this._pingLoop.bind(this), 10000) as unknown) as number;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
29 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
30 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
31
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
32 export class RdfDbChannel {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
33 // lower level reconnecting websocket -- knows about message types, but not what's inside a patch body
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
34 private ws?: WebSocket = undefined;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
35 private pinger?: ChannelPinger;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
36 private connectionId: string = "none"; // server's name for us
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
37 private reconnectTimer?: NodeJS.Timeout = undefined;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
38 private messagesReceived = 0; // (non-ping messages)
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
39 private messagesSent = 0;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
40
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
41 newConnection: SubEvent<void> = new SubEvent();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
42 serverMessage: SubEvent<{ evType: string; body: SyncgraphPatchMessage }> = new SubEvent();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
43 statusDisplay: SubEvent<string> = new SubEvent();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
44
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
45 constructor(public patchSenderUrl: string) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
46 this.openConnection();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
47 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
48 sendMessage(body: string): boolean {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
49 // one try, best effort, true if we think it worked
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
50 if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
51 return false;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
52 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
53 log("send patch to server, " + body.length + " bytes");
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
54 this.ws.send(body);
2289
f2c6b39c155c fix messagesSend counter
drewp@bigasterisk.com
parents: 2285
diff changeset
55 this.messagesSent++;
f2c6b39c155c fix messagesSend counter
drewp@bigasterisk.com
parents: 2285
diff changeset
56 this.updateStatus();
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
57 return true;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
58 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
59
2322
cdfd2901918a logging
drewp@bigasterisk.com
parents: 2289
diff changeset
60 disconnect(why:string) {
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
61 // will be followed by an autoconnect
2322
cdfd2901918a logging
drewp@bigasterisk.com
parents: 2289
diff changeset
62 log("disconnect requested:", why);
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
63 if (this.ws !== undefined) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
64 const closeHandler = this.ws.onclose?.bind(this.ws);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
65 if (!closeHandler) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
66 throw new Error();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
67 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
68 closeHandler(new CloseEvent("forced"));
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
69 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
70 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
71
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
72 private openConnection() {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
73 const wsOrWss = window.location.protocol.replace("http", "ws");
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
74 const fullUrl = wsOrWss + "//" + window.location.host + this.patchSenderUrl;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
75 if (this.ws !== undefined) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
76 this.ws.close();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
77 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
78 this.ws = new WebSocket(fullUrl);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
79 this.ws.onopen = this.onWsOpen.bind(this, this.ws);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
80 this.ws.onerror = this.onWsError.bind(this);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
81 this.ws.onclose = this.onWsClose.bind(this);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
82 this.ws.onmessage = this.onWsMessage.bind(this);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
83 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
84
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
85 private onWsOpen(ws: WebSocket) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
86 log("new connection to", this.patchSenderUrl);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
87 this.updateStatus();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
88 this.newConnection.emit();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
89 this.pinger = new ChannelPinger(ws);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
90 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
91
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
92 private onWsMessage(evt: { data: string }) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
93 const msg = evt.data;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
94 if (msg === "PONG") {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
95 this.onPong();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
96 return;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
97 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
98 this.onJson(msg);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
99 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
100
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
101 private onPong() {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
102 if (this.pinger) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
103 this.pinger.pong();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
104 this.updateStatus();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
105 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
106 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
107
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
108 private onJson(msg: string) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
109 const input = JSON.parse(msg);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
110 if (input.connectedAs) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
111 this.connectionId = input.connectedAs;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
112 } else {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
113 this.onPatch(input as SyncgraphPatchMessage);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
114 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
115 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
116
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
117 private onPatch(input: SyncgraphPatchMessage) {
2285
cc371473ada1 logging
drewp@bigasterisk.com
parents: 2256
diff changeset
118 log(`patch msg from server`);
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
119 this.serverMessage.emit({ evType: "patch", body: input });
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
120 this.messagesReceived++;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
121 this.updateStatus();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
122 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
123
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
124 private onWsError(e: Event) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
125 log("ws error", e);
2322
cdfd2901918a logging
drewp@bigasterisk.com
parents: 2289
diff changeset
126 this.disconnect("ws error");
2256
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
127 this.updateStatus();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
128 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
129
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
130 private onWsClose(ev: CloseEvent) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
131 log("ws close");
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
132 this.updateStatus();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
133 if (this.reconnectTimer !== undefined) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
134 clearTimeout(this.reconnectTimer);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
135 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
136 this.reconnectTimer = setTimeout(this.openConnection.bind(this), 1000);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
137 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
138
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
139 private updateStatus() {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
140 const conn = (() => {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
141 if (this.ws === undefined) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
142 return "no";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
143 } else {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
144 switch (this.ws.readyState) {
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
145 case this.ws.CONNECTING:
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
146 return "connecting";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
147 case this.ws.OPEN:
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
148 return `open as ${this.connectionId}`;
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
149 case this.ws.CLOSING:
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
150 return "closing";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
151 case this.ws.CLOSED:
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
152 return "close";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
153 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
154 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
155 })();
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
156
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
157 const ping = this.pinger ? this.pinger.lastPingMs() : "...";
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
158 this.statusDisplay.emit(`${conn}; ${this.messagesReceived} recv; ${this.messagesSent} sent; ping ${ping}ms`);
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
159 }
eb34653d315d move to RdfDbChannel.ts
drewp@bigasterisk.com
parents:
diff changeset
160 }