@swf2es/desktop 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/connections.d.ts +14 -2
- package/dist/main/connections.d.ts.map +1 -1
- package/dist/main/connections.js +44 -8
- package/dist/main/connections.js.map +1 -1
- package/dist/main/network.d.ts.map +1 -1
- package/dist/main/network.js +2 -1
- package/dist/main/network.js.map +1 -1
- package/dist/main/proxy.d.ts +16 -1
- package/dist/main/proxy.d.ts.map +1 -1
- package/dist/main/proxy.js +67 -12
- package/dist/main/proxy.js.map +1 -1
- package/dist/main/relay.d.ts +55 -0
- package/dist/main/relay.d.ts.map +1 -0
- package/dist/main/relay.js +140 -0
- package/dist/main/relay.js.map +1 -0
- package/dist/main/sockets.d.ts.map +1 -1
- package/dist/main/sockets.js +21 -5
- package/dist/main/sockets.js.map +1 -1
- package/dist/main/websockets.d.ts.map +1 -1
- package/dist/main/websockets.js +14 -4
- package/dist/main/websockets.js.map +1 -1
- package/dist/preload/preload.cjs +7 -6
- package/dist/preload/preload.cjs.map +1 -1
- package/dist/renderer/sockets.d.ts.map +1 -1
- package/dist/renderer/sockets.js +31 -21
- package/dist/renderer/sockets.js.map +1 -1
- package/dist/renderer/websockets.d.ts.map +1 -1
- package/dist/renderer/websockets.js +29 -19
- package/dist/renderer/websockets.js.map +1 -1
- package/dist/shared/api.d.ts +12 -4
- package/dist/shared/api.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/main/connections.ts +55 -10
- package/src/main/network.ts +3 -1
- package/src/main/proxy.ts +87 -14
- package/src/main/relay.ts +169 -0
- package/src/main/sockets.ts +49 -29
- package/src/main/websockets.ts +17 -4
- package/src/preload/preload.cts +10 -8
- package/src/renderer/sockets.ts +30 -21
- package/src/renderer/websockets.ts +28 -19
- package/src/shared/api.ts +13 -4
package/dist/shared/api.d.ts
CHANGED
|
@@ -147,13 +147,21 @@ export type SocketEvent = {
|
|
|
147
147
|
type: "error";
|
|
148
148
|
message: string;
|
|
149
149
|
};
|
|
150
|
+
/**
|
|
151
|
+
* Events as the shell sends them, gathered over a millisecond at most:
|
|
152
|
+
* each with its connection's id, in the order they came.
|
|
153
|
+
*/
|
|
154
|
+
export type ConnectionEvents<E> = readonly (readonly [id: number, event: E])[];
|
|
150
155
|
/** flash.net.Socket's TCP connections, opened by the shell. */
|
|
151
156
|
export interface DesktopSockets {
|
|
152
|
-
/**
|
|
153
|
-
|
|
157
|
+
/**
|
|
158
|
+
* A connection's id; its events follow, an "error" one if the shell refuses it. `noDelay` is
|
|
159
|
+
* tcpNoDelay as the SWF set it, absent where it did not: the shell then sends at once.
|
|
160
|
+
*/
|
|
161
|
+
connect(host: string, port: number, noDelay?: boolean): number;
|
|
154
162
|
send(id: number, bytes: Uint8Array): void;
|
|
155
163
|
close(id: number): void;
|
|
156
|
-
|
|
164
|
+
onEvents(listener: (events: ConnectionEvents<SocketEvent>) => void): void;
|
|
157
165
|
}
|
|
158
166
|
/** What befalls a WebSocket, as player's WebSocketEvents has it. */
|
|
159
167
|
export type WebSocketEvent = {
|
|
@@ -175,7 +183,7 @@ export interface DesktopWebSockets {
|
|
|
175
183
|
/** A text message for a string, a binary one for bytes. */
|
|
176
184
|
send(id: number, data: string | Uint8Array): void;
|
|
177
185
|
close(id: number, code?: number): void;
|
|
178
|
-
|
|
186
|
+
onEvents(listener: (events: ConnectionEvents<WebSocketEvent>) => void): void;
|
|
179
187
|
}
|
|
180
188
|
/** A request of a SWF's, as player's FetchRequest has it. */
|
|
181
189
|
export interface NetworkRequest {
|
package/dist/shared/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/shared/api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/shared/api.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swf2es/desktop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "swf2es's desktop app: local and remote SWFs, and AIR applications, in an Electron window",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"swf",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"electron": "44.10.2",
|
|
38
|
-
"@swf2es/
|
|
39
|
-
"@swf2es/
|
|
40
|
-
"@swf2es/player": "0.1.
|
|
41
|
-
"@swf2es/
|
|
42
|
-
"@swf2es/player-hosts": "0.1.
|
|
43
|
-
"@swf2es/web": "0.1.
|
|
38
|
+
"@swf2es/format": "0.1.24",
|
|
39
|
+
"@swf2es/codegen": "0.1.24",
|
|
40
|
+
"@swf2es/player": "0.1.24",
|
|
41
|
+
"@swf2es/context3d": "0.1.24",
|
|
42
|
+
"@swf2es/player-hosts": "0.1.24",
|
|
43
|
+
"@swf2es/web": "0.1.24"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"fetch-electron": "node node_modules/electron/install.js",
|
package/src/main/connections.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// the proxy (--proxy, proxy.ts): what the socket bridge (sockets.ts) holds
|
|
3
3
|
// for each page, apart from Electron so that node runs it in the tests
|
|
4
4
|
// (tests/desktop/connections.test.ts).
|
|
5
|
-
import { connect, type Socket } from "node:net";
|
|
5
|
+
import { connect, type OnReadOpts, type Socket } from "node:net";
|
|
6
6
|
import type { SocketEvent } from "../shared/api.js";
|
|
7
|
-
import {
|
|
7
|
+
import { type ProxyConfig, type ProxyError, tunnelThrough } from "./proxy.ts";
|
|
8
8
|
|
|
9
9
|
/** As many as a page may hold open at once; past it a connection is refused. */
|
|
10
10
|
const MAX_OPEN = 64;
|
|
@@ -17,6 +17,13 @@ const MAX_OPEN = 64;
|
|
|
17
17
|
*/
|
|
18
18
|
export const MAX_BUFFERED = 4 * 1024 * 1024;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Each connection's read buffer, read into again and again, so that a read
|
|
22
|
+
* makes one store, its copy for the page, where Node's stream would make a
|
|
23
|
+
* Buffer for it besides.
|
|
24
|
+
*/
|
|
25
|
+
const READ_BUFFER = 64 * 1024;
|
|
26
|
+
|
|
20
27
|
const SOCKET_ERROR = "Error #2031: Socket Error.";
|
|
21
28
|
|
|
22
29
|
/** Whether the page asked for a host name of DNS's length and a TCP port. */
|
|
@@ -64,8 +71,12 @@ export class Connections {
|
|
|
64
71
|
/**
|
|
65
72
|
* Connect `id` to `host`:`port`, each checked, as the page asks, at `address` where the host's
|
|
66
73
|
* was pinned (a remote SWF's socket policy came from there); a refusal is an error, then a close.
|
|
74
|
+
* It sends at once (TCP_NODELAY) unless `noDelay` is false, as a SWF's tcpNoDelay set so asks:
|
|
75
|
+
* with Nagle's algorithm, node's default, the second of two small writes waits for the peer to
|
|
76
|
+
* acknowledge the first, which a peer that has nothing to send back delays (some 40 ms on Linux,
|
|
77
|
+
* up to 200 ms on Windows), and a chatty protocol's every exchange with it.
|
|
67
78
|
*/
|
|
68
|
-
connect(id: number, host: unknown, port: unknown, address?: string): void {
|
|
79
|
+
connect(id: number, host: unknown, port: unknown, address?: string, noDelay = true): void {
|
|
69
80
|
if (
|
|
70
81
|
!validEndpoint(host, port) ||
|
|
71
82
|
this.sockets.has(id) ||
|
|
@@ -78,11 +89,16 @@ export class Connections {
|
|
|
78
89
|
|
|
79
90
|
const target = address ?? host;
|
|
80
91
|
if (this.proxy) {
|
|
81
|
-
this.connectThrough(this.proxy, id, target, port as number);
|
|
92
|
+
this.connectThrough(this.proxy, id, target, port as number, noDelay);
|
|
82
93
|
return;
|
|
83
94
|
}
|
|
84
95
|
|
|
85
|
-
const socket = connect({
|
|
96
|
+
const socket = connect({
|
|
97
|
+
host: target,
|
|
98
|
+
port: port as number,
|
|
99
|
+
noDelay,
|
|
100
|
+
onread: this.reader(id),
|
|
101
|
+
});
|
|
86
102
|
socket.on("connect", () =>
|
|
87
103
|
this.tell(id, {
|
|
88
104
|
type: "open",
|
|
@@ -99,19 +115,28 @@ export class Connections {
|
|
|
99
115
|
* Connect `id` through `proxy`, by the address where one was pinned, else
|
|
100
116
|
* by name for the proxy to resolve. Its peer is the target: the proxy's
|
|
101
117
|
* address is no business of the SWF's. A proxy that fails is a refusal,
|
|
102
|
-
* said with why.
|
|
118
|
+
* said with why. Nagle's algorithm is left on through the handshake,
|
|
119
|
+
* which never writes twice without an answer between, so nothing in it
|
|
120
|
+
* waits; it goes off as the tunnel opens, before the SWF's first byte.
|
|
103
121
|
*/
|
|
104
|
-
private connectThrough(
|
|
122
|
+
private connectThrough(
|
|
123
|
+
proxy: ProxyConfig,
|
|
124
|
+
id: number,
|
|
125
|
+
target: string,
|
|
126
|
+
port: number,
|
|
127
|
+
noDelay: boolean,
|
|
128
|
+
): void {
|
|
105
129
|
const opening = new AbortController();
|
|
106
130
|
this.opening.set(id, opening);
|
|
107
|
-
|
|
108
|
-
(socket) => {
|
|
131
|
+
tunnelThrough(proxy, target, port, { signal: opening.signal, onread: this.reader(id) }).then(
|
|
132
|
+
({ socket, rest }) => {
|
|
109
133
|
if (this.opening.get(id) !== opening) {
|
|
110
134
|
socket.destroy();
|
|
111
135
|
return;
|
|
112
136
|
}
|
|
113
137
|
|
|
114
138
|
this.opening.delete(id);
|
|
139
|
+
socket.setNoDelay(noDelay);
|
|
115
140
|
this.attach(id, socket);
|
|
116
141
|
this.tell(id, {
|
|
117
142
|
type: "open",
|
|
@@ -120,6 +145,12 @@ export class Connections {
|
|
|
120
145
|
remoteAddress: target,
|
|
121
146
|
remotePort: port,
|
|
122
147
|
});
|
|
148
|
+
// What came with the proxy's reply is the connection's first.
|
|
149
|
+
if (rest.length > 0) {
|
|
150
|
+
this.tell(id, { type: "data", bytes: rest });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
socket.resume();
|
|
123
154
|
},
|
|
124
155
|
(error: ProxyError) => {
|
|
125
156
|
if (this.opening.get(id) !== opening) {
|
|
@@ -133,9 +164,23 @@ export class Connections {
|
|
|
133
164
|
);
|
|
134
165
|
}
|
|
135
166
|
|
|
167
|
+
/**
|
|
168
|
+
* How `id`'s socket is read: into a buffer of its own, each read copied
|
|
169
|
+
* out at its length for the page. It never pauses the socket, as its
|
|
170
|
+
* stream never did.
|
|
171
|
+
*/
|
|
172
|
+
private reader(id: number): OnReadOpts {
|
|
173
|
+
return {
|
|
174
|
+
buffer: new Uint8Array(READ_BUFFER),
|
|
175
|
+
callback: (length, buffer) => {
|
|
176
|
+
this.tell(id, { type: "data", bytes: new Uint8Array(buffer.subarray(0, length)) });
|
|
177
|
+
return true;
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
136
182
|
private attach(id: number, socket: Socket): void {
|
|
137
183
|
this.sockets.set(id, socket);
|
|
138
|
-
socket.on("data", (bytes) => this.tell(id, { type: "data", bytes: new Uint8Array(bytes) }));
|
|
139
184
|
socket.on("error", () => this.tell(id, { type: "error", message: SOCKET_ERROR }));
|
|
140
185
|
socket.on("close", () => {
|
|
141
186
|
// Only the socket under this id: a page that reused it has another by now.
|
package/src/main/network.ts
CHANGED
|
@@ -78,6 +78,8 @@ import {
|
|
|
78
78
|
} from "./policy.ts";
|
|
79
79
|
import { connectThrough, type ProxyConfig, type ProxyError } from "./proxy.ts";
|
|
80
80
|
|
|
81
|
+
const textDecoder = new TextDecoder();
|
|
82
|
+
|
|
81
83
|
/** What Flash Player 32 reported, sent as it sent it. */
|
|
82
84
|
const FLASH_VERSION = "32,0,0,465";
|
|
83
85
|
const USER_AGENT = "Mozilla/5.0 (compatible; swf2es) Shockwave Flash";
|
|
@@ -644,7 +646,7 @@ export class Network {
|
|
|
644
646
|
return null;
|
|
645
647
|
}
|
|
646
648
|
|
|
647
|
-
const policy = parsePolicy(
|
|
649
|
+
const policy = parsePolicy(textDecoder.decode(response.bytes));
|
|
648
650
|
return policy && { policy, url, contentType, permitted };
|
|
649
651
|
}
|
|
650
652
|
|
package/src/main/proxy.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// command line's alone: never kept, and never said.
|
|
8
8
|
//
|
|
9
9
|
// Without Electron, so that node tests it (tests/desktop/proxy.test.ts).
|
|
10
|
-
import { connect, isIP, isIPv4, type Socket } from "node:net";
|
|
10
|
+
import { connect, isIP, isIPv4, type OnReadOpts, type Socket } from "node:net";
|
|
11
11
|
import { domainToASCII } from "node:url";
|
|
12
12
|
|
|
13
13
|
export interface ProxyConfig {
|
|
@@ -200,26 +200,39 @@ function ipv6Bytes(address: string): Buffer {
|
|
|
200
200
|
return bytes;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* Reads a socket's bytes as a handshake needs them, and gives back what it
|
|
205
|
+
* did not need. A socket read by its stream is read here by "readable"; one
|
|
206
|
+
* read by `onread` (net.connect's option) is fed what it reads.
|
|
207
|
+
*/
|
|
204
208
|
class Reader {
|
|
205
209
|
private buffered = Buffer.alloc(0);
|
|
206
210
|
private wake: (() => void) | null = null;
|
|
207
211
|
private ended = false;
|
|
208
212
|
private readonly socket: Socket;
|
|
213
|
+
private readonly streamed: boolean;
|
|
209
214
|
|
|
210
|
-
constructor(socket: Socket) {
|
|
215
|
+
constructor(socket: Socket, streamed: boolean) {
|
|
211
216
|
this.socket = socket;
|
|
212
|
-
|
|
217
|
+
this.streamed = streamed;
|
|
218
|
+
if (streamed) {
|
|
219
|
+
socket.on("readable", this.readable);
|
|
220
|
+
}
|
|
221
|
+
|
|
213
222
|
socket.on("end", this.end);
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
private readonly readable = () => {
|
|
217
226
|
for (let chunk = this.socket.read() as Buffer | null; chunk; chunk = this.socket.read()) {
|
|
218
|
-
this.
|
|
227
|
+
this.feed(chunk);
|
|
219
228
|
}
|
|
229
|
+
};
|
|
220
230
|
|
|
231
|
+
/** Bytes read, copied: an `onread` buffer is read into again. */
|
|
232
|
+
feed(bytes: Uint8Array): void {
|
|
233
|
+
this.buffered = Buffer.concat([this.buffered, bytes]);
|
|
221
234
|
this.wake?.();
|
|
222
|
-
}
|
|
235
|
+
}
|
|
223
236
|
|
|
224
237
|
private readonly end = () => {
|
|
225
238
|
this.ended = true;
|
|
@@ -263,13 +276,25 @@ class Reader {
|
|
|
263
276
|
}
|
|
264
277
|
}
|
|
265
278
|
|
|
266
|
-
/**
|
|
267
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Stop reading. What came past the handshake goes back to the stream for
|
|
281
|
+
* its next reader, or, for a socket read by `onread`, is given back, a
|
|
282
|
+
* copy of its own.
|
|
283
|
+
*/
|
|
284
|
+
release(): Uint8Array {
|
|
268
285
|
this.socket.removeListener("readable", this.readable);
|
|
269
286
|
this.socket.removeListener("end", this.end);
|
|
270
|
-
|
|
271
|
-
|
|
287
|
+
const rest = this.buffered;
|
|
288
|
+
this.buffered = Buffer.alloc(0);
|
|
289
|
+
if (!this.streamed) {
|
|
290
|
+
return new Uint8Array(rest);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (rest.length > 0) {
|
|
294
|
+
this.socket.unshift(rest);
|
|
272
295
|
}
|
|
296
|
+
|
|
297
|
+
return new Uint8Array(0);
|
|
273
298
|
}
|
|
274
299
|
}
|
|
275
300
|
|
|
@@ -427,6 +452,32 @@ export function connectThrough(
|
|
|
427
452
|
port: number,
|
|
428
453
|
options: { signal?: AbortSignal; timeout?: number } = {},
|
|
429
454
|
): Promise<Socket> {
|
|
455
|
+
return tunnel(proxy, host, port, options, null).then(({ socket }) => socket);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* As connectThrough, the tunnel's bytes read by `onread` (net.connect's
|
|
460
|
+
* option) rather than its stream: the socket comes paused, with the bytes
|
|
461
|
+
* that came with the proxy's reply, for its reader to take before it
|
|
462
|
+
* resumes the socket, so that nothing is read before whoever reads is
|
|
463
|
+
* ready. The handshake reads through `onread`'s buffer too.
|
|
464
|
+
*/
|
|
465
|
+
export function tunnelThrough(
|
|
466
|
+
proxy: ProxyConfig,
|
|
467
|
+
host: string,
|
|
468
|
+
port: number,
|
|
469
|
+
options: { signal?: AbortSignal; timeout?: number; onread: OnReadOpts },
|
|
470
|
+
): Promise<{ socket: Socket; rest: Uint8Array }> {
|
|
471
|
+
return tunnel(proxy, host, port, options, options.onread);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function tunnel(
|
|
475
|
+
proxy: ProxyConfig,
|
|
476
|
+
host: string,
|
|
477
|
+
port: number,
|
|
478
|
+
options: { signal?: AbortSignal; timeout?: number },
|
|
479
|
+
onread: OnReadOpts | null,
|
|
480
|
+
): Promise<{ socket: Socket; rest: Uint8Array }> {
|
|
430
481
|
const where = describeProxy(proxy);
|
|
431
482
|
return new Promise((resolve, reject) => {
|
|
432
483
|
let target: ReturnType<typeof targetHost>;
|
|
@@ -448,8 +499,26 @@ export function connectThrough(
|
|
|
448
499
|
return;
|
|
449
500
|
}
|
|
450
501
|
|
|
451
|
-
|
|
452
|
-
|
|
502
|
+
// Until the tunnel is made its bytes are the handshake's; then onread's own.
|
|
503
|
+
let tunnelled = false;
|
|
504
|
+
const socket = onread
|
|
505
|
+
? connect({
|
|
506
|
+
host: proxy.host,
|
|
507
|
+
port: proxy.port,
|
|
508
|
+
onread: {
|
|
509
|
+
buffer: onread.buffer,
|
|
510
|
+
callback: (length, buffer) => {
|
|
511
|
+
if (tunnelled) {
|
|
512
|
+
return onread.callback(length, buffer);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
reader.feed(buffer.subarray(0, length));
|
|
516
|
+
return true;
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
})
|
|
520
|
+
: connect({ host: proxy.host, port: proxy.port });
|
|
521
|
+
const reader = new Reader(socket, !onread);
|
|
453
522
|
let settled = false;
|
|
454
523
|
const finish = (error: ProxyError | null) => {
|
|
455
524
|
if (settled) {
|
|
@@ -466,8 +535,12 @@ export function connectThrough(
|
|
|
466
535
|
socket.destroy();
|
|
467
536
|
reject(error);
|
|
468
537
|
} else {
|
|
469
|
-
|
|
470
|
-
|
|
538
|
+
if (onread) {
|
|
539
|
+
socket.pause();
|
|
540
|
+
tunnelled = true;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
resolve({ socket, rest: reader.release() });
|
|
471
544
|
}
|
|
472
545
|
};
|
|
473
546
|
const abort = () => finish(new ProxyError("aborted", false));
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// What a page's connections say to it, gathered into one IPC message a
|
|
2
|
+
// millisecond at most: each message is serialized, posted and run as a
|
|
3
|
+
// task of the page's on its own, so a socket read or a WebSocket message
|
|
4
|
+
// apiece cost a page with busy connections tens of thousands a second.
|
|
5
|
+
// Apart from Electron so that node runs it in the tests
|
|
6
|
+
// (tests/desktop/relay.test.ts).
|
|
7
|
+
|
|
8
|
+
/** Each connection's events, by its id, in the order they came. */
|
|
9
|
+
export type Batch<E> = [id: number, event: E][];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A batch that holds this many bytes goes at once, not when it would: a
|
|
13
|
+
* busy socket is not kept from its page, and neither the main process nor
|
|
14
|
+
* one message grows past it by more than a read.
|
|
15
|
+
*/
|
|
16
|
+
export const FLUSH_AT = 256 * 1024;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The least time between two batches, in milliseconds. The first event
|
|
20
|
+
* after a quiet spell goes at the end of its turn, so that a request's
|
|
21
|
+
* answer waits for nothing; what follows within the window waits for its
|
|
22
|
+
* end, and goes with the rest that came by then. Socket reads that cost
|
|
23
|
+
* little come many to a millisecond, each with a few bytes: a turn's
|
|
24
|
+
* batch alone left one message for most of them. On Windows the timer
|
|
25
|
+
* may wait for the system's resolution, about 16 ms: docs/architecture/
|
|
26
|
+
* desktop.md says why that does.
|
|
27
|
+
*/
|
|
28
|
+
export const WINDOW = 1;
|
|
29
|
+
|
|
30
|
+
interface Joining<E> {
|
|
31
|
+
/** Where its event is in the batch. */
|
|
32
|
+
at: number;
|
|
33
|
+
chunks: Uint8Array[];
|
|
34
|
+
length: number;
|
|
35
|
+
wrap: (bytes: Uint8Array) => E;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class Relay<E> {
|
|
39
|
+
private readonly send: (batch: Batch<E>) => void;
|
|
40
|
+
private readonly flushAt: number;
|
|
41
|
+
private batch: Batch<E> = [];
|
|
42
|
+
private size = 0;
|
|
43
|
+
/** Each connection's bytes, while nothing else of it has come after them in the batch. */
|
|
44
|
+
private readonly joining = new Map<number, Joining<E>>();
|
|
45
|
+
private readonly window: number;
|
|
46
|
+
private immediate: ReturnType<typeof setImmediate> | null = null;
|
|
47
|
+
private timer: ReturnType<typeof setTimeout> | null = null;
|
|
48
|
+
/** When the last batch went, by performance.now(). */
|
|
49
|
+
private sent = Number.NEGATIVE_INFINITY;
|
|
50
|
+
|
|
51
|
+
/** `send` takes each batch, never an empty one. */
|
|
52
|
+
constructor(send: (batch: Batch<E>) => void, flushAt = FLUSH_AT, window = WINDOW) {
|
|
53
|
+
this.send = send;
|
|
54
|
+
this.flushAt = flushAt;
|
|
55
|
+
this.window = window;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** `event` for `id`, after whatever came for it before; `size` of its bytes count to FLUSH_AT. */
|
|
59
|
+
push(id: number, event: E, size = 0): void {
|
|
60
|
+
this.seal(id);
|
|
61
|
+
this.batch.push([id, event]);
|
|
62
|
+
this.added(size);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Bytes read for `id`, which it no longer holds: one event, as `wrap`
|
|
67
|
+
* makes it, with the bytes read for it before them in this batch.
|
|
68
|
+
*/
|
|
69
|
+
bytes(id: number, chunk: Uint8Array, wrap: (bytes: Uint8Array) => E): void {
|
|
70
|
+
const joining = this.joining.get(id);
|
|
71
|
+
if (joining) {
|
|
72
|
+
joining.chunks.push(chunk);
|
|
73
|
+
joining.length += chunk.length;
|
|
74
|
+
} else {
|
|
75
|
+
this.joining.set(id, { at: this.batch.length, chunks: [chunk], length: chunk.length, wrap });
|
|
76
|
+
this.batch.push([id, wrap(chunk)]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.added(chunk.length);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Send what is gathered now. */
|
|
83
|
+
flush(): void {
|
|
84
|
+
this.unschedule();
|
|
85
|
+
if (this.batch.length === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const id of this.joining.keys()) {
|
|
90
|
+
this.seal(id);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const batch = this.batch;
|
|
94
|
+
this.batch = [];
|
|
95
|
+
this.size = 0;
|
|
96
|
+
this.sent = performance.now();
|
|
97
|
+
this.send(batch);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Forget what is gathered: its page is gone, and the next numbers its connections from 1. */
|
|
101
|
+
drop(): void {
|
|
102
|
+
this.unschedule();
|
|
103
|
+
this.batch = [];
|
|
104
|
+
this.size = 0;
|
|
105
|
+
this.joining.clear();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private added(size: number): void {
|
|
109
|
+
this.size += size;
|
|
110
|
+
if (this.size >= this.flushAt) {
|
|
111
|
+
this.flush();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (this.immediate || this.timer) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const wait = this.sent + this.window - performance.now();
|
|
120
|
+
if (wait > 0) {
|
|
121
|
+
this.timer = setTimeout(this.flushing, wait);
|
|
122
|
+
} else {
|
|
123
|
+
this.immediate = setImmediate(this.flushing);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private readonly flushing = () => {
|
|
128
|
+
this.immediate = null;
|
|
129
|
+
this.timer = null;
|
|
130
|
+
this.flush();
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
private unschedule(): void {
|
|
134
|
+
if (this.immediate) {
|
|
135
|
+
clearImmediate(this.immediate);
|
|
136
|
+
this.immediate = null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.timer) {
|
|
140
|
+
clearTimeout(this.timer);
|
|
141
|
+
this.timer = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* `id`'s bytes as one event, the chunks joined where there are more than
|
|
147
|
+
* one: a second copy of theirs, but one event for the SWF rather than one
|
|
148
|
+
* for each read, which costs it far more than the copy.
|
|
149
|
+
*/
|
|
150
|
+
private seal(id: number): void {
|
|
151
|
+
const joining = this.joining.get(id);
|
|
152
|
+
if (!joining) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.joining.delete(id);
|
|
157
|
+
|
|
158
|
+
if (joining.chunks.length > 1) {
|
|
159
|
+
const bytes = new Uint8Array(joining.length);
|
|
160
|
+
let offset = 0;
|
|
161
|
+
for (let i = 0; i < joining.chunks.length; i++) {
|
|
162
|
+
bytes.set(joining.chunks[i], offset);
|
|
163
|
+
offset += joining.chunks[i].length;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.batch[joining.at][1] = joining.wrap(bytes);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|