@evolu/nodejs 1.0.1-preview.8 → 1.0.1-preview.9
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/Evolu/Relay.d.ts +17 -2
- package/dist/Evolu/Relay.d.ts.map +1 -1
- package/dist/Evolu/Relay.js +96 -60
- package/package.json +3 -3
- package/src/Evolu/Relay.ts +128 -71
package/dist/Evolu/Relay.d.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { ConsoleDep } from "@evolu/common";
|
|
1
|
+
import { ConsoleDep, CreateSqliteDriverDep, Result, SqliteError } from "@evolu/common";
|
|
2
2
|
import { Relay, RelayConfig } from "@evolu/common/evolu";
|
|
3
3
|
export interface NodeJsRelayConfig extends RelayConfig {
|
|
4
|
+
/** The port number for the HTTP server. */
|
|
4
5
|
readonly port?: number;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Creates an Evolu relay server.
|
|
9
|
+
*
|
|
10
|
+
* This implementation uses Node.js and better-sqlite3. Additional relay
|
|
11
|
+
* implementations will be provided for other platforms (Bun, Deno, Cloudflare
|
|
12
|
+
* Workers, Vercel Edge, etc.).
|
|
13
|
+
*/
|
|
14
|
+
export declare const createNodeJsRelay: (deps: ConsoleDep) => (config: NodeJsRelayConfig) => Promise<Result<Relay, SqliteError>>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates an Evolu relay server with a custom SQLite driver.
|
|
17
|
+
*
|
|
18
|
+
* Use this when you need to provide a different SQLite driver implementation
|
|
19
|
+
* (e.g., using alternative SQLite libraries).
|
|
20
|
+
*/
|
|
21
|
+
export declare const createNodeJsRelayWithSqliteDriver: (deps: ConsoleDep & CreateSqliteDriverDep) => (config: NodeJsRelayConfig) => Promise<Result<Relay, SqliteError>>;
|
|
7
22
|
//# sourceMappingURL=Relay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../src/Evolu/Relay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,
|
|
1
|
+
{"version":3,"file":"Relay.d.ts","sourceRoot":"","sources":["../../src/Evolu/Relay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,qBAAqB,EAIrB,MAAM,EAEN,WAAW,EAGZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAOL,KAAK,EACL,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAM7B,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC3B,MAAM,UAAU,MAChB,QAAQ,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAInD,CAAC;AAEf;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,GAC3C,MAAM,UAAU,GAAG,qBAAqB,MACxC,QAAQ,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAKnD,CAAC"}
|
package/dist/Evolu/Relay.js
CHANGED
|
@@ -1,54 +1,98 @@
|
|
|
1
|
-
import { createManyToManyMap, createRandom, createSqlite,
|
|
2
|
-
import { applyProtocolMessageAsRelay,
|
|
1
|
+
import { createManyToManyMap, createRandom, createSqlite, ok, SimpleName, Uint8Array, } from "@evolu/common";
|
|
2
|
+
import { applyProtocolMessageAsRelay, createRelayLogger, createRelaySqliteStorage, defaultProtocolMessageMaxSize, parseOwnerIdFromUrl, } from "@evolu/common/evolu";
|
|
3
|
+
import { createServer } from "http";
|
|
3
4
|
import { WebSocket, WebSocketServer } from "ws";
|
|
4
5
|
import { createBetterSqliteDriver } from "../BetterSqliteDriver.js";
|
|
5
6
|
import { createTimingSafeEqual } from "../Crypto.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Creates an Evolu relay server.
|
|
9
|
+
*
|
|
10
|
+
* This implementation uses Node.js and better-sqlite3. Additional relay
|
|
11
|
+
* implementations will be provided for other platforms (Bun, Deno, Cloudflare
|
|
12
|
+
* Workers, Vercel Edge, etc.).
|
|
13
|
+
*/
|
|
14
|
+
export const createNodeJsRelay = (deps) => (config) => createNodeJsRelayWithSqliteDriver({
|
|
15
|
+
...deps,
|
|
16
|
+
createSqliteDriver: createBetterSqliteDriver,
|
|
17
|
+
})(config);
|
|
18
|
+
/**
|
|
19
|
+
* Creates an Evolu relay server with a custom SQLite driver.
|
|
20
|
+
*
|
|
21
|
+
* Use this when you need to provide a different SQLite driver implementation
|
|
22
|
+
* (e.g., using alternative SQLite libraries).
|
|
23
|
+
*/
|
|
24
|
+
export const createNodeJsRelayWithSqliteDriver = (deps) => (config) => createNodeJsRelayWithDeps({
|
|
25
|
+
...deps,
|
|
26
|
+
random: createRandom(),
|
|
27
|
+
timingSafeEqual: createTimingSafeEqual(),
|
|
28
|
+
})(config);
|
|
29
|
+
const createNodeJsRelayWithDeps = (deps) => async ({ port = 443, name = SimpleName.orThrow("evolu-relay"), enableLogging = false, authenticateOwner, }) => {
|
|
30
|
+
const log = createRelayLogger(deps);
|
|
31
|
+
log.started(enableLogging, port);
|
|
32
|
+
const sqliteResult = await createSqlite(deps)(name);
|
|
33
|
+
if (!sqliteResult.ok)
|
|
34
|
+
return sqliteResult;
|
|
35
|
+
const sqlite = sqliteResult.value;
|
|
36
|
+
const storageResult = createRelaySqliteStorage({ ...deps, sqlite })({
|
|
37
|
+
onStorageError: log.storageError,
|
|
38
|
+
});
|
|
39
|
+
if (!storageResult.ok)
|
|
40
|
+
return storageResult;
|
|
41
|
+
const storage = storageResult.value;
|
|
42
|
+
const server = createServer();
|
|
25
43
|
const wss = new WebSocketServer({
|
|
26
|
-
maxPayload:
|
|
27
|
-
|
|
44
|
+
maxPayload: defaultProtocolMessageMaxSize,
|
|
45
|
+
noServer: true,
|
|
28
46
|
});
|
|
29
47
|
const ownerSocketsMap = createManyToManyMap();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
48
|
+
server.on("upgrade", (request, socket, head) => {
|
|
49
|
+
socket.on("error", log.upgradeSocketError);
|
|
50
|
+
const completeUpgrade = () => {
|
|
51
|
+
socket.removeListener("error", log.upgradeSocketError);
|
|
52
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
53
|
+
wss.emit("connection", ws, request);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
if (!authenticateOwner) {
|
|
57
|
+
completeUpgrade();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const ownerId = parseOwnerIdFromUrl(request.url);
|
|
61
|
+
if (!ownerId) {
|
|
62
|
+
log.invalidOrMissingOwnerIdInUrl(request.url);
|
|
63
|
+
socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
64
|
+
socket.destroy();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
authenticateOwner(ownerId)
|
|
68
|
+
.then((isAuthenticated) => {
|
|
69
|
+
if (!isAuthenticated) {
|
|
70
|
+
log.unauthorizedOwner(ownerId);
|
|
71
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
72
|
+
socket.destroy();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
completeUpgrade();
|
|
76
|
+
})
|
|
77
|
+
.catch((error) => {
|
|
78
|
+
log.authenticateOwnerError(error);
|
|
79
|
+
socket.write("HTTP/1.1 500 Internal Server Error\r\n\r\n");
|
|
80
|
+
socket.destroy();
|
|
33
81
|
});
|
|
82
|
+
});
|
|
83
|
+
wss.on("connection", (ws) => {
|
|
84
|
+
log.connectionEstablished(wss.clients.size);
|
|
34
85
|
ws.on("error", (error) => {
|
|
35
|
-
|
|
36
|
-
deps.console.error(error);
|
|
86
|
+
log.connectionWebSocketError(error);
|
|
37
87
|
});
|
|
38
88
|
const options = {
|
|
39
89
|
subscribe: (ownerId) => {
|
|
40
90
|
ownerSocketsMap.add(ownerId, ws);
|
|
41
|
-
|
|
42
|
-
ownerId,
|
|
43
|
-
subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
|
|
44
|
-
});
|
|
91
|
+
log.relayOptionSubscribe(ownerId, () => ownerSocketsMap.getValues(ownerId)?.size ?? 0);
|
|
45
92
|
},
|
|
46
93
|
unsubscribe: (ownerId) => {
|
|
47
94
|
ownerSocketsMap.remove(ownerId, ws);
|
|
48
|
-
|
|
49
|
-
ownerId,
|
|
50
|
-
subscriberCount: ownerSocketsMap.getValues(ownerId)?.size ?? 0,
|
|
51
|
-
});
|
|
95
|
+
log.relayOptionUnsubscribe(ownerId, () => ownerSocketsMap.getValues(ownerId)?.size ?? 0);
|
|
52
96
|
},
|
|
53
97
|
broadcast: (ownerId, message) => {
|
|
54
98
|
const sockets = ownerSocketsMap.getValues(ownerId);
|
|
@@ -61,61 +105,53 @@ export const createNodeJsRelay = (deps) => async (config) => {
|
|
|
61
105
|
broadcastCount++;
|
|
62
106
|
}
|
|
63
107
|
}
|
|
64
|
-
|
|
65
|
-
ownerId,
|
|
66
|
-
broadcastCount,
|
|
67
|
-
totalSubscribers: sockets.size,
|
|
68
|
-
});
|
|
108
|
+
log.relayOptionBroadcast(ownerId, broadcastCount, sockets.size);
|
|
69
109
|
},
|
|
70
110
|
};
|
|
71
111
|
ws.on("message", (message) => {
|
|
72
112
|
if (!Uint8Array.is(message))
|
|
73
113
|
return;
|
|
74
|
-
|
|
75
|
-
messageSize: message.length,
|
|
76
|
-
});
|
|
114
|
+
log.messageLength(message.length);
|
|
77
115
|
applyProtocolMessageAsRelay({ storage })(message, options)
|
|
78
116
|
.then((response) => {
|
|
79
117
|
if (!response.ok) {
|
|
80
|
-
|
|
81
|
-
deps.console.error(response.error);
|
|
118
|
+
log.applyProtocolMessageAsRelayError(response.error);
|
|
82
119
|
return;
|
|
83
120
|
}
|
|
84
121
|
ws.send(response.value.message, { binary: true });
|
|
85
|
-
|
|
86
|
-
responseSize: response.value.message.length,
|
|
87
|
-
});
|
|
122
|
+
log.responseLength(response.value.message.length);
|
|
88
123
|
})
|
|
89
|
-
.catch(
|
|
90
|
-
deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
|
|
91
|
-
});
|
|
124
|
+
.catch(log.applyProtocolMessageAsRelayUnknownError);
|
|
92
125
|
});
|
|
93
126
|
ws.on("close", () => {
|
|
94
127
|
ownerSocketsMap.deleteValue(ws);
|
|
95
|
-
|
|
96
|
-
clientCount: wss.clients.size,
|
|
97
|
-
});
|
|
128
|
+
log.connectionClosed(wss.clients.size);
|
|
98
129
|
});
|
|
99
130
|
});
|
|
100
|
-
|
|
101
|
-
|
|
131
|
+
server.listen(port);
|
|
132
|
+
const dispose = () => {
|
|
133
|
+
log.shuttingDown();
|
|
102
134
|
wss.clients.forEach((client) => {
|
|
103
135
|
if (client.readyState === WebSocket.OPEN) {
|
|
104
136
|
client.close(1000, "Evolu Relay shutting down");
|
|
105
137
|
}
|
|
106
138
|
});
|
|
107
139
|
wss.close(() => {
|
|
108
|
-
|
|
140
|
+
log.webSocketServerDisposed();
|
|
141
|
+
});
|
|
142
|
+
server.close(() => {
|
|
143
|
+
log.httpServerDisposed();
|
|
109
144
|
});
|
|
110
145
|
};
|
|
111
146
|
let isDisposed = false;
|
|
112
|
-
|
|
147
|
+
const relay = {
|
|
113
148
|
[Symbol.dispose]: () => {
|
|
114
149
|
if (isDisposed)
|
|
115
150
|
return;
|
|
116
151
|
isDisposed = true;
|
|
117
152
|
sqlite[Symbol.dispose]();
|
|
118
|
-
|
|
153
|
+
dispose();
|
|
119
154
|
},
|
|
120
155
|
};
|
|
156
|
+
return ok(relay);
|
|
121
157
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/nodejs",
|
|
3
|
-
"version": "1.0.1-preview.
|
|
3
|
+
"version": "1.0.1-preview.9",
|
|
4
4
|
"description": "Evolu for Node.js",
|
|
5
5
|
"author": "Daniel Steigerwald <daniel@steigerwald.cz>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"shx": "^0.4.0",
|
|
31
31
|
"typescript": "^5.9.2",
|
|
32
32
|
"vitest": "^4.0.4",
|
|
33
|
-
"@evolu/common": "6.0.1-preview.
|
|
33
|
+
"@evolu/common": "6.0.1-preview.21",
|
|
34
34
|
"@evolu/tsconfig": "0.0.2"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@evolu/common": "^6.0.1-preview.
|
|
37
|
+
"@evolu/common": "^6.0.1-preview.21"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/src/Evolu/Relay.ts
CHANGED
|
@@ -3,94 +3,158 @@ import {
|
|
|
3
3
|
createManyToManyMap,
|
|
4
4
|
createRandom,
|
|
5
5
|
createSqlite,
|
|
6
|
-
|
|
6
|
+
CreateSqliteDriverDep,
|
|
7
|
+
ok,
|
|
7
8
|
OwnerId,
|
|
9
|
+
RandomDep,
|
|
10
|
+
Result,
|
|
8
11
|
SimpleName,
|
|
12
|
+
SqliteError,
|
|
13
|
+
TimingSafeEqualDep,
|
|
9
14
|
Uint8Array,
|
|
10
15
|
} from "@evolu/common";
|
|
11
16
|
import {
|
|
12
17
|
applyProtocolMessageAsRelay,
|
|
13
18
|
ApplyProtocolMessageAsRelayOptions,
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
createRelayLogger,
|
|
20
|
+
createRelaySqliteStorage,
|
|
21
|
+
defaultProtocolMessageMaxSize,
|
|
22
|
+
parseOwnerIdFromUrl,
|
|
16
23
|
Relay,
|
|
17
24
|
RelayConfig,
|
|
18
|
-
RelaySqliteStorageDeps,
|
|
19
25
|
} from "@evolu/common/evolu";
|
|
26
|
+
import { createServer } from "http";
|
|
20
27
|
import { WebSocket, WebSocketServer } from "ws";
|
|
21
28
|
import { createBetterSqliteDriver } from "../BetterSqliteDriver.js";
|
|
22
29
|
import { createTimingSafeEqual } from "../Crypto.js";
|
|
23
30
|
|
|
24
31
|
export interface NodeJsRelayConfig extends RelayConfig {
|
|
32
|
+
/** The port number for the HTTP server. */
|
|
25
33
|
readonly port?: number;
|
|
26
34
|
}
|
|
27
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Creates an Evolu relay server.
|
|
38
|
+
*
|
|
39
|
+
* This implementation uses Node.js and better-sqlite3. Additional relay
|
|
40
|
+
* implementations will be provided for other platforms (Bun, Deno, Cloudflare
|
|
41
|
+
* Workers, Vercel Edge, etc.).
|
|
42
|
+
*/
|
|
28
43
|
export const createNodeJsRelay =
|
|
29
44
|
(deps: ConsoleDep) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const relaySqliteStorageDeps: RelaySqliteStorageDeps = {
|
|
49
|
-
sqlite,
|
|
45
|
+
(config: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> =>
|
|
46
|
+
createNodeJsRelayWithSqliteDriver({
|
|
47
|
+
...deps,
|
|
48
|
+
createSqliteDriver: createBetterSqliteDriver,
|
|
49
|
+
})(config);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates an Evolu relay server with a custom SQLite driver.
|
|
53
|
+
*
|
|
54
|
+
* Use this when you need to provide a different SQLite driver implementation
|
|
55
|
+
* (e.g., using alternative SQLite libraries).
|
|
56
|
+
*/
|
|
57
|
+
export const createNodeJsRelayWithSqliteDriver =
|
|
58
|
+
(deps: ConsoleDep & CreateSqliteDriverDep) =>
|
|
59
|
+
(config: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> =>
|
|
60
|
+
createNodeJsRelayWithDeps({
|
|
61
|
+
...deps,
|
|
50
62
|
random: createRandom(),
|
|
51
63
|
timingSafeEqual: createTimingSafeEqual(),
|
|
52
|
-
};
|
|
64
|
+
})(config);
|
|
65
|
+
|
|
66
|
+
const createNodeJsRelayWithDeps =
|
|
67
|
+
(deps: ConsoleDep & CreateSqliteDriverDep & RandomDep & TimingSafeEqualDep) =>
|
|
68
|
+
async ({
|
|
69
|
+
port = 443,
|
|
70
|
+
name = SimpleName.orThrow("evolu-relay"),
|
|
71
|
+
enableLogging = false,
|
|
72
|
+
authenticateOwner,
|
|
73
|
+
}: NodeJsRelayConfig): Promise<Result<Relay, SqliteError>> => {
|
|
74
|
+
const log = createRelayLogger(deps);
|
|
75
|
+
log.started(enableLogging, port);
|
|
76
|
+
|
|
77
|
+
const sqliteResult = await createSqlite(deps)(name);
|
|
78
|
+
if (!sqliteResult.ok) return sqliteResult;
|
|
79
|
+
const sqlite = sqliteResult.value;
|
|
80
|
+
|
|
81
|
+
const storageResult = createRelaySqliteStorage({ ...deps, sqlite })({
|
|
82
|
+
onStorageError: log.storageError,
|
|
83
|
+
});
|
|
53
84
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
onStorageError: (error) => {
|
|
57
|
-
deps.console.error("[relay]", "storage", error);
|
|
58
|
-
},
|
|
59
|
-
}),
|
|
60
|
-
);
|
|
85
|
+
if (!storageResult.ok) return storageResult;
|
|
86
|
+
const storage = storageResult.value;
|
|
61
87
|
|
|
88
|
+
const server = createServer();
|
|
62
89
|
const wss = new WebSocketServer({
|
|
63
|
-
maxPayload:
|
|
64
|
-
|
|
90
|
+
maxPayload: defaultProtocolMessageMaxSize,
|
|
91
|
+
noServer: true,
|
|
65
92
|
});
|
|
66
93
|
|
|
67
94
|
const ownerSocketsMap = createManyToManyMap<OwnerId, WebSocket>();
|
|
68
95
|
|
|
96
|
+
server.on("upgrade", (request, socket, head) => {
|
|
97
|
+
socket.on("error", log.upgradeSocketError);
|
|
98
|
+
|
|
99
|
+
const completeUpgrade = () => {
|
|
100
|
+
socket.removeListener("error", log.upgradeSocketError);
|
|
101
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
102
|
+
wss.emit("connection", ws, request);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (!authenticateOwner) {
|
|
107
|
+
completeUpgrade();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const ownerId = parseOwnerIdFromUrl(request.url);
|
|
112
|
+
if (!ownerId) {
|
|
113
|
+
log.invalidOrMissingOwnerIdInUrl(request.url);
|
|
114
|
+
socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
115
|
+
socket.destroy();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
authenticateOwner(ownerId)
|
|
120
|
+
.then((isAuthenticated) => {
|
|
121
|
+
if (!isAuthenticated) {
|
|
122
|
+
log.unauthorizedOwner(ownerId);
|
|
123
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
124
|
+
socket.destroy();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
completeUpgrade();
|
|
128
|
+
})
|
|
129
|
+
.catch((error: unknown) => {
|
|
130
|
+
log.authenticateOwnerError(error);
|
|
131
|
+
socket.write("HTTP/1.1 500 Internal Server Error\r\n\r\n");
|
|
132
|
+
socket.destroy();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
69
136
|
wss.on("connection", (ws) => {
|
|
70
|
-
|
|
71
|
-
clientCount: wss.clients.size,
|
|
72
|
-
});
|
|
137
|
+
log.connectionEstablished(wss.clients.size);
|
|
73
138
|
|
|
74
139
|
ws.on("error", (error) => {
|
|
75
|
-
|
|
76
|
-
deps.console.error(error);
|
|
140
|
+
log.connectionWebSocketError(error);
|
|
77
141
|
});
|
|
78
142
|
|
|
79
143
|
const options: ApplyProtocolMessageAsRelayOptions = {
|
|
80
144
|
subscribe: (ownerId) => {
|
|
81
145
|
ownerSocketsMap.add(ownerId, ws);
|
|
82
|
-
|
|
146
|
+
log.relayOptionSubscribe(
|
|
83
147
|
ownerId,
|
|
84
|
-
|
|
85
|
-
|
|
148
|
+
() => ownerSocketsMap.getValues(ownerId)?.size ?? 0,
|
|
149
|
+
);
|
|
86
150
|
},
|
|
87
151
|
|
|
88
152
|
unsubscribe: (ownerId) => {
|
|
89
153
|
ownerSocketsMap.remove(ownerId, ws);
|
|
90
|
-
|
|
154
|
+
log.relayOptionUnsubscribe(
|
|
91
155
|
ownerId,
|
|
92
|
-
|
|
93
|
-
|
|
156
|
+
() => ownerSocketsMap.getValues(ownerId)?.size ?? 0,
|
|
157
|
+
);
|
|
94
158
|
},
|
|
95
159
|
|
|
96
160
|
broadcast: (ownerId, message) => {
|
|
@@ -105,49 +169,36 @@ export const createNodeJsRelay =
|
|
|
105
169
|
}
|
|
106
170
|
}
|
|
107
171
|
|
|
108
|
-
|
|
109
|
-
ownerId,
|
|
110
|
-
broadcastCount,
|
|
111
|
-
totalSubscribers: sockets.size,
|
|
112
|
-
});
|
|
172
|
+
log.relayOptionBroadcast(ownerId, broadcastCount, sockets.size);
|
|
113
173
|
},
|
|
114
174
|
};
|
|
115
175
|
|
|
116
176
|
ws.on("message", (message) => {
|
|
117
177
|
if (!Uint8Array.is(message)) return;
|
|
118
|
-
|
|
119
|
-
deps.console.log("[relay]", "on message", {
|
|
120
|
-
messageSize: message.length,
|
|
121
|
-
});
|
|
178
|
+
log.messageLength(message.length);
|
|
122
179
|
|
|
123
180
|
applyProtocolMessageAsRelay({ storage })(message, options)
|
|
124
181
|
.then((response) => {
|
|
125
182
|
if (!response.ok) {
|
|
126
|
-
|
|
127
|
-
deps.console.error(response.error);
|
|
183
|
+
log.applyProtocolMessageAsRelayError(response.error);
|
|
128
184
|
return;
|
|
129
185
|
}
|
|
130
|
-
|
|
131
186
|
ws.send(response.value.message, { binary: true });
|
|
132
|
-
|
|
133
|
-
responseSize: response.value.message.length,
|
|
134
|
-
});
|
|
187
|
+
log.responseLength(response.value.message.length);
|
|
135
188
|
})
|
|
136
|
-
.catch(
|
|
137
|
-
deps.console.error("[relay]", "applyProtocolMessageAsRelay", error);
|
|
138
|
-
});
|
|
189
|
+
.catch(log.applyProtocolMessageAsRelayUnknownError);
|
|
139
190
|
});
|
|
140
191
|
|
|
141
192
|
ws.on("close", () => {
|
|
142
193
|
ownerSocketsMap.deleteValue(ws);
|
|
143
|
-
|
|
144
|
-
clientCount: wss.clients.size,
|
|
145
|
-
});
|
|
194
|
+
log.connectionClosed(wss.clients.size);
|
|
146
195
|
});
|
|
147
196
|
});
|
|
148
197
|
|
|
149
|
-
|
|
150
|
-
|
|
198
|
+
server.listen(port);
|
|
199
|
+
|
|
200
|
+
const dispose = () => {
|
|
201
|
+
log.shuttingDown();
|
|
151
202
|
|
|
152
203
|
wss.clients.forEach((client) => {
|
|
153
204
|
if (client.readyState === WebSocket.OPEN) {
|
|
@@ -156,18 +207,24 @@ export const createNodeJsRelay =
|
|
|
156
207
|
});
|
|
157
208
|
|
|
158
209
|
wss.close(() => {
|
|
159
|
-
|
|
210
|
+
log.webSocketServerDisposed();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
server.close(() => {
|
|
214
|
+
log.httpServerDisposed();
|
|
160
215
|
});
|
|
161
216
|
};
|
|
162
217
|
|
|
163
218
|
let isDisposed = false;
|
|
164
219
|
|
|
165
|
-
|
|
220
|
+
const relay: Relay = {
|
|
166
221
|
[Symbol.dispose]: () => {
|
|
167
222
|
if (isDisposed) return;
|
|
168
223
|
isDisposed = true;
|
|
169
224
|
sqlite[Symbol.dispose]();
|
|
170
|
-
|
|
225
|
+
dispose();
|
|
171
226
|
},
|
|
172
227
|
};
|
|
228
|
+
|
|
229
|
+
return ok(relay);
|
|
173
230
|
};
|