@neurodevs/node-lsl 5.0.0 → 6.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.
@@ -1,8 +1,13 @@
1
1
  import LslOutletImpl, { LslOutletOptions } from './LslOutlet';
2
2
  export default class TimeMarkerOutletImpl extends LslOutletImpl implements TimeMarkerOutlet {
3
- static Outlet(options?: Partial<LslOutletOptions>): import("./LslOutlet").LslOutlet;
3
+ private isPlaying;
4
+ private waitResolve?;
5
+ private timeout?;
6
+ static TimeMarkerOutlet(options?: Partial<LslOutletOptions>): TimeMarkerOutlet;
4
7
  pushMarkers(markers: DurationMarker[]): Promise<void>;
5
8
  protected wait(durationMs: number): Promise<unknown>;
9
+ private setTimeout;
10
+ stop(): void;
6
11
  }
7
12
  export interface DurationMarker {
8
13
  name: string;
@@ -10,4 +15,5 @@ export interface DurationMarker {
10
15
  }
11
16
  export interface TimeMarkerOutlet {
12
17
  pushMarkers(markers: DurationMarker[]): Promise<void>;
18
+ stop(): void;
13
19
  }
@@ -5,7 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const LslOutlet_1 = __importDefault(require("./LslOutlet"));
7
7
  class TimeMarkerOutletImpl extends LslOutlet_1.default {
8
- static Outlet(options) {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.isPlaying = false;
11
+ }
12
+ static TimeMarkerOutlet(options) {
9
13
  var _a;
10
14
  const defaultOptions = {
11
15
  name: 'Time markers',
@@ -19,16 +23,31 @@ class TimeMarkerOutletImpl extends LslOutlet_1.default {
19
23
  chunkSize: 0,
20
24
  maxBuffered: 0,
21
25
  };
26
+ //@ts-ignore
22
27
  return new ((_a = this.Class) !== null && _a !== void 0 ? _a : this)(Object.assign(Object.assign({}, defaultOptions), options));
23
28
  }
24
29
  async pushMarkers(markers) {
30
+ this.isPlaying = true;
25
31
  for (let marker of markers) {
26
32
  this.pushSample([marker.name]);
27
33
  await this.wait(marker.durationMs);
34
+ if (!this.isPlaying) {
35
+ return;
36
+ }
28
37
  }
29
38
  }
30
39
  async wait(durationMs) {
31
- return new Promise((resolve) => setTimeout(resolve, durationMs));
40
+ return new Promise((resolve) => this.setTimeout(resolve, durationMs));
41
+ }
42
+ setTimeout(resolve, durationMs) {
43
+ this.waitResolve = resolve;
44
+ this.timeout = setTimeout(resolve, durationMs);
45
+ }
46
+ stop() {
47
+ var _a;
48
+ (_a = this.waitResolve) === null || _a === void 0 ? void 0 : _a.call(this);
49
+ clearTimeout(this.timeout);
50
+ this.isPlaying = false;
32
51
  }
33
52
  }
34
53
  exports.default = TimeMarkerOutletImpl;
@@ -1 +1 @@
1
- {"version":3,"file":"TimeMarkerOutlet.js","sourceRoot":"","sources":["../src/TimeMarkerOutlet.ts"],"names":[],"mappings":";;;;;AAAA,4DAA6D;AAE7D,MAAqB,oBACpB,SAAQ,mBAAa;IAGd,MAAM,CAAC,MAAM,CAAC,OAAmC;;QACvD,MAAM,cAAc,GAAG;YACtB,IAAI,EAAE,cAAc;YACpB,IAAI,EAAE,SAAS;YACf,YAAY,EAAE,CAAC,SAAS,CAAC;YACzB,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,QAAQ;YACvB,QAAQ,EAAE,cAAc;YACxB,YAAY,EAAE,KAAK;YACnB,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,CAAC;SACM,CAAA;QAErB,OAAO,IAAI,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,IAAI,CAAC,iCAAM,cAAc,GAAK,OAAO,EAAG,CAAA;IACnE,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,OAAyB;QACjD,KAAK,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;YAC9B,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QACnC,CAAC;IACF,CAAC;IAES,KAAK,CAAC,IAAI,CAAC,UAAkB;QACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;IACjE,CAAC;CACD;AA/BD,uCA+BC"}
1
+ {"version":3,"file":"TimeMarkerOutlet.js","sourceRoot":"","sources":["../src/TimeMarkerOutlet.ts"],"names":[],"mappings":";;;;;AAAA,4DAA6D;AAE7D,MAAqB,oBACpB,SAAQ,mBAAa;IADtB;;QAIS,cAAS,GAAY,KAAK,CAAA;IAwDnC,CAAC;IApDO,MAAM,CAAC,gBAAgB,CAAC,OAAmC;;QACjE,MAAM,cAAc,GAAG;YACtB,IAAI,EAAE,cAAc;YACpB,IAAI,EAAE,SAAS;YACf,YAAY,EAAE,CAAC,SAAS,CAAC;YACzB,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,QAAQ;YACvB,QAAQ,EAAE,cAAc;YACxB,YAAY,EAAE,KAAK;YACnB,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,CAAC;SACM,CAAA;QAErB,YAAY;QACZ,OAAO,IAAI,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,IAAI,CAAC,iCAC3B,cAAc,GACd,OAAO,EACW,CAAA;IACvB,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,OAAyB;QACjD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QAErB,KAAK,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;YAE9B,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;YAElC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACrB,OAAM;YACP,CAAC;QACF,CAAC;IACF,CAAC;IAES,KAAK,CAAC,IAAI,CAAC,UAAkB;QACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;IACtE,CAAC;IAEO,UAAU,CACjB,OAAiC,EACjC,UAAkB;QAElB,IAAI,CAAC,WAAW,GAAG,OAAc,CAAA;QACjC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC/C,CAAC;IAEM,IAAI;;QACV,MAAA,IAAI,CAAC,WAAW,oDAAI,CAAA;QACpB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;IACvB,CAAC;CACD;AA5DD,uCA4DC"}
@@ -7,6 +7,12 @@ export default class TimeMarkerOutletTest extends AbstractSpruceTest {
7
7
  protected static canOverrideDefaultOptions(): Promise<void>;
8
8
  protected static pushingSingleMarkerIncrementsHitCountAndWaitTime(): Promise<void>;
9
9
  protected static pushingTwoMarkersIncrementsHitCountAndWaitTimeTwice(): Promise<void>;
10
- private static generateRandomDurationMarker;
10
+ protected static canStopTimeMarkersMidPush(bailIdx: number): Promise<void>;
11
+ protected static canStartAgainAfterStopping(): Promise<void>;
12
+ protected static doesNotWaitIfStopped(): Promise<void>;
13
+ protected static clearsTheTimeoutOnStop(): Promise<void>;
14
+ private static setupTimeMarkerImpl;
15
+ private static pushTotalMarkers;
16
+ private static generateDurationMarkerValues;
11
17
  private static Outlet;
12
18
  }
@@ -66,25 +66,72 @@ class TimeMarkerOutletTest extends test_utils_1.default {
66
66
  test_utils_1.assert.isEqualDeep(outlet.spyOptions, options);
67
67
  }
68
68
  static async pushingSingleMarkerIncrementsHitCountAndWaitTime() {
69
- const markers = [this.generateRandomDurationMarker()];
69
+ const markers = [this.generateDurationMarkerValues()];
70
70
  await this.outlet.pushMarkers(markers);
71
71
  test_utils_1.assert.isEqual(this.fakeLiblsl.pushSampleStrtHitCount, 1);
72
72
  test_utils_1.assert.isEqual(this.outlet.totalWaitTimeMs, markers[0].durationMs);
73
73
  }
74
74
  static async pushingTwoMarkersIncrementsHitCountAndWaitTimeTwice() {
75
- const markers = [
76
- this.generateRandomDurationMarker(),
77
- this.generateRandomDurationMarker(),
78
- ];
79
- await this.outlet.pushMarkers(markers);
75
+ const markers = await this.pushTotalMarkers(2);
80
76
  test_utils_1.assert.isEqual(this.fakeLiblsl.pushSampleStrtHitCount, 2);
81
77
  test_utils_1.assert.isEqual(this.outlet.totalWaitTimeMs, markers[0].durationMs + markers[1].durationMs);
82
78
  }
83
- static generateRandomDurationMarker() {
84
- return { name: (0, test_utils_1.generateId)(), durationMs: (0, crypto_1.randomInt)(100, 1000) };
79
+ static async canStopTimeMarkersMidPush(bailIdx) {
80
+ let hitCount = 0;
81
+ this.outlet.pushSample = () => {
82
+ hitCount += 1;
83
+ if (hitCount === bailIdx) {
84
+ this.outlet.stop();
85
+ }
86
+ };
87
+ await this.pushTotalMarkers(10);
88
+ test_utils_1.assert.isEqual(hitCount, bailIdx);
89
+ }
90
+ static async canStartAgainAfterStopping() {
91
+ this.outlet.stop();
92
+ let hitCount = 0;
93
+ this.outlet.pushSample = () => {
94
+ hitCount++;
95
+ };
96
+ await this.pushTotalMarkers(10);
97
+ test_utils_1.assert.isEqual(hitCount, 10);
98
+ }
99
+ static async doesNotWaitIfStopped() {
100
+ this.setupTimeMarkerImpl();
101
+ const startMs = Date.now();
102
+ const promise = this.pushTotalMarkers(2, 1000);
103
+ this.outlet.stop();
104
+ await promise;
105
+ const endMs = Date.now();
106
+ test_utils_1.assert.isBelow(endMs - startMs, 10);
107
+ }
108
+ static async clearsTheTimeoutOnStop() {
109
+ this.setupTimeMarkerImpl();
110
+ const promise = this.pushTotalMarkers(2, 100);
111
+ this.outlet.stop();
112
+ this.outlet.pushSample = () => test_utils_1.assert.fail('Should not have been called');
113
+ await promise;
114
+ await this.wait(100);
115
+ }
116
+ static setupTimeMarkerImpl() {
117
+ TimeMarkerOutlet_1.default.Class = TimeMarkerOutlet_1.default;
118
+ this.outlet = this.Outlet();
119
+ }
120
+ static async pushTotalMarkers(total, durationMs) {
121
+ const markers = new Array(total)
122
+ .fill(null)
123
+ .map(() => this.generateDurationMarkerValues(durationMs));
124
+ await this.outlet.pushMarkers(markers);
125
+ return markers;
126
+ }
127
+ static generateDurationMarkerValues(durationMs) {
128
+ return {
129
+ name: (0, test_utils_1.generateId)(),
130
+ durationMs: durationMs !== null && durationMs !== void 0 ? durationMs : (0, crypto_1.randomInt)(100, 1000),
131
+ };
85
132
  }
86
133
  static Outlet(options) {
87
- return TimeMarkerOutlet_1.default.Outlet(options);
134
+ return TimeMarkerOutlet_1.default.TimeMarkerOutlet(options);
88
135
  }
89
136
  }
90
137
  exports.default = TimeMarkerOutletTest;
@@ -100,6 +147,20 @@ __decorate([
100
147
  __decorate([
101
148
  (0, test_utils_1.test)()
102
149
  ], TimeMarkerOutletTest, "pushingTwoMarkersIncrementsHitCountAndWaitTimeTwice", null);
150
+ __decorate([
151
+ (0, test_utils_1.test)('can stop on the first marker', 1),
152
+ (0, test_utils_1.test)('can stop on the second marker', 2),
153
+ (0, test_utils_1.test)('can stop on the third marker', 3)
154
+ ], TimeMarkerOutletTest, "canStopTimeMarkersMidPush", null);
155
+ __decorate([
156
+ (0, test_utils_1.test)()
157
+ ], TimeMarkerOutletTest, "canStartAgainAfterStopping", null);
158
+ __decorate([
159
+ (0, test_utils_1.test)()
160
+ ], TimeMarkerOutletTest, "doesNotWaitIfStopped", null);
161
+ __decorate([
162
+ (0, test_utils_1.test)()
163
+ ], TimeMarkerOutletTest, "clearsTheTimeoutOnStop", null);
103
164
  class SpyTimeMarkerOutlet extends TimeMarkerOutlet_1.default {
104
165
  constructor(options) {
105
166
  super(options);
@@ -1 +1 @@
1
- {"version":3,"file":"TimeMarkerOutlet.test.js","sourceRoot":"","sources":["../../../src/__tests__/behavioral/TimeMarkerOutlet.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TimeMarkerOutlet.test.js","sourceRoot":"","sources":["../../../src/__tests__/behavioral/TimeMarkerOutlet.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/node-lsl",
3
- "version": "5.0.0",
3
+ "version": "6.1.0",
4
4
  "main": "build/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -4,7 +4,11 @@ export default class TimeMarkerOutletImpl
4
4
  extends LslOutletImpl
5
5
  implements TimeMarkerOutlet
6
6
  {
7
- public static Outlet(options?: Partial<LslOutletOptions>) {
7
+ private isPlaying: boolean = false
8
+ private waitResolve?: () => void
9
+ private timeout?: any
10
+
11
+ public static TimeMarkerOutlet(options?: Partial<LslOutletOptions>) {
8
12
  const defaultOptions = {
9
13
  name: 'Time markers',
10
14
  type: 'Markers',
@@ -18,18 +22,43 @@ export default class TimeMarkerOutletImpl
18
22
  maxBuffered: 0,
19
23
  } as LslOutletOptions
20
24
 
21
- return new (this.Class ?? this)({ ...defaultOptions, ...options })
25
+ //@ts-ignore
26
+ return new (this.Class ?? this)({
27
+ ...defaultOptions,
28
+ ...options,
29
+ }) as TimeMarkerOutlet
22
30
  }
23
31
 
24
32
  public async pushMarkers(markers: DurationMarker[]) {
33
+ this.isPlaying = true
34
+
25
35
  for (let marker of markers) {
26
36
  this.pushSample([marker.name])
37
+
27
38
  await this.wait(marker.durationMs)
39
+
40
+ if (!this.isPlaying) {
41
+ return
42
+ }
28
43
  }
29
44
  }
30
45
 
31
46
  protected async wait(durationMs: number) {
32
- return new Promise((resolve) => setTimeout(resolve, durationMs))
47
+ return new Promise((resolve) => this.setTimeout(resolve, durationMs))
48
+ }
49
+
50
+ private setTimeout(
51
+ resolve: (value: unknown) => void,
52
+ durationMs: number
53
+ ): void {
54
+ this.waitResolve = resolve as any
55
+ this.timeout = setTimeout(resolve, durationMs)
56
+ }
57
+
58
+ public stop(): void {
59
+ this.waitResolve?.()
60
+ clearTimeout(this.timeout)
61
+ this.isPlaying = false
33
62
  }
34
63
  }
35
64
 
@@ -40,4 +69,5 @@ export interface DurationMarker {
40
69
 
41
70
  export interface TimeMarkerOutlet {
42
71
  pushMarkers(markers: DurationMarker[]): Promise<void>
72
+ stop(): void
43
73
  }
@@ -47,19 +47,17 @@ export default class TimeMarkerOutletTest extends AbstractSpruceTest {
47
47
 
48
48
  @test()
49
49
  protected static async pushingSingleMarkerIncrementsHitCountAndWaitTime() {
50
- const markers = [this.generateRandomDurationMarker()]
50
+ const markers = [this.generateDurationMarkerValues()]
51
51
  await this.outlet.pushMarkers(markers)
52
+
52
53
  assert.isEqual(this.fakeLiblsl.pushSampleStrtHitCount, 1)
53
54
  assert.isEqual(this.outlet.totalWaitTimeMs, markers[0].durationMs)
54
55
  }
55
56
 
56
57
  @test()
57
58
  protected static async pushingTwoMarkersIncrementsHitCountAndWaitTimeTwice() {
58
- const markers = [
59
- this.generateRandomDurationMarker(),
60
- this.generateRandomDurationMarker(),
61
- ]
62
- await this.outlet.pushMarkers(markers)
59
+ const markers = await this.pushTotalMarkers(2)
60
+
63
61
  assert.isEqual(this.fakeLiblsl.pushSampleStrtHitCount, 2)
64
62
  assert.isEqual(
65
63
  this.outlet.totalWaitTimeMs,
@@ -67,12 +65,92 @@ export default class TimeMarkerOutletTest extends AbstractSpruceTest {
67
65
  )
68
66
  }
69
67
 
70
- private static generateRandomDurationMarker() {
71
- return { name: generateId(), durationMs: randomInt(100, 1000) }
68
+ @test('can stop on the first marker', 1)
69
+ @test('can stop on the second marker', 2)
70
+ @test('can stop on the third marker', 3)
71
+ protected static async canStopTimeMarkersMidPush(bailIdx: number) {
72
+ let hitCount = 0
73
+
74
+ this.outlet.pushSample = () => {
75
+ hitCount += 1
76
+ if (hitCount === bailIdx) {
77
+ this.outlet.stop()
78
+ }
79
+ }
80
+
81
+ await this.pushTotalMarkers(10)
82
+
83
+ assert.isEqual(hitCount, bailIdx)
84
+ }
85
+
86
+ @test()
87
+ protected static async canStartAgainAfterStopping() {
88
+ this.outlet.stop()
89
+
90
+ let hitCount = 0
91
+
92
+ this.outlet.pushSample = () => {
93
+ hitCount++
94
+ }
95
+
96
+ await this.pushTotalMarkers(10)
97
+
98
+ assert.isEqual(hitCount, 10)
99
+ }
100
+
101
+ @test()
102
+ protected static async doesNotWaitIfStopped() {
103
+ this.setupTimeMarkerImpl()
104
+
105
+ const startMs = Date.now()
106
+
107
+ const promise = this.pushTotalMarkers(2, 1000)
108
+
109
+ this.outlet.stop()
110
+
111
+ await promise
112
+
113
+ const endMs = Date.now()
114
+ assert.isBelow(endMs - startMs, 10)
115
+ }
116
+
117
+ @test()
118
+ protected static async clearsTheTimeoutOnStop() {
119
+ this.setupTimeMarkerImpl()
120
+
121
+ const promise = this.pushTotalMarkers(2, 100)
122
+
123
+ this.outlet.stop()
124
+ this.outlet.pushSample = () => assert.fail('Should not have been called')
125
+
126
+ await promise
127
+ await this.wait(100)
128
+ }
129
+
130
+ private static setupTimeMarkerImpl() {
131
+ TimeMarkerOutletImpl.Class = TimeMarkerOutletImpl as any
132
+ this.outlet = this.Outlet()
133
+ }
134
+
135
+ private static async pushTotalMarkers(total: number, durationMs?: number) {
136
+ const markers = new Array(total)
137
+ .fill(null)
138
+ .map(() => this.generateDurationMarkerValues(durationMs))
139
+
140
+ await this.outlet.pushMarkers(markers)
141
+
142
+ return markers
143
+ }
144
+
145
+ private static generateDurationMarkerValues(durationMs?: number) {
146
+ return {
147
+ name: generateId(),
148
+ durationMs: durationMs ?? randomInt(100, 1000),
149
+ }
72
150
  }
73
151
 
74
152
  private static Outlet(options?: Partial<LslOutletOptions>) {
75
- return TimeMarkerOutletImpl.Outlet(options) as SpyTimeMarkerOutlet
153
+ return TimeMarkerOutletImpl.TimeMarkerOutlet(options) as SpyTimeMarkerOutlet
76
154
  }
77
155
  }
78
156