@sigx/lynx-websocket 0.1.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/LICENSE +21 -0
- package/README.md +147 -0
- package/android/com/sigx/websocket/WebSocketEventBus.kt +104 -0
- package/android/com/sigx/websocket/WebSocketModule.kt +78 -0
- package/android/com/sigx/websocket/WebSocketPublisher.kt +44 -0
- package/android/com/sigx/websocket/WebSocketTaskStore.kt +115 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/websocket.d.ts +91 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +429 -0
- package/dist/websocket.js.map +1 -0
- package/ios/WebSocketEventBus.swift +86 -0
- package/ios/WebSocketModule.swift +89 -0
- package/ios/WebSocketPublisher.swift +34 -0
- package/ios/WebSocketTaskStore.swift +128 -0
- package/package.json +58 -0
- package/sigx-module.json +19 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-standard `WebSocket` client backed by the `@sigx/lynx-websocket`
|
|
3
|
+
* native module (URLSessionWebSocketTask on iOS, OkHttp WebSocket on
|
|
4
|
+
* Android).
|
|
5
|
+
*
|
|
6
|
+
* Public surface mirrors the WHATWG WebSocket interface:
|
|
7
|
+
*
|
|
8
|
+
* new WebSocket(url, protocols?)
|
|
9
|
+
* .readyState / .url / .protocol / .extensions / .bufferedAmount
|
|
10
|
+
* .binaryType ('arraybuffer' only — 'blob' is not supported)
|
|
11
|
+
* .onopen / .onmessage / .onerror / .onclose
|
|
12
|
+
* .addEventListener / .removeEventListener / .dispatchEvent
|
|
13
|
+
* .send(string | ArrayBuffer | ArrayBufferView)
|
|
14
|
+
* .close(code?, reason?)
|
|
15
|
+
*
|
|
16
|
+
* Multi-socket dispatch: each instance is assigned a monotonic numeric id.
|
|
17
|
+
* The native side emits a single `__sigxWebSocketEvent` global event
|
|
18
|
+
* carrying `{ id, type, ... }`; the JS shim demultiplexes by id and fires
|
|
19
|
+
* the matching instance's listeners.
|
|
20
|
+
*/
|
|
21
|
+
import { callAsync, guardModule, isModuleAvailable } from '@sigx/lynx-core';
|
|
22
|
+
const MODULE = 'WebSocket';
|
|
23
|
+
const EVENT_NAME = '__sigxWebSocketEvent';
|
|
24
|
+
function lynxObj() {
|
|
25
|
+
return typeof lynx !== 'undefined' ? lynx : undefined;
|
|
26
|
+
}
|
|
27
|
+
const CONNECTING = 0;
|
|
28
|
+
const OPEN = 1;
|
|
29
|
+
const CLOSING = 2;
|
|
30
|
+
const CLOSED = 3;
|
|
31
|
+
/**
|
|
32
|
+
* Decode a base64 string into an `ArrayBuffer`. Lynx's BTS runtime has
|
|
33
|
+
* `atob` per the platform docs, but fall back to a manual decoder to keep
|
|
34
|
+
* this shim portable across hosts where it might be absent.
|
|
35
|
+
*/
|
|
36
|
+
function base64ToArrayBuffer(b64) {
|
|
37
|
+
if (typeof atob === 'function') {
|
|
38
|
+
const bin = atob(b64);
|
|
39
|
+
const buf = new ArrayBuffer(bin.length);
|
|
40
|
+
const view = new Uint8Array(buf);
|
|
41
|
+
for (let i = 0; i < bin.length; i++)
|
|
42
|
+
view[i] = bin.charCodeAt(i);
|
|
43
|
+
return buf;
|
|
44
|
+
}
|
|
45
|
+
// Pure-JS fallback. Not the fastest, but executed at most for binary
|
|
46
|
+
// frames on hosts that ship no atob (vanishingly rare).
|
|
47
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
48
|
+
const lookup = new Int8Array(256).fill(-1);
|
|
49
|
+
for (let i = 0; i < chars.length; i++)
|
|
50
|
+
lookup[chars.charCodeAt(i)] = i;
|
|
51
|
+
const clean = b64.replace(/=+$/, '');
|
|
52
|
+
const out = new Uint8Array((clean.length * 3) >> 2);
|
|
53
|
+
let p = 0;
|
|
54
|
+
let buf = 0;
|
|
55
|
+
let bits = 0;
|
|
56
|
+
for (let i = 0; i < clean.length; i++) {
|
|
57
|
+
const v = lookup[clean.charCodeAt(i)];
|
|
58
|
+
if (v < 0)
|
|
59
|
+
continue;
|
|
60
|
+
buf = (buf << 6) | v;
|
|
61
|
+
bits += 6;
|
|
62
|
+
if (bits >= 8) {
|
|
63
|
+
bits -= 8;
|
|
64
|
+
out[p++] = (buf >> bits) & 0xff;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return out.buffer;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Encode an `ArrayBuffer` / view to base64 for transport to native.
|
|
71
|
+
* Native side base64-decodes back to raw bytes before sending on the wire.
|
|
72
|
+
*/
|
|
73
|
+
function arrayBufferToBase64(buf) {
|
|
74
|
+
const bytes = new Uint8Array(buf);
|
|
75
|
+
if (typeof btoa === 'function') {
|
|
76
|
+
// Build the binary string in chunks to dodge call-stack limits on
|
|
77
|
+
// large frames (String.fromCharCode.apply blows up around ~64k args).
|
|
78
|
+
let bin = '';
|
|
79
|
+
const CHUNK = 0x8000;
|
|
80
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
81
|
+
bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));
|
|
82
|
+
}
|
|
83
|
+
return btoa(bin);
|
|
84
|
+
}
|
|
85
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
86
|
+
let out = '';
|
|
87
|
+
let i = 0;
|
|
88
|
+
for (; i + 2 < bytes.length; i += 3) {
|
|
89
|
+
const n = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
|
90
|
+
out += chars[(n >> 18) & 63] + chars[(n >> 12) & 63] + chars[(n >> 6) & 63] + chars[n & 63];
|
|
91
|
+
}
|
|
92
|
+
if (i < bytes.length) {
|
|
93
|
+
const rem = bytes.length - i;
|
|
94
|
+
const n = rem === 1 ? bytes[i] << 16 : (bytes[i] << 16) | (bytes[i + 1] << 8);
|
|
95
|
+
out += chars[(n >> 18) & 63] + chars[(n >> 12) & 63];
|
|
96
|
+
out += rem === 2 ? chars[(n >> 6) & 63] + '=' : '==';
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Shared event dispatch — one global lynx listener that demuxes by socket id.
|
|
102
|
+
const sockets = new Map();
|
|
103
|
+
let nextId = 1;
|
|
104
|
+
let subscribed = false;
|
|
105
|
+
let cachedEmitter = null;
|
|
106
|
+
function ensureSubscribed() {
|
|
107
|
+
if (subscribed)
|
|
108
|
+
return;
|
|
109
|
+
const emitter = lynxObj()?.getJSModule?.('GlobalEventEmitter');
|
|
110
|
+
if (!emitter)
|
|
111
|
+
return; // web/SSR/test — events simply won't arrive
|
|
112
|
+
cachedEmitter = emitter;
|
|
113
|
+
emitter.addListener(EVENT_NAME, (raw) => {
|
|
114
|
+
// Lynx ships event params as a single JSON-shaped object or as the
|
|
115
|
+
// first arg of the listener. Tolerate both shapes.
|
|
116
|
+
const evt = typeof raw === 'string' ? safeParse(raw) : raw;
|
|
117
|
+
if (!evt || typeof evt.id !== 'number')
|
|
118
|
+
return;
|
|
119
|
+
const ws = sockets.get(evt.id);
|
|
120
|
+
if (!ws)
|
|
121
|
+
return;
|
|
122
|
+
// Internal dispatch lives on the instance so it can mutate state.
|
|
123
|
+
ws._dispatch(evt);
|
|
124
|
+
});
|
|
125
|
+
subscribed = true;
|
|
126
|
+
}
|
|
127
|
+
function safeParse(s) {
|
|
128
|
+
try {
|
|
129
|
+
return JSON.parse(s);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* WHATWG-compatible WebSocket. Drop-in for browser code.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* const ws = new WebSocket('wss://ws.postman-echo.com/raw');
|
|
142
|
+
* ws.onopen = () => ws.send('hello');
|
|
143
|
+
* ws.onmessage = e => console.log(e.data);
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export class WebSocket {
|
|
147
|
+
get readyState() {
|
|
148
|
+
return this._readyState;
|
|
149
|
+
}
|
|
150
|
+
constructor(url, protocols) {
|
|
151
|
+
this.CONNECTING = CONNECTING;
|
|
152
|
+
this.OPEN = OPEN;
|
|
153
|
+
this.CLOSING = CLOSING;
|
|
154
|
+
this.CLOSED = CLOSED;
|
|
155
|
+
this.protocol = '';
|
|
156
|
+
this.extensions = '';
|
|
157
|
+
this.bufferedAmount = 0;
|
|
158
|
+
this.binaryType = 'arraybuffer';
|
|
159
|
+
this.onopen = null;
|
|
160
|
+
this.onmessage = null;
|
|
161
|
+
this.onerror = null;
|
|
162
|
+
this.onclose = null;
|
|
163
|
+
this._readyState = CONNECTING;
|
|
164
|
+
this._listeners = Object.create(null);
|
|
165
|
+
if (typeof url !== 'string' || url.length === 0) {
|
|
166
|
+
throw new TypeError(`WebSocket: invalid URL`);
|
|
167
|
+
}
|
|
168
|
+
// Match browsers: only ws:/wss: are valid. We accept http:/https: too
|
|
169
|
+
// and let the native side reject — some debug proxies normalise.
|
|
170
|
+
const colon = url.indexOf(':');
|
|
171
|
+
if (colon <= 0) {
|
|
172
|
+
throw new SyntaxError(`WebSocket: invalid URL "${url}"`);
|
|
173
|
+
}
|
|
174
|
+
const scheme = url.slice(0, colon).toLowerCase();
|
|
175
|
+
if (scheme !== 'ws' && scheme !== 'wss' && scheme !== 'http' && scheme !== 'https') {
|
|
176
|
+
throw new SyntaxError(`WebSocket: unsupported URL scheme "${scheme}"`);
|
|
177
|
+
}
|
|
178
|
+
guardModule(MODULE);
|
|
179
|
+
this.url = url;
|
|
180
|
+
this._id = nextId++;
|
|
181
|
+
sockets.set(this._id, this);
|
|
182
|
+
ensureSubscribed();
|
|
183
|
+
const protoList = Array.isArray(protocols)
|
|
184
|
+
? protocols
|
|
185
|
+
: typeof protocols === 'string' && protocols.length > 0
|
|
186
|
+
? [protocols]
|
|
187
|
+
: [];
|
|
188
|
+
// Fire-and-forget — open/error are delivered through the event
|
|
189
|
+
// channel, not the callback. We still surface synchronous bridge
|
|
190
|
+
// failures (e.g. module not registered) as an async error event.
|
|
191
|
+
callAsync(MODULE, 'create', this._id, url, protoList).catch(err => {
|
|
192
|
+
this._dispatch({
|
|
193
|
+
id: this._id,
|
|
194
|
+
type: 'error',
|
|
195
|
+
data: err instanceof Error ? err.message : String(err),
|
|
196
|
+
});
|
|
197
|
+
this._dispatch({
|
|
198
|
+
id: this._id,
|
|
199
|
+
type: 'close',
|
|
200
|
+
code: 1006,
|
|
201
|
+
reason: '',
|
|
202
|
+
wasClean: false,
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
send(data) {
|
|
207
|
+
if (this._readyState === CONNECTING) {
|
|
208
|
+
// Browsers throw InvalidStateError here.
|
|
209
|
+
throw new Error("InvalidStateError: WebSocket is still in CONNECTING state.");
|
|
210
|
+
}
|
|
211
|
+
if (this._readyState !== OPEN) {
|
|
212
|
+
// Browsers silently drop on CLOSING/CLOSED but warn in devtools.
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
let isBinary = false;
|
|
216
|
+
let payload;
|
|
217
|
+
if (typeof data === 'string') {
|
|
218
|
+
payload = data;
|
|
219
|
+
}
|
|
220
|
+
else if (data instanceof ArrayBuffer) {
|
|
221
|
+
isBinary = true;
|
|
222
|
+
payload = arrayBufferToBase64(data);
|
|
223
|
+
}
|
|
224
|
+
else if (ArrayBuffer.isView(data)) {
|
|
225
|
+
isBinary = true;
|
|
226
|
+
const view = data;
|
|
227
|
+
// Copy the active range out of the underlying buffer so we don't
|
|
228
|
+
// accidentally send bytes outside the view.
|
|
229
|
+
const slice = view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
230
|
+
payload = arrayBufferToBase64(slice);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
throw new TypeError('WebSocket.send: unsupported data type');
|
|
234
|
+
}
|
|
235
|
+
// bufferedAmount is approximated as the byte length the JS side has
|
|
236
|
+
// handed off — the native side acks via 'flushed' frames in a future
|
|
237
|
+
// version; for now this is a write-through counter.
|
|
238
|
+
this.bufferedAmount += isBinary ? base64ByteLength(payload) : utf8ByteLength(payload);
|
|
239
|
+
callAsync(MODULE, 'send', this._id, payload, isBinary).catch(err => {
|
|
240
|
+
this._dispatch({
|
|
241
|
+
id: this._id,
|
|
242
|
+
type: 'error',
|
|
243
|
+
data: err instanceof Error ? err.message : String(err),
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
close(code, reason) {
|
|
248
|
+
if (this._readyState === CLOSING || this._readyState === CLOSED)
|
|
249
|
+
return;
|
|
250
|
+
// WHATWG: code must be 1000 or 3000–4999. Validate to mirror browsers.
|
|
251
|
+
if (code !== undefined) {
|
|
252
|
+
if (code !== 1000 && (code < 3000 || code > 4999)) {
|
|
253
|
+
throw new Error(`InvalidAccessError: close code ${code} must be 1000 or in the 3000-4999 range.`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (reason !== undefined && utf8ByteLength(reason) > 123) {
|
|
257
|
+
throw new SyntaxError('SyntaxError: close reason must be ≤123 UTF-8 bytes.');
|
|
258
|
+
}
|
|
259
|
+
this._readyState = CLOSING;
|
|
260
|
+
callAsync(MODULE, 'close', this._id, code ?? 1000, reason ?? '').catch(err => {
|
|
261
|
+
// Bridge call itself failed (e.g. module missing). Synthesize an
|
|
262
|
+
// abnormal close so the instance doesn't get stuck in CLOSING and
|
|
263
|
+
// we still clean up sockets state.
|
|
264
|
+
this._dispatch({
|
|
265
|
+
id: this._id,
|
|
266
|
+
type: 'error',
|
|
267
|
+
data: err instanceof Error ? err.message : String(err),
|
|
268
|
+
});
|
|
269
|
+
this._dispatch({
|
|
270
|
+
id: this._id,
|
|
271
|
+
type: 'close',
|
|
272
|
+
code: 1006,
|
|
273
|
+
reason: '',
|
|
274
|
+
wasClean: false,
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// -- EventTarget ---------------------------------------------------------
|
|
279
|
+
addEventListener(type, listener) {
|
|
280
|
+
var _a;
|
|
281
|
+
if (!listener)
|
|
282
|
+
return;
|
|
283
|
+
((_a = this._listeners)[type] ?? (_a[type] = new Set())).add(listener);
|
|
284
|
+
}
|
|
285
|
+
removeEventListener(type, listener) {
|
|
286
|
+
this._listeners[type]?.delete(listener);
|
|
287
|
+
}
|
|
288
|
+
dispatchEvent(event) {
|
|
289
|
+
this._invoke(event.type, event);
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
// -- Internal ------------------------------------------------------------
|
|
293
|
+
/** @internal — called by the shared global-event subscriber. */
|
|
294
|
+
_dispatch(evt) {
|
|
295
|
+
switch (evt.type) {
|
|
296
|
+
case 'open': {
|
|
297
|
+
this._readyState = OPEN;
|
|
298
|
+
if (typeof evt.protocol === 'string')
|
|
299
|
+
this.protocol = evt.protocol;
|
|
300
|
+
if (typeof evt.extensions === 'string')
|
|
301
|
+
this.extensions = evt.extensions;
|
|
302
|
+
this._invoke('open', {
|
|
303
|
+
type: 'open',
|
|
304
|
+
target: this,
|
|
305
|
+
currentTarget: this,
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case 'message': {
|
|
310
|
+
if (this._readyState !== OPEN)
|
|
311
|
+
return;
|
|
312
|
+
let data;
|
|
313
|
+
if (evt.isBinary && typeof evt.binary === 'string') {
|
|
314
|
+
data = base64ToArrayBuffer(evt.binary);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
data = evt.data ?? '';
|
|
318
|
+
}
|
|
319
|
+
this._invoke('message', {
|
|
320
|
+
type: 'message',
|
|
321
|
+
target: this,
|
|
322
|
+
currentTarget: this,
|
|
323
|
+
data,
|
|
324
|
+
});
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
case 'error': {
|
|
328
|
+
this._invoke('error', {
|
|
329
|
+
type: 'error',
|
|
330
|
+
target: this,
|
|
331
|
+
currentTarget: this,
|
|
332
|
+
message: evt.data,
|
|
333
|
+
});
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case 'close': {
|
|
337
|
+
if (this._readyState === CLOSED)
|
|
338
|
+
return;
|
|
339
|
+
this._readyState = CLOSED;
|
|
340
|
+
sockets.delete(this._id);
|
|
341
|
+
this._invoke('close', {
|
|
342
|
+
type: 'close',
|
|
343
|
+
target: this,
|
|
344
|
+
currentTarget: this,
|
|
345
|
+
code: evt.code ?? 1006,
|
|
346
|
+
reason: evt.reason ?? '',
|
|
347
|
+
wasClean: evt.wasClean ?? false,
|
|
348
|
+
});
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
_invoke(type, event) {
|
|
354
|
+
const handler = this[`on${type}`];
|
|
355
|
+
if (typeof handler === 'function') {
|
|
356
|
+
try {
|
|
357
|
+
handler.call(this, event);
|
|
358
|
+
}
|
|
359
|
+
catch (e) {
|
|
360
|
+
console.warn(`[WebSocket] on${type} handler threw:`, e);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const set = this._listeners[type];
|
|
364
|
+
if (set) {
|
|
365
|
+
for (const listener of set) {
|
|
366
|
+
try {
|
|
367
|
+
if (typeof listener === 'function')
|
|
368
|
+
listener.call(this, event);
|
|
369
|
+
else
|
|
370
|
+
listener.handleEvent(event);
|
|
371
|
+
}
|
|
372
|
+
catch (e) {
|
|
373
|
+
console.warn(`[WebSocket] '${type}' listener threw:`, e);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
WebSocket.CONNECTING = CONNECTING;
|
|
380
|
+
WebSocket.OPEN = OPEN;
|
|
381
|
+
WebSocket.CLOSING = CLOSING;
|
|
382
|
+
WebSocket.CLOSED = CLOSED;
|
|
383
|
+
/** Whether the native WebSocket module is registered in this build. */
|
|
384
|
+
export function isWebSocketAvailable() {
|
|
385
|
+
return isModuleAvailable(MODULE);
|
|
386
|
+
}
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
// Byte-length helpers (kept local to avoid pulling a dep).
|
|
389
|
+
function utf8ByteLength(s) {
|
|
390
|
+
let n = 0;
|
|
391
|
+
for (let i = 0; i < s.length; i++) {
|
|
392
|
+
const c = s.charCodeAt(i);
|
|
393
|
+
if (c < 0x80)
|
|
394
|
+
n += 1;
|
|
395
|
+
else if (c < 0x800)
|
|
396
|
+
n += 2;
|
|
397
|
+
else if (c >= 0xd800 && c <= 0xdbff) {
|
|
398
|
+
n += 4;
|
|
399
|
+
i++; // surrogate pair
|
|
400
|
+
}
|
|
401
|
+
else
|
|
402
|
+
n += 3;
|
|
403
|
+
}
|
|
404
|
+
return n;
|
|
405
|
+
}
|
|
406
|
+
function base64ByteLength(b64) {
|
|
407
|
+
const padding = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0;
|
|
408
|
+
return ((b64.length * 3) >> 2) - padding;
|
|
409
|
+
}
|
|
410
|
+
// Test-only escape hatch: exported under a stable name with a leading
|
|
411
|
+
// underscore so it's tree-shakeable but reachable from unit tests.
|
|
412
|
+
/** @internal */
|
|
413
|
+
export const __internal = {
|
|
414
|
+
deliver(evt) {
|
|
415
|
+
const ws = sockets.get(evt.id);
|
|
416
|
+
if (ws)
|
|
417
|
+
ws._dispatch(evt);
|
|
418
|
+
},
|
|
419
|
+
reset() {
|
|
420
|
+
sockets.clear();
|
|
421
|
+
nextId = 1;
|
|
422
|
+
subscribed = false;
|
|
423
|
+
cachedEmitter = null;
|
|
424
|
+
},
|
|
425
|
+
get cachedEmitter() {
|
|
426
|
+
return cachedEmitter;
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
//# sourceMappingURL=websocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Process-wide pub/sub bus that owns the conversion of native WebSocket
|
|
4
|
+
/// callbacks into JS-side event payloads. Sockets, sessions, and OS
|
|
5
|
+
/// delegates write here; per-LynxView `WebSocketPublisher` instances read.
|
|
6
|
+
///
|
|
7
|
+
/// Mirrors the publisher pattern used elsewhere in the repo
|
|
8
|
+
/// (`LinkingState`, `SafeAreaPublisher`, …): native lifecycle is decoupled
|
|
9
|
+
/// from any specific LynxView so events survive view recreation and
|
|
10
|
+
/// per-view subscribers can fan out without holding onto the WS task.
|
|
11
|
+
final class WebSocketEventBus {
|
|
12
|
+
|
|
13
|
+
static let shared = WebSocketEventBus()
|
|
14
|
+
|
|
15
|
+
/// JSON-encodable payload pushed to JS as the single
|
|
16
|
+
/// `__sigxWebSocketEvent` global event. Keys match the `NativeEvent`
|
|
17
|
+
/// interface in `src/websocket.ts`.
|
|
18
|
+
typealias Payload = [String: Any]
|
|
19
|
+
typealias Listener = (Payload) -> Void
|
|
20
|
+
|
|
21
|
+
private let queue = DispatchQueue(label: "com.sigx.websocket.bus")
|
|
22
|
+
private var listeners: [(token: UUID, fn: Listener)] = []
|
|
23
|
+
|
|
24
|
+
@discardableResult
|
|
25
|
+
func addListener(_ fn: @escaping Listener) -> UUID {
|
|
26
|
+
let token = UUID()
|
|
27
|
+
queue.sync { listeners.append((token, fn)) }
|
|
28
|
+
return token
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func removeListener(_ token: UUID) {
|
|
32
|
+
queue.sync { listeners.removeAll { $0.token == token } }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// MARK: - Publish
|
|
36
|
+
|
|
37
|
+
func publish(open protocolStr: String, extensions: String, id: Int) {
|
|
38
|
+
emit([
|
|
39
|
+
"id": id,
|
|
40
|
+
"type": "open",
|
|
41
|
+
"protocol": protocolStr,
|
|
42
|
+
"extensions": extensions,
|
|
43
|
+
])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func publish(messageText text: String, id: Int) {
|
|
47
|
+
emit([
|
|
48
|
+
"id": id,
|
|
49
|
+
"type": "message",
|
|
50
|
+
"data": text,
|
|
51
|
+
"isBinary": false,
|
|
52
|
+
])
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func publish(messageBinary base64: String, id: Int) {
|
|
56
|
+
emit([
|
|
57
|
+
"id": id,
|
|
58
|
+
"type": "message",
|
|
59
|
+
"binary": base64,
|
|
60
|
+
"isBinary": true,
|
|
61
|
+
])
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func publish(error message: String, id: Int) {
|
|
65
|
+
emit([
|
|
66
|
+
"id": id,
|
|
67
|
+
"type": "error",
|
|
68
|
+
"data": message,
|
|
69
|
+
])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func publish(close code: Int, reason: String, wasClean: Bool, id: Int) {
|
|
73
|
+
emit([
|
|
74
|
+
"id": id,
|
|
75
|
+
"type": "close",
|
|
76
|
+
"code": code,
|
|
77
|
+
"reason": reason,
|
|
78
|
+
"wasClean": wasClean,
|
|
79
|
+
])
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func emit(_ payload: Payload) {
|
|
83
|
+
let snapshot = queue.sync { listeners }
|
|
84
|
+
for (_, fn) in snapshot { fn(payload) }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Lynx
|
|
3
|
+
|
|
4
|
+
/// Native WebSocket bridge — JS-callable side.
|
|
5
|
+
///
|
|
6
|
+
/// JS usage (via the `@sigx/lynx-websocket` shim, not directly):
|
|
7
|
+
///
|
|
8
|
+
/// NativeModules.WebSocket.create(id, url, protocols, cb)
|
|
9
|
+
/// NativeModules.WebSocket.send(id, payload, isBinary, cb)
|
|
10
|
+
/// NativeModules.WebSocket.close(id, code, reason, cb)
|
|
11
|
+
///
|
|
12
|
+
/// Async lifecycle events (`open`, `message`, `error`, `close`) are pushed
|
|
13
|
+
/// back via `WebSocketEventBus`, which a per-LynxView `WebSocketPublisher`
|
|
14
|
+
/// forwards to JS through `LynxView.sendGlobalEvent("__sigxWebSocketEvent",
|
|
15
|
+
/// [...])`.
|
|
16
|
+
///
|
|
17
|
+
/// Implemented with `URLSessionWebSocketTask` (iOS 13+). Each socket is
|
|
18
|
+
/// stored in `tasks` keyed by the JS-supplied numeric id; the same id is
|
|
19
|
+
/// echoed back in every event so the JS shim can demultiplex.
|
|
20
|
+
@objc class WebSocketModule: NSObject, LynxModule {
|
|
21
|
+
|
|
22
|
+
@objc static var name: String { "WebSocket" }
|
|
23
|
+
|
|
24
|
+
@objc static var methodLookup: [String: String] {
|
|
25
|
+
[
|
|
26
|
+
"create": NSStringFromSelector(#selector(create(_:url:protocols:callback:))),
|
|
27
|
+
"send": NSStringFromSelector(#selector(send(_:payload:isBinary:callback:))),
|
|
28
|
+
"close": NSStringFromSelector(#selector(close(_:code:reason:callback:))),
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
required override init() { super.init() }
|
|
33
|
+
required init(param: Any) { super.init() }
|
|
34
|
+
|
|
35
|
+
// MARK: - JS-callable methods
|
|
36
|
+
|
|
37
|
+
@objc func create(_ id: NSNumber, url: String?, protocols: [Any]?, callback: LynxCallbackBlock?) {
|
|
38
|
+
guard let urlString = url, let parsed = URL(string: urlString) else {
|
|
39
|
+
WebSocketEventBus.shared.publish(error: "Invalid URL", id: id.intValue)
|
|
40
|
+
WebSocketEventBus.shared.publish(close: 1006, reason: "Invalid URL", wasClean: false, id: id.intValue)
|
|
41
|
+
callback?(NSNull())
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var request = URLRequest(url: parsed)
|
|
46
|
+
if let protos = protocols as? [String], !protos.isEmpty {
|
|
47
|
+
request.setValue(protos.joined(separator: ", "), forHTTPHeaderField: "Sec-WebSocket-Protocol")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
WebSocketTaskStore.shared.create(id: id.intValue, request: request)
|
|
51
|
+
callback?(NSNull())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@objc func send(_ id: NSNumber, payload: String?, isBinary: NSNumber?, callback: LynxCallbackBlock?) {
|
|
55
|
+
let binary = (isBinary?.boolValue ?? false)
|
|
56
|
+
guard let task = WebSocketTaskStore.shared.task(forId: id.intValue) else {
|
|
57
|
+
callback?(["error": "WebSocket \(id) not found"])
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let message: URLSessionWebSocketTask.Message
|
|
62
|
+
if binary {
|
|
63
|
+
// Payload is base64-encoded on the JS side — decode to raw bytes.
|
|
64
|
+
guard let data = Data(base64Encoded: payload ?? "") else {
|
|
65
|
+
callback?(["error": "Invalid base64 payload"])
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
message = .data(data)
|
|
69
|
+
} else {
|
|
70
|
+
message = .string(payload ?? "")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
task.send(message) { error in
|
|
74
|
+
if let error = error {
|
|
75
|
+
WebSocketEventBus.shared.publish(error: error.localizedDescription, id: id.intValue)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
callback?(NSNull())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@objc func close(_ id: NSNumber, code: NSNumber?, reason: String?, callback: LynxCallbackBlock?) {
|
|
82
|
+
WebSocketTaskStore.shared.close(
|
|
83
|
+
id: id.intValue,
|
|
84
|
+
code: code?.intValue ?? 1000,
|
|
85
|
+
reason: reason ?? ""
|
|
86
|
+
)
|
|
87
|
+
callback?(NSNull())
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Lynx
|
|
3
|
+
|
|
4
|
+
/// Per-`LynxView` publisher that pumps `WebSocketEventBus` payloads into JS
|
|
5
|
+
/// via `LynxView.sendGlobalEvent("__sigxWebSocketEvent", [...])`.
|
|
6
|
+
///
|
|
7
|
+
/// One instance per LynxView; instantiated by the generated
|
|
8
|
+
/// `GeneratedLifecyclePublishers.attachAll(to:)` and retained for the
|
|
9
|
+
/// LynxView's lifetime. The bus is global so opening a socket from one
|
|
10
|
+
/// LynxView and reading it from another (via the JS shim) works, but in
|
|
11
|
+
/// practice each LynxView holds its own JS heap so events are delivered to
|
|
12
|
+
/// the matching view only.
|
|
13
|
+
final class WebSocketPublisher {
|
|
14
|
+
|
|
15
|
+
private weak var lynxView: LynxView?
|
|
16
|
+
private var token: UUID?
|
|
17
|
+
|
|
18
|
+
init(lynxView: LynxView) {
|
|
19
|
+
self.lynxView = lynxView
|
|
20
|
+
self.token = WebSocketEventBus.shared.addListener { [weak self] payload in
|
|
21
|
+
guard let view = self?.lynxView else { return }
|
|
22
|
+
// sendGlobalEvent expects an array of params; pass a single
|
|
23
|
+
// dictionary as the only param, matching what the JS shim
|
|
24
|
+
// expects (it reads the first arg as `NativeEvent`).
|
|
25
|
+
view.sendGlobalEvent("__sigxWebSocketEvent", withParams: [payload])
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
deinit {
|
|
30
|
+
if let token = token {
|
|
31
|
+
WebSocketEventBus.shared.removeListener(token)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|