@neurodevs/node-lsl 14.1.5 → 16.0.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/build/__tests__/AbstractPackageTest.d.ts +1 -0
- package/build/__tests__/AbstractPackageTest.js +7 -0
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LslStreamInfo.test.d.ts +1 -0
- package/build/__tests__/impl/LslStreamInfo.test.js +33 -6
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.d.ts +10 -2
- package/build/__tests__/impl/LslWebSocketBridge.test.js +78 -12
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/impl/LslStreamInfo.d.ts +17 -8
- package/build/impl/LslStreamInfo.js +12 -6
- package/build/impl/LslStreamInfo.js.map +1 -1
- package/build/impl/LslStreamInlet.js +2 -1
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/impl/LslStreamOutlet.d.ts +3 -2
- package/build/impl/LslStreamOutlet.js +4 -4
- package/build/impl/LslStreamOutlet.js.map +1 -1
- package/build/impl/LslWebSocketBridge.d.ts +18 -6
- package/build/impl/LslWebSocketBridge.js +69 -27
- package/build/impl/LslWebSocketBridge.js.map +1 -1
- package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +8 -0
- package/build/testDoubles/StreamInfo/FakeStreamInfo.js +11 -0
- package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
- package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +2 -0
- package/build/testDoubles/StreamInfo/SpyStreamInfo.js +5 -0
- package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +1 -1
- package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.d.ts +2 -0
- package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js +18 -4
- package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +1 -1
- package/build/testDoubles/WebSockets/FakeWebSocket.d.ts +4 -0
- package/build/testDoubles/WebSockets/FakeWebSocket.js +12 -1
- package/build/testDoubles/WebSockets/FakeWebSocket.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/AbstractPackageTest.ts +10 -0
- package/src/__tests__/impl/LslStreamInfo.test.ts +40 -6
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +111 -13
- package/src/impl/LslStreamInfo.ts +28 -12
- package/src/impl/LslStreamInlet.ts +4 -1
- package/src/impl/LslStreamOutlet.ts +6 -5
- package/src/impl/LslWebSocketBridge.ts +104 -38
- package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +14 -0
- package/src/testDoubles/StreamInfo/SpyStreamInfo.ts +7 -0
- package/src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts +24 -5
- package/src/testDoubles/WebSockets/FakeWebSocket.ts +14 -1
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
import { WebSocketServer } from 'ws';
|
|
1
|
+
import WebSocket, { WebSocketServer } from 'ws';
|
|
2
2
|
import { ChannelFormat } from './LiblslAdapter.js';
|
|
3
3
|
import { StreamInlet } from './LslStreamInlet.js';
|
|
4
4
|
export default class LslWebSocketBridge implements WebSocketBridge {
|
|
5
5
|
static Class?: WebSocketBridgeConstructor;
|
|
6
|
+
static WS: typeof WebSocket;
|
|
6
7
|
static WSS: typeof import("ws").Server;
|
|
7
8
|
private inlet;
|
|
8
|
-
private
|
|
9
|
+
private localServer?;
|
|
10
|
+
private remoteSockets?;
|
|
9
11
|
private isDestroyed;
|
|
10
12
|
protected constructor(options: WebSocketBridgeConstructorOptions);
|
|
11
13
|
static Create(options: WebSocketBridgeOptions): WebSocketBridge;
|
|
14
|
+
private throwIfNoLocalServerOrRemoteSockets;
|
|
15
|
+
private readonly insufficientOptionsError;
|
|
12
16
|
activate(): void;
|
|
13
17
|
private throwIfBridgeIsDestroyed;
|
|
18
|
+
private readonly cannotActivateMessage;
|
|
14
19
|
private startPullingData;
|
|
15
20
|
deactivate(): void;
|
|
21
|
+
private readonly cannotDeactivateMessage;
|
|
16
22
|
private stopPullingData;
|
|
17
23
|
destroy(): void;
|
|
18
24
|
private destroyBoundInlet;
|
|
19
|
-
private
|
|
25
|
+
private closeLocalServerIfExists;
|
|
26
|
+
private closeRemoteSocketsIfExists;
|
|
20
27
|
private static createOnDataCallback;
|
|
21
28
|
private static broadcastToClients;
|
|
22
|
-
private static
|
|
29
|
+
private static sendToSockets;
|
|
30
|
+
private static createSocketsFrom;
|
|
31
|
+
private static WebSocket;
|
|
23
32
|
private static WebSocketServer;
|
|
33
|
+
private static LslStreamInlet;
|
|
24
34
|
}
|
|
25
35
|
export interface WebSocketBridge {
|
|
26
36
|
activate(): void;
|
|
@@ -36,9 +46,11 @@ export interface WebSocketBridgeOptions {
|
|
|
36
46
|
name?: string;
|
|
37
47
|
type?: string;
|
|
38
48
|
sourceId?: string;
|
|
39
|
-
|
|
49
|
+
listenPort?: number;
|
|
50
|
+
connectUrls?: string | string[];
|
|
40
51
|
}
|
|
41
52
|
export interface WebSocketBridgeConstructorOptions extends WebSocketBridgeOptions {
|
|
42
53
|
inlet: StreamInlet;
|
|
43
|
-
|
|
54
|
+
localServer?: WebSocketServer;
|
|
55
|
+
remoteSockets?: WebSocket[];
|
|
44
56
|
}
|
|
@@ -1,72 +1,114 @@
|
|
|
1
|
-
import { WebSocketServer } from 'ws';
|
|
1
|
+
import WebSocket, { WebSocketServer } from 'ws';
|
|
2
2
|
import LslStreamInlet from './LslStreamInlet.js';
|
|
3
3
|
export default class LslWebSocketBridge {
|
|
4
4
|
static Class;
|
|
5
|
+
static WS = WebSocket;
|
|
5
6
|
static WSS = WebSocketServer;
|
|
6
7
|
inlet;
|
|
7
|
-
|
|
8
|
+
localServer;
|
|
9
|
+
remoteSockets;
|
|
8
10
|
isDestroyed = false;
|
|
9
11
|
constructor(options) {
|
|
10
|
-
const { inlet,
|
|
12
|
+
const { inlet, localServer, remoteSockets } = options;
|
|
11
13
|
this.inlet = inlet;
|
|
12
|
-
this.
|
|
14
|
+
this.localServer = localServer;
|
|
15
|
+
this.remoteSockets = remoteSockets;
|
|
16
|
+
this.throwIfNoLocalServerOrRemoteSockets();
|
|
13
17
|
}
|
|
14
18
|
static Create(options) {
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
+
const { listenPort, connectUrls, ...rest } = options;
|
|
20
|
+
const inletOptions = rest;
|
|
21
|
+
const localServer = this.WebSocketServer(listenPort);
|
|
22
|
+
const remoteSockets = this.createSocketsFrom(connectUrls);
|
|
23
|
+
const inlet = this.LslStreamInlet(inletOptions, localServer, remoteSockets);
|
|
24
|
+
return new (this.Class ?? this)({
|
|
25
|
+
...options,
|
|
26
|
+
inlet,
|
|
27
|
+
localServer,
|
|
28
|
+
remoteSockets,
|
|
29
|
+
});
|
|
19
30
|
}
|
|
31
|
+
throwIfNoLocalServerOrRemoteSockets() {
|
|
32
|
+
if (!(this.localServer || this.remoteSockets)) {
|
|
33
|
+
throw new Error(this.insufficientOptionsError);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
insufficientOptionsError = `At least one of listenPort or connectUrls must be provided!`;
|
|
20
37
|
activate() {
|
|
21
|
-
this.throwIfBridgeIsDestroyed();
|
|
38
|
+
this.throwIfBridgeIsDestroyed(this.cannotActivateMessage);
|
|
22
39
|
this.startPullingData();
|
|
23
40
|
}
|
|
24
|
-
throwIfBridgeIsDestroyed() {
|
|
41
|
+
throwIfBridgeIsDestroyed(err) {
|
|
25
42
|
if (this.isDestroyed) {
|
|
26
|
-
throw new Error(
|
|
43
|
+
throw new Error(err);
|
|
27
44
|
}
|
|
28
45
|
}
|
|
46
|
+
cannotActivateMessage = `\n\n Cannot activate bridge after destroying it! \n\n Please create and activate a new instance. \n`;
|
|
29
47
|
startPullingData() {
|
|
30
48
|
this.inlet.startPulling();
|
|
31
49
|
}
|
|
32
50
|
deactivate() {
|
|
51
|
+
this.throwIfBridgeIsDestroyed(this.cannotDeactivateMessage);
|
|
33
52
|
this.stopPullingData();
|
|
34
53
|
}
|
|
54
|
+
cannotDeactivateMessage = `\n\n Cannot deactivate bridge after destroying it! \n\n Please create and activate a new instance. \n`;
|
|
35
55
|
stopPullingData() {
|
|
36
56
|
this.inlet.stopPulling();
|
|
37
57
|
}
|
|
38
58
|
destroy() {
|
|
39
59
|
this.destroyBoundInlet();
|
|
40
|
-
this.
|
|
60
|
+
this.closeLocalServerIfExists();
|
|
61
|
+
this.closeRemoteSocketsIfExists();
|
|
41
62
|
this.isDestroyed = true;
|
|
42
63
|
}
|
|
43
64
|
destroyBoundInlet() {
|
|
44
65
|
this.inlet.destroy();
|
|
45
66
|
}
|
|
46
|
-
|
|
47
|
-
this.
|
|
67
|
+
closeLocalServerIfExists() {
|
|
68
|
+
this.localServer?.close();
|
|
69
|
+
}
|
|
70
|
+
closeRemoteSocketsIfExists() {
|
|
71
|
+
this.remoteSockets?.forEach((socket) => socket.close());
|
|
48
72
|
}
|
|
49
|
-
static createOnDataCallback(
|
|
73
|
+
static createOnDataCallback(localServer, remoteSockets) {
|
|
50
74
|
return (samples, timestamps) => {
|
|
51
|
-
|
|
75
|
+
const payload = JSON.stringify({ samples, timestamps });
|
|
76
|
+
if (localServer) {
|
|
77
|
+
this.broadcastToClients(localServer, payload);
|
|
78
|
+
}
|
|
79
|
+
if (remoteSockets) {
|
|
80
|
+
this.sendToSockets(remoteSockets, payload);
|
|
81
|
+
}
|
|
52
82
|
};
|
|
53
83
|
}
|
|
54
|
-
static broadcastToClients(
|
|
55
|
-
for (const client of
|
|
84
|
+
static broadcastToClients(localServer, payload) {
|
|
85
|
+
for (const client of localServer.clients) {
|
|
56
86
|
if (client.readyState === WebSocket.OPEN) {
|
|
57
|
-
client.send(
|
|
58
|
-
samples,
|
|
59
|
-
timestamps,
|
|
60
|
-
}));
|
|
87
|
+
client.send(payload);
|
|
61
88
|
}
|
|
62
89
|
}
|
|
63
90
|
}
|
|
64
|
-
static
|
|
65
|
-
const
|
|
66
|
-
|
|
91
|
+
static sendToSockets(remoteSockets, payload) {
|
|
92
|
+
for (const socket of remoteSockets) {
|
|
93
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
94
|
+
socket.send(payload);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
static createSocketsFrom(connectUrls) {
|
|
99
|
+
return connectUrls
|
|
100
|
+
? (Array.isArray(connectUrls) ? connectUrls : [connectUrls]).map((url) => this.WebSocket(url))
|
|
101
|
+
: undefined;
|
|
67
102
|
}
|
|
68
|
-
static
|
|
69
|
-
return new this.
|
|
103
|
+
static WebSocket(url) {
|
|
104
|
+
return new this.WS(url);
|
|
105
|
+
}
|
|
106
|
+
static WebSocketServer(listenPort) {
|
|
107
|
+
return listenPort ? new this.WSS({ port: listenPort }) : undefined;
|
|
108
|
+
}
|
|
109
|
+
static LslStreamInlet(options, localServer, remoteSockets) {
|
|
110
|
+
const onData = this.createOnDataCallback(localServer, remoteSockets);
|
|
111
|
+
return LslStreamInlet.Create(options, onData);
|
|
70
112
|
}
|
|
71
113
|
}
|
|
72
114
|
//# sourceMappingURL=LslWebSocketBridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,16 @@ export default class FakeStreamInfo implements StreamInfo {
|
|
|
4
4
|
static callsToConstructor: StreamInfoOptions[];
|
|
5
5
|
static numCallsToDestroy: number;
|
|
6
6
|
static boundStreamInfo: BoundStreamInfo;
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
sourceId: string;
|
|
10
|
+
channelNames: string[];
|
|
11
|
+
channelFormat: "float32";
|
|
12
|
+
sampleRateHz: number;
|
|
13
|
+
units: string;
|
|
7
14
|
constructor(options: StreamInfoOptions);
|
|
8
15
|
destroy(): void;
|
|
16
|
+
get channelCount(): number;
|
|
9
17
|
get boundStreamInfo(): BoundStreamInfo;
|
|
10
18
|
static resetTestDouble(): void;
|
|
11
19
|
}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
import generateId from '@neurodevs/generate-id';
|
|
1
2
|
export default class FakeStreamInfo {
|
|
2
3
|
static callsToConstructor = [];
|
|
3
4
|
static numCallsToDestroy = 0;
|
|
4
5
|
static boundStreamInfo = {};
|
|
6
|
+
name = generateId();
|
|
7
|
+
type = generateId();
|
|
8
|
+
sourceId = generateId();
|
|
9
|
+
channelNames = [generateId(), generateId()];
|
|
10
|
+
channelFormat = 'float32';
|
|
11
|
+
sampleRateHz = 0;
|
|
12
|
+
units = 'N/A';
|
|
5
13
|
constructor(options) {
|
|
6
14
|
FakeStreamInfo.callsToConstructor.push(options);
|
|
7
15
|
}
|
|
8
16
|
destroy() {
|
|
9
17
|
FakeStreamInfo.numCallsToDestroy++;
|
|
10
18
|
}
|
|
19
|
+
get channelCount() {
|
|
20
|
+
return this.channelNames.length;
|
|
21
|
+
}
|
|
11
22
|
get boundStreamInfo() {
|
|
12
23
|
return FakeStreamInfo.boundStreamInfo;
|
|
13
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAK/C,MAAM,CAAC,OAAO,OAAO,cAAc;IACxB,MAAM,CAAC,kBAAkB,GAAwB,EAAE,CAAA;IACnD,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,GAAG,EAAqB,CAAA;IAE9C,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,QAAQ,GAAG,UAAU,EAAE,CAAA;IACvB,YAAY,GAAa,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IACrD,aAAa,GAAG,SAAkB,CAAA;IAClC,YAAY,GAAG,CAAC,CAAA;IAChB,KAAK,GAAG,KAAK,CAAA;IAEpB,YAAmB,OAA0B;QACzC,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAEM,OAAO;QACV,cAAc,CAAC,iBAAiB,EAAE,CAAA;IACtC,CAAC;IAED,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAA;IACnC,CAAC;IAED,IAAW,eAAe;QACtB,OAAO,cAAc,CAAC,eAAe,CAAA;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,cAAc,CAAC,kBAAkB,GAAG,EAAE,CAAA;QACtC,cAAc,CAAC,iBAAiB,GAAG,CAAC,CAAA;IACxC,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import LslStreamInfo, { StreamInfoOptions } from '../../impl/LslStreamInfo.js';
|
|
2
2
|
export default class SpyStreamInfo extends LslStreamInfo {
|
|
3
|
+
static numCallsToConstructor: number;
|
|
3
4
|
constructor(options: StreamInfoOptions);
|
|
4
5
|
getBoundInfo(): import("../../index.js").BoundStreamInfo;
|
|
5
6
|
getName(): string;
|
|
6
7
|
getType(): string;
|
|
7
8
|
getSourceId(): string;
|
|
8
9
|
getUnits(): string;
|
|
10
|
+
static resetTestDouble(): void;
|
|
9
11
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import LslStreamInfo from '../../impl/LslStreamInfo.js';
|
|
2
2
|
export default class SpyStreamInfo extends LslStreamInfo {
|
|
3
|
+
static numCallsToConstructor = 0;
|
|
3
4
|
constructor(options) {
|
|
4
5
|
super(options);
|
|
6
|
+
SpyStreamInfo.numCallsToConstructor++;
|
|
5
7
|
}
|
|
6
8
|
getBoundInfo() {
|
|
7
9
|
return this.boundInfo;
|
|
@@ -18,5 +20,8 @@ export default class SpyStreamInfo extends LslStreamInfo {
|
|
|
18
20
|
getUnits() {
|
|
19
21
|
return this.units;
|
|
20
22
|
}
|
|
23
|
+
static resetTestDouble() {
|
|
24
|
+
SpyStreamInfo.numCallsToConstructor = 0;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
//# sourceMappingURL=SpyStreamInfo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;
|
|
1
|
+
{"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;IAC7C,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAEvC,YAAmB,OAA0B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,aAAa,CAAC,qBAAqB,EAAE,CAAA;IACzC,CAAC;IAEM,YAAY;QACf,OAAO,IAAI,CAAC,SAAS,CAAA;IACzB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,aAAa,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAC3C,CAAC"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import LslWebSocketBridge from '../../impl/LslWebSocketBridge.js';
|
|
2
|
+
import FakeWebSocket from '../WebSockets/FakeWebSocket.js';
|
|
3
|
+
import FakeWebSocketServer from '../WebSockets/FakeWebSocketServer.js';
|
|
1
4
|
export default class FakeWebSocketBridge {
|
|
2
5
|
static numCallsToConstructor = 0;
|
|
3
6
|
static numCallsToActivate = 0;
|
|
@@ -16,10 +19,21 @@ export default class FakeWebSocketBridge {
|
|
|
16
19
|
FakeWebSocketBridge.numCallsToDestroy++;
|
|
17
20
|
}
|
|
18
21
|
static resetTestDouble() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
this.numCallsToConstructor = 0;
|
|
23
|
+
this.numCallsToActivate = 0;
|
|
24
|
+
this.numCallsToDeactivate = 0;
|
|
25
|
+
this.numCallsToDestroy = 0;
|
|
26
|
+
this.setFakeWebSocket();
|
|
27
|
+
this.setFakeWebSocketServer();
|
|
28
|
+
}
|
|
29
|
+
static setFakeWebSocket() {
|
|
30
|
+
LslWebSocketBridge.WS = FakeWebSocket;
|
|
31
|
+
FakeWebSocket.resetTestDouble();
|
|
32
|
+
}
|
|
33
|
+
static setFakeWebSocketServer() {
|
|
34
|
+
LslWebSocketBridge.WSS =
|
|
35
|
+
FakeWebSocketServer;
|
|
36
|
+
FakeWebSocketServer.resetTestDouble();
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
39
|
//# sourceMappingURL=FakeWebSocketBridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeWebSocketBridge.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FakeWebSocketBridge.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts"],"names":[],"mappings":"AACA,OAAO,kBAEN,MAAM,kCAAkC,CAAA;AACzC,OAAO,aAAa,MAAM,gCAAgC,CAAA;AAC1D,OAAO,mBAAmB,MAAM,sCAAsC,CAAA;AAEtE,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAC7B,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAChC,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAA;IAC7B,MAAM,CAAC,oBAAoB,GAAG,CAAC,CAAA;IAC/B,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAEnC;QACI,mBAAmB,CAAC,qBAAqB,EAAE,CAAA;IAC/C,CAAC;IAEM,QAAQ;QACX,mBAAmB,CAAC,kBAAkB,EAAE,CAAA;IAC5C,CAAC;IAEM,UAAU;QACb,mBAAmB,CAAC,oBAAoB,EAAE,CAAA;IAC9C,CAAC;IAEM,OAAO;QACV,mBAAmB,CAAC,iBAAiB,EAAE,CAAA;IAC3C,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,IAAI,CAAC,qBAAqB,GAAG,CAAC,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAA;QAC7B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAA;QAE1B,IAAI,CAAC,gBAAgB,EAAE,CAAA;QACvB,IAAI,CAAC,sBAAsB,EAAE,CAAA;IACjC,CAAC;IAEO,MAAM,CAAC,gBAAgB;QAC3B,kBAAkB,CAAC,EAAE,GAAG,aAA4C,CAAA;QACpE,aAAa,CAAC,eAAe,EAAE,CAAA;IACnC,CAAC;IAEO,MAAM,CAAC,sBAAsB;QACjC,kBAAkB,CAAC,GAAG;YAClB,mBAAwD,CAAA;QAC5D,mBAAmB,CAAC,eAAe,EAAE,CAAA;IACzC,CAAC"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export default class FakeWebSocket {
|
|
2
|
+
static callsToConstructor: (string | undefined)[];
|
|
2
3
|
static callsToSend: {
|
|
3
4
|
id: string;
|
|
4
5
|
data: unknown;
|
|
5
6
|
}[];
|
|
7
|
+
static numCallsToClose: number;
|
|
6
8
|
readyState: number;
|
|
7
9
|
id: string;
|
|
10
|
+
constructor(url?: string);
|
|
8
11
|
send(data: unknown): void;
|
|
12
|
+
close(): void;
|
|
9
13
|
static resetTestDouble(): void;
|
|
10
14
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import generateId from '@neurodevs/generate-id';
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
3
|
export default class FakeWebSocket {
|
|
4
|
+
static callsToConstructor = [];
|
|
4
5
|
static callsToSend = [];
|
|
6
|
+
static numCallsToClose = 0;
|
|
5
7
|
readyState = WebSocket.OPEN;
|
|
6
8
|
id = generateId();
|
|
9
|
+
constructor(url) {
|
|
10
|
+
FakeWebSocket.callsToConstructor.push(url);
|
|
11
|
+
}
|
|
7
12
|
send(data) {
|
|
8
13
|
FakeWebSocket.callsToSend.push({ id: this.id, data });
|
|
9
14
|
}
|
|
15
|
+
close() {
|
|
16
|
+
FakeWebSocket.numCallsToClose++;
|
|
17
|
+
this.readyState = WebSocket.CLOSED;
|
|
18
|
+
}
|
|
10
19
|
static resetTestDouble() {
|
|
11
|
-
|
|
20
|
+
this.callsToConstructor = [];
|
|
21
|
+
this.callsToSend = [];
|
|
22
|
+
this.numCallsToClose = 0;
|
|
12
23
|
}
|
|
13
24
|
}
|
|
14
25
|
//# sourceMappingURL=FakeWebSocket.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeWebSocket.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSockets/FakeWebSocket.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,SAAS,MAAM,IAAI,CAAA;AAE1B,MAAM,CAAC,OAAO,OAAO,aAAa;IACvB,MAAM,CAAC,WAAW,GAAoC,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"FakeWebSocket.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSockets/FakeWebSocket.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,SAAS,MAAM,IAAI,CAAA;AAE1B,MAAM,CAAC,OAAO,OAAO,aAAa;IACvB,MAAM,CAAC,kBAAkB,GAA2B,EAAE,CAAA;IACtD,MAAM,CAAC,WAAW,GAAoC,EAAE,CAAA;IACxD,MAAM,CAAC,eAAe,GAAG,CAAC,CAAA;IAE1B,UAAU,GAAW,SAAS,CAAC,IAAI,CAAA;IACnC,EAAE,GAAG,UAAU,EAAE,CAAA;IAExB,YAAmB,GAAY;QAC3B,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC9C,CAAC;IAEM,IAAI,CAAC,IAAa;QACrB,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC;IAEM,KAAK;QACR,aAAa,CAAC,eAAe,EAAE,CAAA;QAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,MAAM,CAAA;IACtC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAA;QAC5B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QACrB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;IAC5B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import AbstractModuleTest from '@neurodevs/node-tdd'
|
|
2
|
+
import WebSocket from 'ws'
|
|
2
3
|
|
|
3
4
|
import { Server } from 'ws'
|
|
4
5
|
import LiblslAdapter from '../impl/LiblslAdapter.js'
|
|
@@ -18,6 +19,7 @@ import FakeStreamInlet from '../testDoubles/StreamInlet/FakeStreamInlet.js'
|
|
|
18
19
|
import { SpyStreamInlet } from '../testDoubles/StreamInlet/SpyStreamInlet.js'
|
|
19
20
|
import FakeStreamOutlet from '../testDoubles/StreamOutlet/FakeStreamOutlet.js'
|
|
20
21
|
import SpyLslWebSocketBridge from '../testDoubles/WebSocketBridge/SpyLslWebSocketBridge.js'
|
|
22
|
+
import FakeWebSocket from '../testDoubles/WebSockets/FakeWebSocket.js'
|
|
21
23
|
import FakeWebSocketServer from '../testDoubles/WebSockets/FakeWebSocketServer.js'
|
|
22
24
|
|
|
23
25
|
export default class AbstractPackageTest extends AbstractModuleTest {
|
|
@@ -38,11 +40,14 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
38
40
|
|
|
39
41
|
protected static setSpyStreamInfo() {
|
|
40
42
|
LslStreamInfo.Class = SpyStreamInfo
|
|
43
|
+
SpyStreamInfo.resetTestDouble()
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
protected static setFakeStreamInfo() {
|
|
44
47
|
LslStreamInfo.Class = FakeStreamInfo
|
|
45
48
|
FakeStreamInfo.resetTestDouble()
|
|
49
|
+
|
|
50
|
+
LslStreamInfo['instanceCache'] = {}
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
protected static setSpyStreamInlet() {
|
|
@@ -67,6 +72,11 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
67
72
|
LslWebSocketBridge.Class = SpyLslWebSocketBridge
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
protected static setFakeWebSocket() {
|
|
76
|
+
LslWebSocketBridge.WS = FakeWebSocket as unknown as typeof WebSocket
|
|
77
|
+
FakeWebSocket.resetTestDouble()
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
protected static setFakeWebSocketServer() {
|
|
71
81
|
LslWebSocketBridge.WSS = FakeWebSocketServer as unknown as typeof Server
|
|
72
82
|
FakeWebSocketServer.resetTestDouble()
|
|
@@ -13,6 +13,8 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
13
13
|
|
|
14
14
|
this.setSpyStreamInfo()
|
|
15
15
|
|
|
16
|
+
LslStreamInfo['instanceCache'] = {}
|
|
17
|
+
|
|
16
18
|
this.instance = this.LslStreamInfo()
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -23,8 +25,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
23
25
|
|
|
24
26
|
@test()
|
|
25
27
|
protected static async generatesUniqueNameIfNotProvided() {
|
|
26
|
-
const instance1 = this.LslStreamInfo({
|
|
27
|
-
|
|
28
|
+
const instance1 = this.LslStreamInfo({
|
|
29
|
+
name: undefined,
|
|
30
|
+
type: this.generateId(),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const instance2 = this.LslStreamInfo({
|
|
34
|
+
name: undefined,
|
|
35
|
+
type: this.generateId(),
|
|
36
|
+
})
|
|
28
37
|
|
|
29
38
|
assert.isNotEqual(
|
|
30
39
|
instance1.getName(),
|
|
@@ -58,8 +67,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
58
67
|
|
|
59
68
|
@test()
|
|
60
69
|
protected static async generatesUniqueTypeIfNotProvided() {
|
|
61
|
-
const instance1 = this.LslStreamInfo({
|
|
62
|
-
|
|
70
|
+
const instance1 = this.LslStreamInfo({
|
|
71
|
+
type: undefined,
|
|
72
|
+
name: this.generateId(),
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const instance2 = this.LslStreamInfo({
|
|
76
|
+
type: undefined,
|
|
77
|
+
name: this.generateId(),
|
|
78
|
+
})
|
|
63
79
|
|
|
64
80
|
assert.isNotEqual(
|
|
65
81
|
instance1.getType(),
|
|
@@ -82,8 +98,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
82
98
|
|
|
83
99
|
@test()
|
|
84
100
|
protected static async generatesUniqueSourceIdIfNotProvided() {
|
|
85
|
-
const instance1 = this.LslStreamInfo({
|
|
86
|
-
|
|
101
|
+
const instance1 = this.LslStreamInfo({
|
|
102
|
+
sourceId: undefined,
|
|
103
|
+
name: this.generateId(),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const instance2 = this.LslStreamInfo({
|
|
107
|
+
sourceId: undefined,
|
|
108
|
+
name: this.generateId(),
|
|
109
|
+
})
|
|
87
110
|
|
|
88
111
|
assert.isNotEqual(
|
|
89
112
|
instance1.getSourceId(),
|
|
@@ -192,6 +215,17 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
192
215
|
)
|
|
193
216
|
}
|
|
194
217
|
|
|
218
|
+
@test()
|
|
219
|
+
protected static async cachesInfoIfPassedSameOptions() {
|
|
220
|
+
this.LslStreamInfo()
|
|
221
|
+
|
|
222
|
+
assert.isEqual(
|
|
223
|
+
SpyStreamInfo.numCallsToConstructor,
|
|
224
|
+
1,
|
|
225
|
+
'Did not cache stream info!'
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
195
229
|
private static readonly defaultOptions = {
|
|
196
230
|
name: this.generateId(),
|
|
197
231
|
type: this.generateId(),
|