@webqit/port-plus 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/.github/FUNDING.yml +13 -0
- package/.github/workflows/publish.yml +48 -0
- package/.gitignore +6 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/dist/index.html +51 -0
- package/dist/main.js +2 -0
- package/dist/main.js.map +7 -0
- package/package.json +53 -0
- package/src/BroadcastChannelPlus.js +25 -0
- package/src/MessageChannelPlus.js +16 -0
- package/src/MessageEventPlus.js +94 -0
- package/src/MessagePortPlus.js +829 -0
- package/src/RelayPort.js +50 -0
- package/src/StarPort.js +74 -0
- package/src/WebSocketPort.js +47 -0
- package/src/index.browser.js +2 -0
- package/src/index.js +7 -0
- package/test/basic.test.js +38 -0
package/src/RelayPort.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { StarPort } from './StarPort.js';
|
|
2
|
+
|
|
3
|
+
export class RelayPort extends StarPort {
|
|
4
|
+
|
|
5
|
+
#namespace;
|
|
6
|
+
get namespace() { return this.#namespace; }
|
|
7
|
+
|
|
8
|
+
constructor(namespace = null) {
|
|
9
|
+
super();
|
|
10
|
+
this.#namespace = namespace;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
addPort(portPlus, { resolveData = null } = {}) {
|
|
14
|
+
const $resolveData = (data, ...args) => {
|
|
15
|
+
if (resolveData) return resolveData(data, ...args);
|
|
16
|
+
return data;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Add port and forward its messages back to this relay instance
|
|
20
|
+
const unadd = super.addPort(portPlus, { enableBubbling: false });
|
|
21
|
+
const unforward = portPlus.forwardPort('*', this, { bidirectional: false, resolveData: $resolveData, namespace1: this.namespace, namespace2: this.namespace });
|
|
22
|
+
|
|
23
|
+
const messageType_ping = this.namespace
|
|
24
|
+
&& `${this.namespace}:message`
|
|
25
|
+
|| 'message';
|
|
26
|
+
|
|
27
|
+
// PING: joins
|
|
28
|
+
this.postMessage(
|
|
29
|
+
$resolveData({ event: 'joins' }, portPlus, this),
|
|
30
|
+
{ type: messageType_ping, relayedFrom: portPlus }
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const leaves = () => {
|
|
34
|
+
// PING: leaves
|
|
35
|
+
this.postMessage(
|
|
36
|
+
$resolveData({ event: 'leaves' }, portPlus, this),
|
|
37
|
+
{ type: messageType_ping, relayedFrom: portPlus }
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
leaves();
|
|
43
|
+
unforward();
|
|
44
|
+
unadd();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
portPlus.readyStateChange('close').then(cleanup);
|
|
48
|
+
return cleanup;
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/StarPort.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MessagePortPlus, _meta, _options } from './MessagePortPlus.js';
|
|
2
|
+
|
|
3
|
+
export class StarPort extends MessagePortPlus {
|
|
4
|
+
|
|
5
|
+
#ports = new Set;
|
|
6
|
+
|
|
7
|
+
get length() { return this.#ports.size; }
|
|
8
|
+
|
|
9
|
+
[Symbol.iterator]() { return this.#ports[Symbol.iterator](); }
|
|
10
|
+
|
|
11
|
+
constructor({ autoClose = true } = {}) {
|
|
12
|
+
super({ autoStart: false, postAwaitsOpen: true, autoClose });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
addPort(portPlus, { enableBubbling = true } = {}) {
|
|
16
|
+
if (!(portPlus instanceof MessagePortPlus)) {
|
|
17
|
+
throw new TypeError('Port must be a WQMessagePort instance.');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (this.#ports.has(portPlus)) return;
|
|
21
|
+
this.#ports.add(portPlus); // @ORDER: 1
|
|
22
|
+
|
|
23
|
+
const portPlusMeta = _meta(portPlus);
|
|
24
|
+
|
|
25
|
+
if (enableBubbling) {
|
|
26
|
+
if (portPlusMeta.get('parentNode')) {
|
|
27
|
+
throw new TypeError('Incoming port already has a parent node.');
|
|
28
|
+
}
|
|
29
|
+
portPlusMeta.set('parentNode', this); // @ORDER: 2
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
portPlus.readyStateChange('open').then(() => this.start());
|
|
33
|
+
portPlus.readyStateChange('close').then(cleanup);
|
|
34
|
+
|
|
35
|
+
const cleanup = () => {
|
|
36
|
+
if (!this.#ports.has(portPlus)) return;
|
|
37
|
+
|
|
38
|
+
this.#ports.delete(portPlus);
|
|
39
|
+
|
|
40
|
+
if (enableBubbling
|
|
41
|
+
&& portPlusMeta.get('parentNode') === this) {
|
|
42
|
+
portPlusMeta.set('parentNode', null);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this.#ports.size === 0
|
|
46
|
+
&& _options(this).autoClose) {
|
|
47
|
+
this.close();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return cleanup;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
findPort(callback) {
|
|
55
|
+
for (const portPlus of this.#ports) {
|
|
56
|
+
if (callback(portPlus)) return portPlus;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// --------
|
|
61
|
+
|
|
62
|
+
_postMessage(payload, portOptions, relayedFrom) {
|
|
63
|
+
for (const portPlus of this.#ports) {
|
|
64
|
+
if (portPlus === relayedFrom) continue;
|
|
65
|
+
portPlus.postMessage(payload, portOptions);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
close(...args) {
|
|
70
|
+
for (const portPlus of this.#ports) {
|
|
71
|
+
portPlus.close?.(...args);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { _isObject } from '@webqit/util/js/index.js';
|
|
2
|
+
import {
|
|
3
|
+
_meta,
|
|
4
|
+
MessagePortPlusMockPortsMixin,
|
|
5
|
+
} from './MessagePortPlus.js';
|
|
6
|
+
|
|
7
|
+
export class WebSocketPort extends MessagePortPlusMockPortsMixin(EventTarget) {
|
|
8
|
+
|
|
9
|
+
#ws;
|
|
10
|
+
|
|
11
|
+
constructor(ws, { autoStart = true, naturalOpen = true, postAwaitsOpen = false } = {}) {
|
|
12
|
+
super();
|
|
13
|
+
this.#ws = typeof ws === 'string' ? new WebSocket(ws) : ws;
|
|
14
|
+
|
|
15
|
+
const portPlusMeta = _meta(this);
|
|
16
|
+
portPlusMeta.set('options', { autoStart, naturalOpen, postAwaitsOpen });
|
|
17
|
+
// Must come before upgradeEvents()
|
|
18
|
+
|
|
19
|
+
this.constructor/* IMPORTANT */.upgradeEvents(this.#ws, this);
|
|
20
|
+
|
|
21
|
+
if (naturalOpen
|
|
22
|
+
&& autoStart
|
|
23
|
+
&& this.#ws.readyState === WebSocket.OPEN) {
|
|
24
|
+
this.start();
|
|
25
|
+
}
|
|
26
|
+
if (this.#ws.readyState === WebSocket.CLOSED) {
|
|
27
|
+
try { this.close(); } catch(e) {}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static _hydrateMessage(portPlus, event) {
|
|
32
|
+
try {
|
|
33
|
+
let data;
|
|
34
|
+
if (typeof event.data === 'string'
|
|
35
|
+
&& _isObject(data = JSON.parse(event.data))
|
|
36
|
+
&& data['.wq']) {
|
|
37
|
+
Object.defineProperty(event, 'data', { value: data, configurable: true });
|
|
38
|
+
return super._hydrateMessage(portPlus, event);
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
return event;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
__postMessage(payload, portOptions) {
|
|
45
|
+
this.#ws.send(JSON.stringify(payload), portOptions);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { BroadcastChannelPlus } from './BroadcastChannelPlus.js';
|
|
2
|
+
export { MessageChannelPlus } from './MessageChannelPlus.js';
|
|
3
|
+
export { MessageEventPlus } from './MessageEventPlus.js';
|
|
4
|
+
export { MessagePortPlus } from './MessagePortPlus.js';
|
|
5
|
+
export { RelayPort } from './RelayPort.js';
|
|
6
|
+
export { StarPort } from './StarPort.js';
|
|
7
|
+
export { WebSocketPort } from './WebSocketPort.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MessagePortPlus, MessageChannelPlus, WebSocketPort, BroadcastChannelPlus } from '../src/index.js';
|
|
2
|
+
|
|
3
|
+
const t = new MessagePortPlus;
|
|
4
|
+
|
|
5
|
+
let m, q = 3;
|
|
6
|
+
|
|
7
|
+
if (q === 1) {
|
|
8
|
+
m = new MessageChannel;
|
|
9
|
+
} else if (q === 2) {
|
|
10
|
+
m = { port1: new BroadcastChannel('test'), port2: new BroadcastChannel('test') };
|
|
11
|
+
} else if (q === 3) {
|
|
12
|
+
m = new MessageChannelPlus({ postAwaitsOpen: true });
|
|
13
|
+
m.port1.__ = 1;
|
|
14
|
+
m.port2.__ = 2;
|
|
15
|
+
} else if (q === 4) {
|
|
16
|
+
m = { port0: new BroadcastChannelPlus('test', { clientServerMode: 'client', postAwaitsOpen: true }), port1: new BroadcastChannelPlus('test', { clientServerMode: 'client', postAwaitsOpen: true }), port2: new BroadcastChannelPlus('test', { clientServerMode: 'server', postAwaitsOpen: true }) };
|
|
17
|
+
m.port0.__ = 0;
|
|
18
|
+
m.port1.__ = 1;
|
|
19
|
+
m.port2.__ = 2;
|
|
20
|
+
console.log('____________________________________');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
m.port0?.addEventListener('open', () => console.log('open0'));
|
|
25
|
+
m.port0?.addEventListener('close', () => console.log('close0'));
|
|
26
|
+
|
|
27
|
+
m.port1.addEventListener('open', () => console.log('open1'));
|
|
28
|
+
m.port1.addEventListener('close', () => console.log('close1'));
|
|
29
|
+
|
|
30
|
+
m.port2.addEventListener('open', () => console.log('open2'));
|
|
31
|
+
m.port2.addEventListener('close', () => console.log('close2'));
|
|
32
|
+
|
|
33
|
+
m.port1.addEventListener('message', (e) => console.log('message', e.data));
|
|
34
|
+
m.port2.postMessage('hello');
|
|
35
|
+
|
|
36
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
37
|
+
//m.port1.close();
|
|
38
|
+
m.port2.close();
|