@modularizer/plat 0.7.0 → 0.9.0
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/README.md +75 -0
- package/dist/client-server-entry.d.ts +5 -0
- package/dist/client-server-entry.d.ts.map +1 -1
- package/dist/client-server-entry.js +5 -0
- package/dist/client-server-entry.js.map +1 -1
- package/dist/client-side-python/runtime.d.ts +1 -0
- package/dist/client-side-python/runtime.d.ts.map +1 -1
- package/dist/client-side-python/runtime.js +10 -1
- package/dist/client-side-python/runtime.js.map +1 -1
- package/dist/client-side-server/channel.d.ts +1 -1
- package/dist/client-side-server/channel.d.ts.map +1 -1
- package/dist/client-side-server/channel.js +113 -4
- package/dist/client-side-server/channel.js.map +1 -1
- package/dist/client-side-server/identity.d.ts +4 -2
- package/dist/client-side-server/identity.d.ts.map +1 -1
- package/dist/client-side-server/identity.js +30 -2
- package/dist/client-side-server/identity.js.map +1 -1
- package/dist/client-side-server/mqtt-webrtc.d.ts +84 -3
- package/dist/client-side-server/mqtt-webrtc.d.ts.map +1 -1
- package/dist/client-side-server/mqtt-webrtc.js +267 -10
- package/dist/client-side-server/mqtt-webrtc.js.map +1 -1
- package/dist/client-side-server/plat-bridge.d.ts +40 -0
- package/dist/client-side-server/plat-bridge.d.ts.map +1 -0
- package/dist/client-side-server/plat-bridge.js +876 -0
- package/dist/client-side-server/plat-bridge.js.map +1 -0
- package/dist/client-side-server/plat-fetch.d.ts +33 -0
- package/dist/client-side-server/plat-fetch.d.ts.map +1 -0
- package/dist/client-side-server/plat-fetch.js +199 -0
- package/dist/client-side-server/plat-fetch.js.map +1 -0
- package/dist/client-side-server/plat-service-worker-client.d.ts +30 -0
- package/dist/client-side-server/plat-service-worker-client.d.ts.map +1 -0
- package/dist/client-side-server/plat-service-worker-client.js +141 -0
- package/dist/client-side-server/plat-service-worker-client.js.map +1 -0
- package/dist/client-side-server/plat-service-worker.d.ts +35 -0
- package/dist/client-side-server/plat-service-worker.d.ts.map +1 -0
- package/dist/client-side-server/plat-service-worker.js +292 -0
- package/dist/client-side-server/plat-service-worker.js.map +1 -0
- package/dist/client-side-server/protocol.d.ts +68 -1
- package/dist/client-side-server/protocol.d.ts.map +1 -1
- package/dist/client-side-server/protocol.js +7 -0
- package/dist/client-side-server/protocol.js.map +1 -1
- package/dist/client-side-server/runtime.d.ts +16 -1
- package/dist/client-side-server/runtime.d.ts.map +1 -1
- package/dist/client-side-server/runtime.js +41 -13
- package/dist/client-side-server/runtime.js.map +1 -1
- package/dist/client-side-server/server.d.ts +34 -1
- package/dist/client-side-server/server.d.ts.map +1 -1
- package/dist/client-side-server/server.js +171 -7
- package/dist/client-side-server/server.js.map +1 -1
- package/dist/client-side-server/worker-pool.d.ts +20 -0
- package/dist/client-side-server/worker-pool.d.ts.map +1 -0
- package/dist/client-side-server/worker-pool.js +336 -0
- package/dist/client-side-server/worker-pool.js.map +1 -0
- package/dist/generated/python-browser-sources.js +4 -4
- package/dist/generated/python-browser-sources.js.map +1 -1
- package/dist/server/authority-server.d.ts +1 -1
- package/dist/server/authority-server.d.ts.map +1 -1
- package/dist/server/authority-server.js +27 -14
- package/dist/server/authority-server.js.map +1 -1
- package/dist/server/core.d.ts +8 -0
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +21 -0
- package/dist/server/core.js.map +1 -1
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +81 -2
- package/dist/server/server.js.map +1 -1
- package/dist/static/file-response.d.ts +42 -0
- package/dist/static/file-response.d.ts.map +1 -0
- package/dist/static/file-response.js +57 -0
- package/dist/static/file-response.js.map +1 -0
- package/dist/static/glob-match.d.ts +16 -0
- package/dist/static/glob-match.d.ts.map +1 -0
- package/dist/static/glob-match.js +48 -0
- package/dist/static/glob-match.js.map +1 -0
- package/dist/static/index.d.ts +9 -0
- package/dist/static/index.d.ts.map +1 -0
- package/dist/static/index.js +6 -0
- package/dist/static/index.js.map +1 -0
- package/dist/static/mime-types.d.ts +6 -0
- package/dist/static/mime-types.d.ts.map +1 -0
- package/dist/static/mime-types.js +74 -0
- package/dist/static/mime-types.js.map +1 -0
- package/dist/static/static-folder.d.ts +69 -0
- package/dist/static/static-folder.d.ts.map +1 -0
- package/dist/static/static-folder.js +206 -0
- package/dist/static/static-folder.js.map +1 -0
- package/dist/static/virtual-file-system.d.ts +45 -0
- package/dist/static/virtual-file-system.d.ts.map +1 -0
- package/dist/static/virtual-file-system.js +100 -0
- package/dist/static/virtual-file-system.js.map +1 -0
- package/package.json +5 -1
|
@@ -1,13 +1,70 @@
|
|
|
1
1
|
import { type IClientOptions } from 'mqtt';
|
|
2
2
|
import type { OpenAPIClientTransportPlugin } from '../client/transport-plugin';
|
|
3
3
|
import { type ClientSideServerChannel } from './channel';
|
|
4
|
-
import { type ClientSideServerAuthorityServer, type ClientSideServerExportedKeyPair, type ClientSideServerSignedAuthorityRecord, type ClientSideServerStorageLike, type ClientSideServerTrustedServerRecord } from './identity';
|
|
5
|
-
import { type ClientSideServerPeerMessage } from './protocol';
|
|
4
|
+
import { type ClientSideServerAuthorityServer, type ClientSideServerExportedKeyPair, type ClientSideServerPublicIdentity, type ClientSideServerSignedAuthorityRecord, type ClientSideServerStorageLike, type ClientSideServerTrustedServerRecord } from './identity';
|
|
5
|
+
import { type ClientSideServerInstanceInfo, type ClientSideServerPeerMessage } from './protocol';
|
|
6
6
|
import { type ClientSideServerAddress } from './signaling';
|
|
7
7
|
import type { PLATClientSideServer } from './server';
|
|
8
8
|
export declare const DEFAULT_CLIENT_SIDE_SERVER_MQTT_BROKER = "wss://broker.emqx.io:8084/mqtt";
|
|
9
9
|
export declare const DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC = "mrtchat/plat-css";
|
|
10
10
|
export declare const DEFAULT_CLIENT_SIDE_SERVER_ICE_SERVERS: RTCIceServer[];
|
|
11
|
+
export interface ClientSideServerWorkerInfo {
|
|
12
|
+
weight?: number;
|
|
13
|
+
suggestedWorkerCount?: number;
|
|
14
|
+
currentClients?: number;
|
|
15
|
+
acceptingNewClients?: boolean;
|
|
16
|
+
loadBalancing?: ClientSideServerLoadBalancingPreferences;
|
|
17
|
+
}
|
|
18
|
+
export interface ClientSideServerLoadBalancingPreferences {
|
|
19
|
+
strategy?: 'weighted-random' | 'round-robin' | 'least-connections' | 'none';
|
|
20
|
+
maxClientsPerInstance?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ClientSideServerWorkerPoolOptions {
|
|
23
|
+
maxActiveWorkers?: number;
|
|
24
|
+
maxStandbyWorkers?: number;
|
|
25
|
+
maxTotalConnections?: number;
|
|
26
|
+
rediscoveryThreshold?: number;
|
|
27
|
+
discoveryTimeoutMs?: number;
|
|
28
|
+
passiveDiscovery?: boolean;
|
|
29
|
+
rankCandidates?: (candidates: ClientSideServerDiscoveryCandidate[]) => ClientSideServerDiscoveryCandidate[];
|
|
30
|
+
assignWeights?: (workers: ClientSideServerWorkerState[]) => void;
|
|
31
|
+
routingStrategy?: 'weighted-random' | 'round-robin' | 'least-pending' | 'primary-with-fallback';
|
|
32
|
+
healthCheckIntervalMs?: number;
|
|
33
|
+
healthCheckTimeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface ClientSideServerDiscoveryCandidate {
|
|
36
|
+
instanceId: string;
|
|
37
|
+
serverName: string;
|
|
38
|
+
identity: ClientSideServerPublicIdentity;
|
|
39
|
+
authorityRecord?: ClientSideServerSignedAuthorityRecord;
|
|
40
|
+
mqttChallengeVerified: boolean;
|
|
41
|
+
workerInfo: ClientSideServerWorkerInfo;
|
|
42
|
+
instanceInfo?: ClientSideServerInstanceInfo;
|
|
43
|
+
discoveredAt: number;
|
|
44
|
+
alreadyConnected: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ClientSideServerDiscoveryResult {
|
|
47
|
+
serverName: string;
|
|
48
|
+
candidates: ClientSideServerDiscoveryCandidate[];
|
|
49
|
+
discoveredAt: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ClientSideServerWorkerState {
|
|
52
|
+
instanceId: string;
|
|
53
|
+
session: ClientSideServerPeerSession;
|
|
54
|
+
identity: ClientSideServerPublicIdentity;
|
|
55
|
+
authorityRecord?: ClientSideServerSignedAuthorityRecord;
|
|
56
|
+
status: 'connecting' | 'verifying' | 'active' | 'standby' | 'draining' | 'failed' | 'closed';
|
|
57
|
+
weight: number;
|
|
58
|
+
serverAdvertisedWeight: number;
|
|
59
|
+
authorityVerified: boolean;
|
|
60
|
+
pendingRequests: number;
|
|
61
|
+
totalRequests: number;
|
|
62
|
+
totalErrors: number;
|
|
63
|
+
connectedAt: number;
|
|
64
|
+
lastRequestAt?: number;
|
|
65
|
+
lastErrorAt?: number;
|
|
66
|
+
lastPongAt?: number;
|
|
67
|
+
}
|
|
11
68
|
export interface ClientSideServerMQTTWebRTCOptions {
|
|
12
69
|
mqttBroker?: string;
|
|
13
70
|
mqttTopic?: string;
|
|
@@ -17,10 +74,19 @@ export interface ClientSideServerMQTTWebRTCOptions {
|
|
|
17
74
|
announceIntervalMs?: number;
|
|
18
75
|
clientIdPrefix?: string;
|
|
19
76
|
identity?: ClientSideServerIdentityOptions;
|
|
77
|
+
workerPool?: ClientSideServerWorkerPoolOptions;
|
|
78
|
+
requirePrivateChallenge?: boolean;
|
|
20
79
|
}
|
|
21
80
|
export interface ClientSideServerMQTTWebRTCServerOptions extends ClientSideServerMQTTWebRTCOptions {
|
|
22
81
|
serverName: string;
|
|
23
82
|
server: PLATClientSideServer;
|
|
83
|
+
workerInfo?: ClientSideServerWorkerInfo;
|
|
84
|
+
/**
|
|
85
|
+
* Override or supplement the instance info from the PLATClientSideServer.
|
|
86
|
+
* If not provided, instance info is read from the server's own options.
|
|
87
|
+
* `openapiHash` and `serverStartedAt` are always auto-computed.
|
|
88
|
+
*/
|
|
89
|
+
instanceInfo?: ClientSideServerInstanceInfo;
|
|
24
90
|
}
|
|
25
91
|
export interface ClientSideServerIdentityOptions {
|
|
26
92
|
keyPair?: ClientSideServerExportedKeyPair;
|
|
@@ -43,6 +109,7 @@ export interface ClientSideServerPeerSession extends ClientSideServerChannel {
|
|
|
43
109
|
readonly connectionId: string;
|
|
44
110
|
readonly peerId: string;
|
|
45
111
|
readonly connectedAt: number;
|
|
112
|
+
readonly identity?: ClientSideServerPublicIdentity;
|
|
46
113
|
isOpen(): boolean;
|
|
47
114
|
sendPeer(event: string, data?: unknown): Promise<void>;
|
|
48
115
|
subscribePeer(listener: (message: ClientSideServerPeerMessage) => void | Promise<void>): () => void;
|
|
@@ -55,23 +122,37 @@ export interface ClientSideServerPeerPool {
|
|
|
55
122
|
export declare class ClientSideServerMQTTWebRTCServer {
|
|
56
123
|
private options;
|
|
57
124
|
private mqtt?;
|
|
58
|
-
|
|
125
|
+
readonly serverInstanceId: string;
|
|
59
126
|
private readonly unsubscribeByConnection;
|
|
60
127
|
private readonly peers;
|
|
61
128
|
private readonly pendingCandidates;
|
|
129
|
+
private readonly channels;
|
|
62
130
|
private announceTimer?;
|
|
63
131
|
private identityKeyPair?;
|
|
64
132
|
private publicIdentity?;
|
|
133
|
+
private clientCount;
|
|
134
|
+
private resolvedInstanceInfo?;
|
|
65
135
|
constructor(options: ClientSideServerMQTTWebRTCServerOptions);
|
|
66
136
|
get connectionUrl(): string;
|
|
67
137
|
start(): Promise<void>;
|
|
68
138
|
stop(): Promise<void>;
|
|
69
139
|
private announce;
|
|
70
140
|
private onMessage;
|
|
141
|
+
private respondToDiscover;
|
|
142
|
+
private buildResolvedInstanceInfo;
|
|
143
|
+
private buildWorkerInfo;
|
|
144
|
+
private handleControlMessage;
|
|
145
|
+
drain(): Promise<void>;
|
|
71
146
|
private acceptOffer;
|
|
72
147
|
private ensureIdentity;
|
|
73
148
|
}
|
|
74
149
|
export declare function createClientSideServerMQTTWebRTCTransportPlugin(options?: ClientSideServerMQTTWebRTCOptions): OpenAPIClientTransportPlugin;
|
|
75
150
|
export declare function createClientSideServerMQTTWebRTCPeerPool(options?: ClientSideServerMQTTWebRTCOptions): ClientSideServerPeerPool;
|
|
151
|
+
export declare function discoverClientSideServers(serverName: string, options?: ClientSideServerMQTTWebRTCOptions): Promise<ClientSideServerDiscoveryResult>;
|
|
152
|
+
export declare function connectFirstDiscovery(address: ClientSideServerAddress, options: ClientSideServerMQTTWebRTCOptions): Promise<{
|
|
153
|
+
primary: ClientSideServerPeerSession;
|
|
154
|
+
discovery: Promise<ClientSideServerDiscoveryResult>;
|
|
155
|
+
}>;
|
|
156
|
+
export declare function createClientSideServerMQTTWebRTCPeerSession(address: ClientSideServerAddress, options: ClientSideServerMQTTWebRTCOptions, targetInstanceId?: string): Promise<ClientSideServerPeerSession>;
|
|
76
157
|
export declare function createClientSideServerMQTTWebRTCServer(options: ClientSideServerMQTTWebRTCServerOptions): ClientSideServerMQTTWebRTCServer;
|
|
77
158
|
//# sourceMappingURL=mqtt-webrtc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt-webrtc.d.ts","sourceRoot":"","sources":["../../src/client-side-server/mqtt-webrtc.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,KAAK,cAAc,EAAmB,MAAM,MAAM,CAAA;AAEjE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,EAA+B,KAAK,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,EAGL,KAAK,+BAA+B,EACpC,KAAK,+BAA+B,
|
|
1
|
+
{"version":3,"file":"mqtt-webrtc.d.ts","sourceRoot":"","sources":["../../src/client-side-server/mqtt-webrtc.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,9 +22,12 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
22
22
|
unsubscribeByConnection = new Map();
|
|
23
23
|
peers = new Map();
|
|
24
24
|
pendingCandidates = new Map();
|
|
25
|
+
channels = new Map();
|
|
25
26
|
announceTimer;
|
|
26
27
|
identityKeyPair;
|
|
27
28
|
publicIdentity;
|
|
29
|
+
clientCount = 0;
|
|
30
|
+
resolvedInstanceInfo;
|
|
28
31
|
constructor(options) {
|
|
29
32
|
this.options = options;
|
|
30
33
|
this.serverInstanceId = `${options.serverName}:${randomId('server')}`;
|
|
@@ -41,6 +44,8 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
41
44
|
void this.onMessage(payload);
|
|
42
45
|
});
|
|
43
46
|
await subscribe(this.mqtt, this.options.mqttTopic ?? DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC);
|
|
47
|
+
// Compute and cache instance info (includes openapi hash) before first announce
|
|
48
|
+
this.resolvedInstanceInfo = await this.buildResolvedInstanceInfo();
|
|
44
49
|
await this.announce();
|
|
45
50
|
const intervalMs = this.options.announceIntervalMs ?? 30_000;
|
|
46
51
|
this.announceTimer = setInterval(() => {
|
|
@@ -75,6 +80,7 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
75
80
|
serverName: this.options.serverName,
|
|
76
81
|
identity: this.publicIdentity,
|
|
77
82
|
authorityRecord: this.options.identity?.authorityRecord,
|
|
83
|
+
instanceInfo: this.resolvedInstanceInfo,
|
|
78
84
|
at: Date.now(),
|
|
79
85
|
});
|
|
80
86
|
}
|
|
@@ -84,7 +90,14 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
84
90
|
return;
|
|
85
91
|
if (message.targetId && message.targetId !== this.options.serverName && message.targetId !== this.serverInstanceId)
|
|
86
92
|
return;
|
|
87
|
-
if (message.kind === '
|
|
93
|
+
if (message.kind === 'discover' && message.targetId === this.options.serverName && message.challengeNonce) {
|
|
94
|
+
await this.respondToDiscover(message);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (message.kind === 'offer'
|
|
98
|
+
&& (message.targetId === this.options.serverName || message.targetId === this.serverInstanceId)
|
|
99
|
+
&& message.connectionId
|
|
100
|
+
&& message.description) {
|
|
88
101
|
await this.acceptOffer(message);
|
|
89
102
|
return;
|
|
90
103
|
}
|
|
@@ -103,6 +116,100 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
103
116
|
}
|
|
104
117
|
}
|
|
105
118
|
}
|
|
119
|
+
async respondToDiscover(message) {
|
|
120
|
+
if (!this.mqtt || !message.challengeNonce)
|
|
121
|
+
return;
|
|
122
|
+
await this.ensureIdentity();
|
|
123
|
+
const challengeString = buildClientSideServerIdentityChallenge({
|
|
124
|
+
serverName: this.options.serverName,
|
|
125
|
+
connectionId: this.serverInstanceId,
|
|
126
|
+
challengeNonce: message.challengeNonce,
|
|
127
|
+
});
|
|
128
|
+
const challengeSignature = await signClientSideServerChallenge(this.identityKeyPair, challengeString);
|
|
129
|
+
await publish(this.mqtt, this.options.mqttTopic ?? DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC, {
|
|
130
|
+
protocol: 'plat-css-v1',
|
|
131
|
+
kind: 'announce',
|
|
132
|
+
senderId: this.serverInstanceId,
|
|
133
|
+
serverName: this.options.serverName,
|
|
134
|
+
identity: this.publicIdentity,
|
|
135
|
+
authorityRecord: this.options.identity?.authorityRecord,
|
|
136
|
+
challengeNonce: message.challengeNonce,
|
|
137
|
+
challengeSignature,
|
|
138
|
+
workerInfo: this.buildWorkerInfo(),
|
|
139
|
+
instanceInfo: this.resolvedInstanceInfo,
|
|
140
|
+
at: Date.now(),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async buildResolvedInstanceInfo() {
|
|
144
|
+
// Merge: options.instanceInfo (user override) > server.getServerInfo() (auto-computed)
|
|
145
|
+
const serverInfo = await this.options.server.getServerInfo();
|
|
146
|
+
return {
|
|
147
|
+
...serverInfo,
|
|
148
|
+
...(this.options.instanceInfo ?? {}),
|
|
149
|
+
// Always override openapiHash and serverStartedAt with freshly computed values
|
|
150
|
+
openapiHash: this.options.instanceInfo?.openapiHash ?? serverInfo.openapiHash,
|
|
151
|
+
serverStartedAt: Date.now(),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
buildWorkerInfo() {
|
|
155
|
+
const base = this.options.workerInfo;
|
|
156
|
+
return {
|
|
157
|
+
weight: base?.weight,
|
|
158
|
+
suggestedWorkerCount: base?.suggestedWorkerCount,
|
|
159
|
+
currentClients: this.clientCount,
|
|
160
|
+
acceptingNewClients: base?.acceptingNewClients,
|
|
161
|
+
loadBalancing: base?.loadBalancing,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async handleControlMessage(msg, channel, connectionId) {
|
|
165
|
+
if (!('platcss' in msg))
|
|
166
|
+
return;
|
|
167
|
+
const control = msg;
|
|
168
|
+
if (control.platcss === 'ping') {
|
|
169
|
+
await channel.send({ platcss: 'pong', ts: control.ts });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (control.platcss === 'private-challenge') {
|
|
173
|
+
const req = control;
|
|
174
|
+
if (req.challengeNonce.includes('-mqtt')) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
await this.ensureIdentity();
|
|
178
|
+
const challengeString = buildClientSideServerIdentityChallenge({
|
|
179
|
+
serverName: this.options.serverName,
|
|
180
|
+
connectionId,
|
|
181
|
+
challengeNonce: req.challengeNonce,
|
|
182
|
+
});
|
|
183
|
+
const sig = await signClientSideServerChallenge(this.identityKeyPair, challengeString);
|
|
184
|
+
await channel.send({
|
|
185
|
+
platcss: 'private-challenge-response',
|
|
186
|
+
challengeNonce: req.challengeNonce,
|
|
187
|
+
challengeSignature: sig,
|
|
188
|
+
identity: this.publicIdentity,
|
|
189
|
+
authorityRecord: this.options.identity?.authorityRecord,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async drain() {
|
|
194
|
+
if (this.options.workerInfo) {
|
|
195
|
+
this.options.workerInfo.acceptingNewClients = false;
|
|
196
|
+
}
|
|
197
|
+
if (this.mqtt) {
|
|
198
|
+
await publish(this.mqtt, this.options.mqttTopic ?? DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC, {
|
|
199
|
+
protocol: 'plat-css-v1',
|
|
200
|
+
kind: 'announce',
|
|
201
|
+
senderId: this.serverInstanceId,
|
|
202
|
+
serverName: this.options.serverName,
|
|
203
|
+
identity: this.publicIdentity,
|
|
204
|
+
workerInfo: { ...this.buildWorkerInfo(), acceptingNewClients: false },
|
|
205
|
+
instanceInfo: this.resolvedInstanceInfo,
|
|
206
|
+
at: Date.now(),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
for (const channel of this.channels.values()) {
|
|
210
|
+
await channel.send({ platcss: 'drain' });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
106
213
|
async acceptOffer(message) {
|
|
107
214
|
if (!this.mqtt || !message.connectionId || !message.description)
|
|
108
215
|
return;
|
|
@@ -133,12 +240,23 @@ export class ClientSideServerMQTTWebRTCServer {
|
|
|
133
240
|
}
|
|
134
241
|
};
|
|
135
242
|
peer.ondatachannel = (event) => {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
243
|
+
const channel = createRTCDataChannelAdapter(event.channel);
|
|
244
|
+
const connId = message.connectionId;
|
|
245
|
+
const controlUnsubscribe = channel.subscribe(async (msg) => {
|
|
246
|
+
await this.handleControlMessage(msg, channel, connId);
|
|
247
|
+
});
|
|
248
|
+
const serveUnsubscribe = this.options.server.serveChannel(channel);
|
|
249
|
+
this.channels.set(connId, channel);
|
|
250
|
+
this.clientCount++;
|
|
251
|
+
const cleanup = () => {
|
|
252
|
+
controlUnsubscribe();
|
|
253
|
+
serveUnsubscribe();
|
|
254
|
+
this.channels.delete(connId);
|
|
255
|
+
this.clientCount--;
|
|
256
|
+
this.unsubscribeByConnection.delete(connId);
|
|
257
|
+
};
|
|
258
|
+
this.unsubscribeByConnection.set(connId, cleanup);
|
|
259
|
+
event.channel.addEventListener('close', cleanup, { once: true });
|
|
142
260
|
};
|
|
143
261
|
await peer.setRemoteDescription(new RTCSessionDescription(message.description));
|
|
144
262
|
for (const candidate of this.pendingCandidates.get(message.connectionId) ?? []) {
|
|
@@ -188,6 +306,26 @@ export function createClientSideServerMQTTWebRTCTransportPlugin(options = {}) {
|
|
|
188
306
|
return createClientSideServerMQTTWebRTCTransportPluginInternal(options);
|
|
189
307
|
}
|
|
190
308
|
function createClientSideServerMQTTWebRTCTransportPluginInternal(options) {
|
|
309
|
+
const useMultiWorker = options.workerPool
|
|
310
|
+
&& ((options.workerPool.maxActiveWorkers ?? 1) > 1 || (options.workerPool.maxStandbyWorkers ?? 0) > 0);
|
|
311
|
+
if (useMultiWorker) {
|
|
312
|
+
let multiPoolPromise;
|
|
313
|
+
const getPool = () => {
|
|
314
|
+
multiPoolPromise ??= import('./worker-pool').then((mod) => mod.createClientSideServerMultiWorkerPool(options));
|
|
315
|
+
return multiPoolPromise;
|
|
316
|
+
};
|
|
317
|
+
return createClientSideServerTransportPlugin({
|
|
318
|
+
connect: async ({ address }) => {
|
|
319
|
+
const pool = await getPool();
|
|
320
|
+
const session = await pool.connect(address);
|
|
321
|
+
return {
|
|
322
|
+
send: (message) => session.send(message),
|
|
323
|
+
subscribe: (listener) => session.subscribe(listener),
|
|
324
|
+
close: () => undefined,
|
|
325
|
+
};
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
}
|
|
191
329
|
const pool = createClientSideServerMQTTWebRTCPeerPool(options);
|
|
192
330
|
return createClientSideServerTransportPlugin({
|
|
193
331
|
connect: async ({ address }) => {
|
|
@@ -250,7 +388,118 @@ function createClientSideServerMQTTWebRTCPeerPoolInternal(options) {
|
|
|
250
388
|
},
|
|
251
389
|
};
|
|
252
390
|
}
|
|
253
|
-
async function
|
|
391
|
+
export async function discoverClientSideServers(serverName, options = {}) {
|
|
392
|
+
const mqttClient = await connectToBroker(options);
|
|
393
|
+
const topic = options.mqttTopic ?? DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC;
|
|
394
|
+
const peerId = `${options.clientIdPrefix ?? 'client'}:${randomId('discover')}`;
|
|
395
|
+
const challengeNonce = randomId('challenge') + '-mqtt';
|
|
396
|
+
const timeoutMs = options.workerPool?.discoveryTimeoutMs ?? 3000;
|
|
397
|
+
const candidates = [];
|
|
398
|
+
await subscribe(mqttClient, topic);
|
|
399
|
+
const onMessage = async (_topic, payload) => {
|
|
400
|
+
const message = parseSignalingMessage(payload);
|
|
401
|
+
if (!message || message.senderId === peerId)
|
|
402
|
+
return;
|
|
403
|
+
if (message.kind !== 'announce')
|
|
404
|
+
return;
|
|
405
|
+
if (message.serverName !== serverName)
|
|
406
|
+
return;
|
|
407
|
+
if (message.challengeNonce && message.challengeNonce !== challengeNonce)
|
|
408
|
+
return;
|
|
409
|
+
let mqttChallengeVerified = false;
|
|
410
|
+
if (message.challengeNonce === challengeNonce && message.challengeSignature && message.identity) {
|
|
411
|
+
const challengeString = buildClientSideServerIdentityChallenge({
|
|
412
|
+
serverName,
|
|
413
|
+
connectionId: message.senderId,
|
|
414
|
+
challengeNonce,
|
|
415
|
+
});
|
|
416
|
+
mqttChallengeVerified = await verifyClientSideServerChallenge(message.identity.publicKeyJwk, challengeString, message.challengeSignature);
|
|
417
|
+
}
|
|
418
|
+
if (message.authorityRecord && options.identity?.authority?.publicKeyJwk) {
|
|
419
|
+
const authorityOk = await verifySignedClientSideServerAuthorityRecord(message.authorityRecord, options.identity.authority.publicKeyJwk);
|
|
420
|
+
if (!authorityOk)
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const existing = candidates.find((c) => c.instanceId === message.senderId);
|
|
424
|
+
if (existing)
|
|
425
|
+
return;
|
|
426
|
+
candidates.push({
|
|
427
|
+
instanceId: message.senderId,
|
|
428
|
+
serverName,
|
|
429
|
+
identity: message.identity,
|
|
430
|
+
authorityRecord: message.authorityRecord,
|
|
431
|
+
mqttChallengeVerified,
|
|
432
|
+
workerInfo: {
|
|
433
|
+
weight: message.workerInfo?.weight ?? 3,
|
|
434
|
+
suggestedWorkerCount: message.workerInfo?.suggestedWorkerCount,
|
|
435
|
+
currentClients: message.workerInfo?.currentClients ?? 0,
|
|
436
|
+
acceptingNewClients: message.workerInfo?.acceptingNewClients ?? true,
|
|
437
|
+
loadBalancing: message.workerInfo?.loadBalancing,
|
|
438
|
+
},
|
|
439
|
+
instanceInfo: message.instanceInfo,
|
|
440
|
+
discoveredAt: Date.now(),
|
|
441
|
+
alreadyConnected: false,
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
mqttClient.on('message', onMessage);
|
|
445
|
+
await publish(mqttClient, topic, {
|
|
446
|
+
protocol: 'plat-css-v1',
|
|
447
|
+
kind: 'discover',
|
|
448
|
+
senderId: peerId,
|
|
449
|
+
targetId: serverName,
|
|
450
|
+
challengeNonce,
|
|
451
|
+
at: Date.now(),
|
|
452
|
+
});
|
|
453
|
+
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
454
|
+
mqttClient.off('message', onMessage);
|
|
455
|
+
await endClient(mqttClient);
|
|
456
|
+
return {
|
|
457
|
+
serverName,
|
|
458
|
+
candidates: defaultRankCandidates(candidates, options),
|
|
459
|
+
discoveredAt: Date.now(),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function defaultRankCandidates(candidates, options) {
|
|
463
|
+
if (options.workerPool?.rankCandidates) {
|
|
464
|
+
return options.workerPool.rankCandidates(candidates);
|
|
465
|
+
}
|
|
466
|
+
const accepting = candidates.filter((c) => c.workerInfo.acceptingNewClients !== false);
|
|
467
|
+
const pool = accepting.length > 0 ? accepting : candidates;
|
|
468
|
+
return pool.sort((a, b) => {
|
|
469
|
+
const aAuth = a.authorityRecord ? 1 : 0;
|
|
470
|
+
const bAuth = b.authorityRecord ? 1 : 0;
|
|
471
|
+
if (bAuth !== aAuth)
|
|
472
|
+
return bAuth - aAuth;
|
|
473
|
+
const aMqtt = a.mqttChallengeVerified ? 1 : 0;
|
|
474
|
+
const bMqtt = b.mqttChallengeVerified ? 1 : 0;
|
|
475
|
+
if (bMqtt !== aMqtt)
|
|
476
|
+
return bMqtt - aMqtt;
|
|
477
|
+
const aWeight = a.workerInfo.weight ?? 3;
|
|
478
|
+
const bWeight = b.workerInfo.weight ?? 3;
|
|
479
|
+
if (bWeight !== aWeight)
|
|
480
|
+
return bWeight - aWeight;
|
|
481
|
+
const aClients = a.workerInfo.currentClients ?? 0;
|
|
482
|
+
const bClients = b.workerInfo.currentClients ?? 0;
|
|
483
|
+
return aClients - bClients;
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
export async function connectFirstDiscovery(address, options) {
|
|
487
|
+
const primaryPromise = createClientSideServerMQTTWebRTCPeerSession(address, options);
|
|
488
|
+
const discovery = discoverClientSideServers(address.serverName, options).then((result) => {
|
|
489
|
+
return primaryPromise.then((primary) => {
|
|
490
|
+
for (const candidate of result.candidates) {
|
|
491
|
+
if (candidate.identity && primary.identity
|
|
492
|
+
&& clientSideServerPublicKeysEqual(candidate.identity.publicKeyJwk, primary.identity.publicKeyJwk)) {
|
|
493
|
+
candidate.alreadyConnected = true;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
}).catch(() => result);
|
|
498
|
+
});
|
|
499
|
+
const primary = await primaryPromise;
|
|
500
|
+
return { primary, discovery };
|
|
501
|
+
}
|
|
502
|
+
export async function createClientSideServerMQTTWebRTCPeerSession(address, options, targetInstanceId) {
|
|
254
503
|
const webrtc = await resolveClientWebRTCImplementation();
|
|
255
504
|
const mqtt = await connectToBroker(options);
|
|
256
505
|
const topic = options.mqttTopic ?? DEFAULT_CLIENT_SIDE_SERVER_MQTT_TOPIC;
|
|
@@ -267,6 +516,8 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
267
516
|
const pendingCandidates = [];
|
|
268
517
|
const expectedIdentity = await resolveExpectedServerIdentity(address.serverName, options.identity);
|
|
269
518
|
let open = true;
|
|
519
|
+
let answerApplied = false;
|
|
520
|
+
let serverIdentity;
|
|
270
521
|
await subscribe(mqtt, topic);
|
|
271
522
|
const onMessage = async (_topic, payload) => {
|
|
272
523
|
const message = parseSignalingMessage(payload);
|
|
@@ -274,6 +525,9 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
274
525
|
return;
|
|
275
526
|
}
|
|
276
527
|
if (message.kind === 'answer' && message.description) {
|
|
528
|
+
if (answerApplied)
|
|
529
|
+
return;
|
|
530
|
+
answerApplied = true;
|
|
277
531
|
await verifyServerIdentityForAnswer({
|
|
278
532
|
serverName: address.serverName,
|
|
279
533
|
connectionId,
|
|
@@ -282,6 +536,7 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
282
536
|
optionsIdentity: options.identity,
|
|
283
537
|
expectedIdentity,
|
|
284
538
|
});
|
|
539
|
+
serverIdentity = message.identity;
|
|
285
540
|
await peer.setRemoteDescription(webrtc.createSessionDescription(message.description));
|
|
286
541
|
if (!expectedIdentity && message.authorityRecord && options.identity?.authority?.publicKeyJwk) {
|
|
287
542
|
const trusted = await trustClientSideServerFromAuthorityRecord(message.authorityRecord, options.identity.authority.publicKeyJwk, {
|
|
@@ -317,6 +572,7 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
317
572
|
};
|
|
318
573
|
mqtt.on('message', onMessage);
|
|
319
574
|
cleanupCallbacks.push(() => mqtt.off('message', onMessage));
|
|
575
|
+
const offerTarget = targetInstanceId ?? address.serverName;
|
|
320
576
|
peer.onicecandidate = (event) => {
|
|
321
577
|
if (!event.candidate)
|
|
322
578
|
return;
|
|
@@ -324,7 +580,7 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
324
580
|
protocol: 'plat-css-v1',
|
|
325
581
|
kind: 'ice',
|
|
326
582
|
senderId: peerId,
|
|
327
|
-
targetId:
|
|
583
|
+
targetId: offerTarget,
|
|
328
584
|
connectionId,
|
|
329
585
|
candidate: webrtc.serializeIceCandidate(event.candidate),
|
|
330
586
|
at: Date.now(),
|
|
@@ -350,7 +606,7 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
350
606
|
protocol: 'plat-css-v1',
|
|
351
607
|
kind: 'offer',
|
|
352
608
|
senderId: peerId,
|
|
353
|
-
targetId:
|
|
609
|
+
targetId: offerTarget,
|
|
354
610
|
serverName: address.serverName,
|
|
355
611
|
connectionId,
|
|
356
612
|
description: offer,
|
|
@@ -370,6 +626,7 @@ async function createClientSideServerMQTTWebRTCPeerSession(address, options) {
|
|
|
370
626
|
connectionId,
|
|
371
627
|
peerId,
|
|
372
628
|
connectedAt: Date.now(),
|
|
629
|
+
identity: serverIdentity,
|
|
373
630
|
isOpen: () => open && dataChannel.readyState === 'open',
|
|
374
631
|
async sendPeer(event, data) {
|
|
375
632
|
await channel.send({
|