@api.global/typedsocket 4.0.0 → 4.1.2
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/typedsocket.classes.typedsocket.d.ts +114 -31
- package/dist_ts/typedsocket.classes.typedsocket.js +372 -191
- package/dist_ts/typedsocket.plugins.d.ts +3 -2
- package/dist_ts/typedsocket.plugins.js +4 -3
- package/npmextra.json +13 -7
- package/package.json +14 -17
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/typedsocket.classes.typedsocket.ts +491 -279
- package/ts/typedsocket.plugins.ts +4 -3
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as plugins from './typedsocket.plugins.js';
|
|
2
|
-
const
|
|
3
|
-
const publicRolePass = 'publicRolePass';
|
|
2
|
+
const TAG_PREFIX = '__typedsocket_tag__';
|
|
4
3
|
/**
|
|
5
4
|
* Creates a wrapper around IWebSocketPeer for tag compatibility
|
|
6
5
|
*/
|
|
7
6
|
function wrapSmartServePeer(peer) {
|
|
8
|
-
const TAG_PREFIX = '__typedsocket_tag__';
|
|
9
7
|
return {
|
|
10
8
|
peer,
|
|
11
9
|
async getTagById(tagId) {
|
|
@@ -18,72 +16,52 @@ function wrapSmartServePeer(peer) {
|
|
|
18
16
|
};
|
|
19
17
|
}
|
|
20
18
|
export class TypedSocket {
|
|
21
|
-
//
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// STATIC METHODS
|
|
21
|
+
// ============================================================================
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Creates a TypedSocket client using native WebSocket.
|
|
24
|
+
* Works in both browser and Node.js environments.
|
|
25
|
+
*
|
|
26
|
+
* @param typedrouterArg - TypedRouter for handling server-initiated requests
|
|
27
|
+
* @param serverUrlArg - Server URL (e.g., 'http://localhost:3000' or 'wss://example.com')
|
|
28
|
+
* @param options - Connection options
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const typedRouter = new TypedRouter();
|
|
33
|
+
* const client = await TypedSocket.createClient(
|
|
34
|
+
* typedRouter,
|
|
35
|
+
* 'http://localhost:3000',
|
|
36
|
+
* { autoReconnect: true }
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
25
39
|
*/
|
|
26
|
-
static async
|
|
27
|
-
const
|
|
28
|
-
alias: 'typedsocketServer',
|
|
29
|
-
port: 3000,
|
|
30
|
-
});
|
|
31
|
-
smartsocketServer.socketFunctions.add(new plugins.smartsocket.SocketFunction({
|
|
32
|
-
funcName: 'processMessage',
|
|
33
|
-
funcDef: async (dataArg, socketConnectionArg) => {
|
|
34
|
-
return typedrouterArg.routeAndAddResponse(dataArg);
|
|
35
|
-
},
|
|
36
|
-
}));
|
|
37
|
-
const typedsocket = new TypedSocket('server', typedrouterArg, async (dataArg, targetConnectionArg) => {
|
|
38
|
-
if (!targetConnectionArg) {
|
|
39
|
-
if ((smartsocketServer.socketConnections.getArray().length = 1)) {
|
|
40
|
-
console.log('Since no targetConnection was supplied and there is only one active one present, choosing that one automatically');
|
|
41
|
-
targetConnectionArg = smartsocketServer.socketConnections.getArray()[0];
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
throw new Error('you need to specify the wanted targetConnection. Currently no target is selectable automatically.');
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const response = (await smartsocketServer.clientCall('processMessage', dataArg, targetConnectionArg));
|
|
48
|
-
return response;
|
|
49
|
-
}, smartsocketServer);
|
|
50
|
-
await smartsocketServer.start();
|
|
51
|
-
return typedsocket;
|
|
52
|
-
}
|
|
53
|
-
static async createClient(typedrouterArg, serverUrlArg, aliasArg = 'clientArg') {
|
|
54
|
-
const domain = new plugins.smartstring.Domain(serverUrlArg);
|
|
55
|
-
const socketOptions = {
|
|
56
|
-
alias: aliasArg,
|
|
57
|
-
port: domain.port || 3000,
|
|
58
|
-
url: `${domain.nodeParsedUrl.protocol}//${domain.nodeParsedUrl.hostname}`,
|
|
40
|
+
static async createClient(typedrouterArg, serverUrlArg, options = {}) {
|
|
41
|
+
const defaultOptions = {
|
|
59
42
|
autoReconnect: true,
|
|
43
|
+
maxRetries: 100,
|
|
44
|
+
initialBackoffMs: 1000,
|
|
45
|
+
maxBackoffMs: 60000,
|
|
60
46
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
}));
|
|
70
|
-
const typedsocket = new TypedSocket('client', typedrouterArg, async (dataArg) => {
|
|
71
|
-
const response = smartsocketClient.serverCall('processMessage', dataArg);
|
|
72
|
-
return response;
|
|
73
|
-
}, smartsocketClient);
|
|
74
|
-
console.log(`typedsocket triggering smartsocket to connect...`);
|
|
75
|
-
const before = Date.now();
|
|
76
|
-
await smartsocketClient.connect();
|
|
77
|
-
console.log(`typedsocket triggered smartsocket connected in ${Date.now() - before}ms!!!`);
|
|
78
|
-
return typedsocket;
|
|
47
|
+
const opts = { ...defaultOptions, ...options };
|
|
48
|
+
const typedSocket = new TypedSocket('client', typedrouterArg);
|
|
49
|
+
typedSocket.clientOptions = opts;
|
|
50
|
+
typedSocket.serverUrl = serverUrlArg;
|
|
51
|
+
typedSocket.currentBackoff = opts.initialBackoffMs;
|
|
52
|
+
await typedSocket.connect();
|
|
53
|
+
return typedSocket;
|
|
79
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns the current window location origin URL.
|
|
57
|
+
* Useful in browser environments for connecting to the same origin.
|
|
58
|
+
*/
|
|
80
59
|
static { this.useWindowLocationOriginUrl = () => {
|
|
81
|
-
|
|
82
|
-
return windowLocationResult;
|
|
60
|
+
return plugins.smarturl.Smarturl.createFromUrl(globalThis.location.origin).toString();
|
|
83
61
|
}; }
|
|
84
62
|
/**
|
|
85
63
|
* Creates a TypedSocket server from an existing SmartServe instance.
|
|
86
|
-
*
|
|
64
|
+
* This is the only way to create a server-side TypedSocket.
|
|
87
65
|
*
|
|
88
66
|
* @param smartServeArg - SmartServe instance with typedRouter configured in websocket options
|
|
89
67
|
* @param typedRouterArg - TypedRouter for handling requests (must match SmartServe's typedRouter)
|
|
@@ -104,179 +82,382 @@ export class TypedSocket {
|
|
|
104
82
|
*/
|
|
105
83
|
static fromSmartServe(smartServeArg, typedRouterArg) {
|
|
106
84
|
const connectionWrappers = new Map();
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
// Register built-in tag handlers
|
|
86
|
+
TypedSocket.registerTagHandlers(typedRouterArg);
|
|
87
|
+
const typedSocket = new TypedSocket('server', typedRouterArg);
|
|
88
|
+
typedSocket.smartServeRef = smartServeArg;
|
|
89
|
+
typedSocket.smartServeConnectionWrappers = connectionWrappers;
|
|
90
|
+
return typedSocket;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Registers built-in TypedHandlers for tag management
|
|
94
|
+
*/
|
|
95
|
+
static registerTagHandlers(typedRouter) {
|
|
96
|
+
// Set tag handler
|
|
97
|
+
typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_setTag', async (data, meta) => {
|
|
98
|
+
const peer = meta?.localData?.peer;
|
|
99
|
+
if (!peer) {
|
|
100
|
+
console.warn('setTag: No peer found in request context');
|
|
101
|
+
return { success: false };
|
|
102
|
+
}
|
|
103
|
+
peer.tags.add(data.name);
|
|
104
|
+
peer.data.set(`${TAG_PREFIX}${data.name}`, data.payload);
|
|
105
|
+
return { success: true };
|
|
106
|
+
}));
|
|
107
|
+
// Remove tag handler
|
|
108
|
+
typedRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('__typedsocket_removeTag', async (data, meta) => {
|
|
109
|
+
const peer = meta?.localData?.peer;
|
|
110
|
+
if (!peer) {
|
|
111
|
+
console.warn('removeTag: No peer found in request context');
|
|
112
|
+
return { success: false };
|
|
113
|
+
}
|
|
114
|
+
peer.tags.delete(data.name);
|
|
115
|
+
peer.data.delete(`${TAG_PREFIX}${data.name}`);
|
|
116
|
+
return { success: true };
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// CONSTRUCTOR
|
|
121
|
+
// ============================================================================
|
|
122
|
+
constructor(sideArg, typedrouterArg) {
|
|
123
|
+
// Connection status observable
|
|
124
|
+
this.statusSubject = new plugins.smartrx.rxjs.Subject();
|
|
125
|
+
this.connectionStatus = 'new';
|
|
126
|
+
// Client-specific properties
|
|
127
|
+
this.websocket = null;
|
|
128
|
+
this.clientOptions = null;
|
|
129
|
+
this.serverUrl = '';
|
|
130
|
+
this.retryCount = 0;
|
|
131
|
+
this.currentBackoff = 1000;
|
|
132
|
+
this.pendingRequests = new Map();
|
|
133
|
+
// Server-specific properties (SmartServe mode)
|
|
134
|
+
this.smartServeRef = null;
|
|
135
|
+
this.smartServeConnectionWrappers = new Map();
|
|
136
|
+
this.side = sideArg;
|
|
137
|
+
this.typedrouter = typedrouterArg;
|
|
138
|
+
}
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// CLIENT METHODS
|
|
141
|
+
// ============================================================================
|
|
142
|
+
/**
|
|
143
|
+
* Connects the client to the server using native WebSocket
|
|
144
|
+
*/
|
|
145
|
+
async connect() {
|
|
146
|
+
const done = plugins.smartpromise.defer();
|
|
147
|
+
this.updateStatus('connecting');
|
|
148
|
+
// Convert HTTP URL to WebSocket URL
|
|
149
|
+
const wsUrl = this.toWebSocketUrl(this.serverUrl);
|
|
150
|
+
console.log(`TypedSocket connecting to ${wsUrl}...`);
|
|
151
|
+
this.websocket = new WebSocket(wsUrl);
|
|
152
|
+
const connectionTimeout = setTimeout(() => {
|
|
153
|
+
if (this.connectionStatus !== 'connected') {
|
|
154
|
+
console.warn('TypedSocket connection timeout');
|
|
155
|
+
this.websocket?.close();
|
|
156
|
+
done.reject(new Error('Connection timeout'));
|
|
157
|
+
}
|
|
158
|
+
}, 10000);
|
|
159
|
+
this.websocket.onopen = () => {
|
|
160
|
+
clearTimeout(connectionTimeout);
|
|
161
|
+
console.log('TypedSocket connected!');
|
|
162
|
+
this.updateStatus('connected');
|
|
163
|
+
this.retryCount = 0;
|
|
164
|
+
this.currentBackoff = this.clientOptions?.initialBackoffMs ?? 1000;
|
|
165
|
+
done.resolve();
|
|
166
|
+
};
|
|
167
|
+
this.websocket.onmessage = async (event) => {
|
|
168
|
+
await this.handleMessage(event.data);
|
|
169
|
+
};
|
|
170
|
+
this.websocket.onclose = () => {
|
|
171
|
+
clearTimeout(connectionTimeout);
|
|
172
|
+
this.handleDisconnect();
|
|
173
|
+
};
|
|
174
|
+
this.websocket.onerror = (error) => {
|
|
175
|
+
console.error('TypedSocket WebSocket error:', error);
|
|
176
|
+
};
|
|
177
|
+
try {
|
|
178
|
+
await done.promise;
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
clearTimeout(connectionTimeout);
|
|
182
|
+
if (this.clientOptions?.autoReconnect) {
|
|
183
|
+
await this.scheduleReconnect();
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
throw err;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Converts an HTTP(S) URL to a WebSocket URL
|
|
192
|
+
*/
|
|
193
|
+
toWebSocketUrl(url) {
|
|
194
|
+
const parsed = new URL(url);
|
|
195
|
+
const wsProtocol = parsed.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
196
|
+
return `${wsProtocol}//${parsed.host}${parsed.pathname}`;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Handles incoming WebSocket messages
|
|
200
|
+
*/
|
|
201
|
+
async handleMessage(data) {
|
|
202
|
+
try {
|
|
203
|
+
const messageText = typeof data === 'string' ? data : new TextDecoder().decode(data);
|
|
204
|
+
const message = plugins.smartjson.parse(messageText);
|
|
205
|
+
// Check if this is a response to a pending request
|
|
206
|
+
if (message.correlation?.id && this.pendingRequests.has(message.correlation.id)) {
|
|
207
|
+
const pending = this.pendingRequests.get(message.correlation.id);
|
|
208
|
+
this.pendingRequests.delete(message.correlation.id);
|
|
209
|
+
pending.resolve(message);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Server-initiated request - route through TypedRouter
|
|
213
|
+
const response = await this.typedrouter.routeAndAddResponse(message);
|
|
214
|
+
if (response && this.websocket?.readyState === WebSocket.OPEN) {
|
|
215
|
+
this.websocket.send(plugins.smartjson.stringify(response));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
console.error('TypedSocket failed to process message:', err);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Handles WebSocket disconnection
|
|
224
|
+
*/
|
|
225
|
+
handleDisconnect() {
|
|
226
|
+
if (this.connectionStatus === 'disconnected') {
|
|
227
|
+
return; // Already handled
|
|
228
|
+
}
|
|
229
|
+
this.updateStatus('disconnected');
|
|
230
|
+
// Reject all pending requests — the connection is gone and they'll never receive a response
|
|
231
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
232
|
+
pending.reject(new Error('TypedSocket disconnected'));
|
|
233
|
+
}
|
|
234
|
+
this.pendingRequests.clear();
|
|
235
|
+
if (this.clientOptions?.autoReconnect && this.retryCount < this.clientOptions.maxRetries) {
|
|
236
|
+
this.scheduleReconnect();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Schedules a reconnection attempt with exponential backoff
|
|
241
|
+
*/
|
|
242
|
+
async scheduleReconnect() {
|
|
243
|
+
if (!this.clientOptions)
|
|
244
|
+
return;
|
|
245
|
+
this.updateStatus('reconnecting');
|
|
246
|
+
this.retryCount++;
|
|
247
|
+
// Exponential backoff with jitter
|
|
248
|
+
const jitter = this.currentBackoff * 0.2 * (Math.random() * 2 - 1);
|
|
249
|
+
const delay = Math.min(this.currentBackoff + jitter, this.clientOptions.maxBackoffMs);
|
|
250
|
+
console.log(`TypedSocket reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount}/${this.clientOptions.maxRetries})`);
|
|
251
|
+
await plugins.smartdelay.delayFor(delay);
|
|
252
|
+
// Increase backoff for next time
|
|
253
|
+
this.currentBackoff = Math.min(this.currentBackoff * 2, this.clientOptions.maxBackoffMs);
|
|
254
|
+
try {
|
|
255
|
+
await this.connect();
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
console.error('TypedSocket reconnection failed:', err);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Updates connection status and notifies subscribers
|
|
263
|
+
*/
|
|
264
|
+
updateStatus(status) {
|
|
265
|
+
if (this.connectionStatus !== status) {
|
|
266
|
+
this.connectionStatus = status;
|
|
267
|
+
this.statusSubject.next(status);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Sends a request to the server and waits for response (client-side)
|
|
272
|
+
*/
|
|
273
|
+
async sendRequest(request) {
|
|
274
|
+
if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) {
|
|
275
|
+
throw new Error('WebSocket not connected');
|
|
276
|
+
}
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
const timeout = setTimeout(() => {
|
|
279
|
+
this.pendingRequests.delete(request.correlation.id);
|
|
280
|
+
reject(new Error('Request timeout'));
|
|
281
|
+
}, 30000);
|
|
282
|
+
this.pendingRequests.set(request.correlation.id, {
|
|
283
|
+
resolve: (response) => {
|
|
284
|
+
clearTimeout(timeout);
|
|
285
|
+
resolve(response);
|
|
286
|
+
},
|
|
287
|
+
reject: (error) => {
|
|
288
|
+
clearTimeout(timeout);
|
|
289
|
+
reject(error);
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
this.websocket.send(plugins.smartjson.stringify(request));
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// ============================================================================
|
|
296
|
+
// PUBLIC API - SHARED
|
|
297
|
+
// ============================================================================
|
|
298
|
+
/**
|
|
299
|
+
* Creates a TypedRequest for the specified method.
|
|
300
|
+
* On clients, sends to the server.
|
|
301
|
+
* On servers, sends to the specified target connection.
|
|
302
|
+
*/
|
|
303
|
+
createTypedRequest(methodName, targetConnection) {
|
|
304
|
+
const postMethod = async (requestDataArg) => {
|
|
305
|
+
if (this.side === 'client') {
|
|
306
|
+
return this.sendRequest(requestDataArg);
|
|
307
|
+
}
|
|
308
|
+
// Server-side: send to target connection
|
|
309
|
+
if (!this.smartServeRef) {
|
|
310
|
+
throw new Error('Server not initialized');
|
|
311
|
+
}
|
|
312
|
+
let target = targetConnection;
|
|
313
|
+
if (!target) {
|
|
314
|
+
const allConnections = this.smartServeRef.getWebSocketConnections();
|
|
111
315
|
if (allConnections.length === 1) {
|
|
112
|
-
console.log('Since no targetConnection was supplied and there is only one active one present, choosing that one automatically');
|
|
113
316
|
const peer = allConnections[0];
|
|
114
|
-
|
|
115
|
-
if (!wrapper) {
|
|
116
|
-
wrapper = wrapSmartServePeer(peer);
|
|
117
|
-
connectionWrappers.set(peer.id, wrapper);
|
|
118
|
-
}
|
|
119
|
-
targetConnectionArg = wrapper;
|
|
317
|
+
target = this.getOrCreateWrapper(peer);
|
|
120
318
|
}
|
|
121
319
|
else if (allConnections.length === 0) {
|
|
122
320
|
throw new Error('No WebSocket connections available');
|
|
123
321
|
}
|
|
124
322
|
else {
|
|
125
|
-
throw new Error('
|
|
323
|
+
throw new Error('Multiple connections available - specify targetConnection');
|
|
126
324
|
}
|
|
127
325
|
}
|
|
128
|
-
// Register interest for
|
|
129
|
-
const interest = await
|
|
130
|
-
// Send
|
|
131
|
-
|
|
132
|
-
// Wait for
|
|
133
|
-
|
|
134
|
-
return response;
|
|
326
|
+
// Register interest for response
|
|
327
|
+
const interest = await this.typedrouter.fireEventInterestMap.addInterest(requestDataArg.correlation.id, requestDataArg);
|
|
328
|
+
// Send request
|
|
329
|
+
target.peer.send(plugins.smartjson.stringify(requestDataArg));
|
|
330
|
+
// Wait for response
|
|
331
|
+
return await interest.interestFullfilled;
|
|
135
332
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
333
|
+
return new plugins.typedrequest.TypedRequest(new plugins.typedrequest.TypedTarget({ postMethod }), methodName);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Gets the current connection status
|
|
337
|
+
*/
|
|
338
|
+
getStatus() {
|
|
339
|
+
return this.connectionStatus;
|
|
141
340
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Stops the TypedSocket client or cleans up server state
|
|
343
|
+
*/
|
|
344
|
+
async stop() {
|
|
345
|
+
if (this.side === 'client') {
|
|
346
|
+
if (this.clientOptions) {
|
|
347
|
+
this.clientOptions.autoReconnect = false;
|
|
348
|
+
}
|
|
349
|
+
if (this.websocket) {
|
|
350
|
+
this.websocket.close();
|
|
351
|
+
this.websocket = null;
|
|
352
|
+
}
|
|
353
|
+
this.pendingRequests.clear();
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
// Server mode - just clear wrappers (SmartServe manages its own lifecycle)
|
|
357
|
+
this.smartServeConnectionWrappers.clear();
|
|
148
358
|
}
|
|
149
|
-
return this.socketServerOrClient.eventSubject;
|
|
150
359
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
360
|
+
// ============================================================================
|
|
361
|
+
// CLIENT-ONLY METHODS
|
|
362
|
+
// ============================================================================
|
|
363
|
+
/**
|
|
364
|
+
* Sets a tag on this client connection.
|
|
365
|
+
* Tags are stored on the server and can be used for filtering.
|
|
366
|
+
* @client-only
|
|
367
|
+
*/
|
|
368
|
+
async setTag(name, payload) {
|
|
369
|
+
if (this.side !== 'client') {
|
|
370
|
+
throw new Error('setTag is only available on clients');
|
|
371
|
+
}
|
|
372
|
+
const request = this.createTypedRequest('__typedsocket_setTag');
|
|
373
|
+
const response = await request.fire({ name, payload });
|
|
374
|
+
if (!response.success) {
|
|
375
|
+
throw new Error('Failed to set tag on server');
|
|
376
|
+
}
|
|
157
377
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
378
|
+
/**
|
|
379
|
+
* Removes a tag from this client connection.
|
|
380
|
+
* @client-only
|
|
381
|
+
*/
|
|
382
|
+
async removeTag(name) {
|
|
383
|
+
if (this.side !== 'client') {
|
|
384
|
+
throw new Error('removeTag is only available on clients');
|
|
165
385
|
}
|
|
166
|
-
|
|
167
|
-
|
|
386
|
+
const request = this.createTypedRequest('__typedsocket_removeTag');
|
|
387
|
+
const response = await request.fire({ name });
|
|
388
|
+
if (!response.success) {
|
|
389
|
+
throw new Error('Failed to remove tag on server');
|
|
168
390
|
}
|
|
169
391
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
392
|
+
// ============================================================================
|
|
393
|
+
// SERVER-ONLY METHODS
|
|
394
|
+
// ============================================================================
|
|
395
|
+
/**
|
|
396
|
+
* Gets or creates a connection wrapper for a peer
|
|
397
|
+
*/
|
|
398
|
+
getOrCreateWrapper(peer) {
|
|
399
|
+
let wrapper = this.smartServeConnectionWrappers.get(peer.id);
|
|
400
|
+
if (!wrapper) {
|
|
401
|
+
wrapper = wrapSmartServePeer(peer);
|
|
402
|
+
this.smartServeConnectionWrappers.set(peer.id, wrapper);
|
|
403
|
+
}
|
|
404
|
+
return wrapper;
|
|
178
405
|
}
|
|
179
406
|
/**
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* @param asyncFindFuncArg - async filter function
|
|
183
|
-
* @returns array of matching connections
|
|
407
|
+
* Finds all connections matching the filter function.
|
|
408
|
+
* @server-only
|
|
184
409
|
*/
|
|
185
410
|
async findAllTargetConnections(asyncFindFuncArg) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const matchingConnections = [];
|
|
189
|
-
for (const peer of this.smartServeRef.getWebSocketConnections()) {
|
|
190
|
-
let wrapper = this.smartServeConnectionWrappers.get(peer.id);
|
|
191
|
-
if (!wrapper) {
|
|
192
|
-
wrapper = wrapSmartServePeer(peer);
|
|
193
|
-
this.smartServeConnectionWrappers.set(peer.id, wrapper);
|
|
194
|
-
}
|
|
195
|
-
if (await asyncFindFuncArg(wrapper)) {
|
|
196
|
-
matchingConnections.push(wrapper);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return matchingConnections;
|
|
411
|
+
if (this.side !== 'server' || !this.smartServeRef) {
|
|
412
|
+
throw new Error('findAllTargetConnections is only available on servers');
|
|
200
413
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
matchingSockets.push(socketConnection);
|
|
207
|
-
}
|
|
414
|
+
const matchingConnections = [];
|
|
415
|
+
for (const peer of this.smartServeRef.getWebSocketConnections()) {
|
|
416
|
+
const wrapper = this.getOrCreateWrapper(peer);
|
|
417
|
+
if (await asyncFindFuncArg(wrapper)) {
|
|
418
|
+
matchingConnections.push(wrapper);
|
|
208
419
|
}
|
|
209
|
-
return matchingSockets;
|
|
210
420
|
}
|
|
211
|
-
|
|
421
|
+
return matchingConnections;
|
|
212
422
|
}
|
|
213
423
|
/**
|
|
214
|
-
*
|
|
215
|
-
* @
|
|
216
|
-
* @returns
|
|
424
|
+
* Finds the first connection matching the filter function.
|
|
425
|
+
* @server-only
|
|
217
426
|
*/
|
|
218
427
|
async findTargetConnection(asyncFindFuncArg) {
|
|
219
428
|
const allMatching = await this.findAllTargetConnections(asyncFindFuncArg);
|
|
220
429
|
return allMatching[0];
|
|
221
430
|
}
|
|
222
431
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
432
|
+
* Finds all connections with the specified tag.
|
|
433
|
+
* @server-only
|
|
225
434
|
*/
|
|
226
435
|
async findAllTargetConnectionsByTag(keyArg, payloadArg) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const tag = await wrapper.getTagById(keyArg);
|
|
240
|
-
if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
436
|
+
if (this.side !== 'server' || !this.smartServeRef) {
|
|
437
|
+
throw new Error('findAllTargetConnectionsByTag is only available on servers');
|
|
438
|
+
}
|
|
439
|
+
const peers = this.smartServeRef.getWebSocketConnectionsByTag(keyArg);
|
|
440
|
+
const results = [];
|
|
441
|
+
for (const peer of peers) {
|
|
442
|
+
const wrapper = this.getOrCreateWrapper(peer);
|
|
443
|
+
// If payload specified, also filter by payload
|
|
444
|
+
if (payloadArg !== undefined) {
|
|
445
|
+
const tag = await wrapper.getTagById(keyArg);
|
|
446
|
+
if (plugins.smartjson.stringify(tag?.payload) !== plugins.smartjson.stringify(payloadArg)) {
|
|
447
|
+
continue;
|
|
243
448
|
}
|
|
244
|
-
results.push(wrapper);
|
|
245
449
|
}
|
|
246
|
-
|
|
450
|
+
results.push(wrapper);
|
|
247
451
|
}
|
|
248
|
-
|
|
249
|
-
return this.findAllTargetConnections(async (socketConnectionArg) => {
|
|
250
|
-
let result;
|
|
251
|
-
if (!payloadArg) {
|
|
252
|
-
result = !!(await socketConnectionArg.getTagById(keyArg));
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
result = !!(plugins.smartjson.stringify((await socketConnectionArg.getTagById(keyArg))?.payload) ===
|
|
256
|
-
plugins.smartjson.stringify(payloadArg));
|
|
257
|
-
}
|
|
258
|
-
return result;
|
|
259
|
-
});
|
|
452
|
+
return results;
|
|
260
453
|
}
|
|
261
454
|
/**
|
|
262
|
-
*
|
|
455
|
+
* Finds the first connection with the specified tag.
|
|
456
|
+
* @server-only
|
|
263
457
|
*/
|
|
264
458
|
async findTargetConnectionByTag(keyArg, payloadArg) {
|
|
265
459
|
const allResults = await this.findAllTargetConnectionsByTag(keyArg, payloadArg);
|
|
266
460
|
return allResults[0];
|
|
267
461
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Stop the TypedSocket server/client
|
|
270
|
-
* Note: In SmartServe mode, SmartServe manages its own lifecycle
|
|
271
|
-
*/
|
|
272
|
-
async stop() {
|
|
273
|
-
if (this.smartServeRef) {
|
|
274
|
-
// SmartServe manages its own lifecycle
|
|
275
|
-
// Clear our connection wrappers
|
|
276
|
-
this.smartServeConnectionWrappers.clear();
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
await this.socketServerOrClient.stop();
|
|
280
|
-
}
|
|
281
462
|
}
|
|
282
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWRzb2NrZXQuY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3R5cGVkc29ja2V0LmNsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUVwRCxNQUFNLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQztBQUN4QyxNQUFNLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQztBQWF4Qzs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQUMsSUFBNEI7SUFDdEQsTUFBTSxVQUFVLEdBQUcscUJBQXFCLENBQUM7SUFDekMsT0FBTztRQUNMLElBQUk7UUFDSixLQUFLLENBQUMsVUFBVSxDQUFDLEtBQWE7WUFDNUIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzFCLE9BQU8sU0FBUyxDQUFDO1lBQ25CLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ2hDLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELE1BQU0sT0FBTyxXQUFXO0lBQ3RCLFNBQVM7SUFDVDs7O09BR0c7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FDOUIsY0FBZ0Q7UUFFaEQsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO1lBQzVELEtBQUssRUFBRSxtQkFBbUI7WUFDMUIsSUFBSSxFQUFFLElBQUk7U0FDWCxDQUFDLENBQUM7UUFFSCxpQkFBaUIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUNuQyxJQUFJLE9BQU8sQ0FBQyxX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
|
|
463
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWRzb2NrZXQuY2xhc3Nlcy50eXBlZHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3R5cGVkc29ja2V0LmNsYXNzZXMudHlwZWRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUtwRCxNQUFNLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQztBQW1DekM7O0dBRUc7QUFDSCxTQUFTLGtCQUFrQixDQUFDLElBQTRCO0lBQ3RELE9BQU87UUFDTCxJQUFJO1FBQ0osS0FBSyxDQUFDLFVBQVUsQ0FBQyxLQUFhO1lBQzVCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUMxQixPQUFPLFNBQVMsQ0FBQztZQUNuQixDQUFDO1lBQ0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxVQUFVLEdBQUcsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUN2RCxPQUFPLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNoQyxDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLE9BQU8sV0FBVztJQUN0QiwrRUFBK0U7SUFDL0UsaUJBQWlCO0lBQ2pCLCtFQUErRTtJQUUvRTs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FDOUIsY0FBZ0QsRUFDaEQsWUFBb0IsRUFDcEIsVUFBcUMsRUFBRTtRQUV2QyxNQUFNLGNBQWMsR0FBd0M7WUFDMUQsYUFBYSxFQUFFLElBQUk7WUFDbkIsVUFBVSxFQUFFLEdBQUc7WUFDZixnQkFBZ0IsRUFBRSxJQUFJO1lBQ3RCLFlBQVksRUFBRSxLQUFLO1NBQ3BCLENBQUM7UUFDRixNQUFNLElBQUksR0FBRyxFQUFFLEdBQUcsY0FBYyxFQUFFLEdBQUcs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
|