gingersnap 0.23.1 → 0.23.3
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/data-structures/object/Queue.cjs +3 -0
- package/data-structures/object/Queue.d.ts +1 -0
- package/data-structures/object/Queue.mjs +3 -0
- package/errors/TimeoutError.cjs +1 -3
- package/errors/TimeoutError.d.ts +1 -2
- package/errors/TimeoutError.mjs +1 -3
- package/future/future.cjs +18 -12
- package/future/future.d.ts +2 -2
- package/future/future.mjs +18 -12
- package/networking/SocketService.cjs +4 -4
- package/networking/SocketService.mjs +4 -4
- package/package.json +1 -1
- package/socket.cjs +31 -2
- package/socket.d.ts +17 -4
- package/socket.mjs +31 -2
- package/stream/index.d.ts +36 -0
- package/stream/observable.cjs +24 -0
- package/stream/observable.d.ts +13 -0
- package/stream/observable.mjs +24 -0
- package/stream.cjs +127 -0
- package/stream.mjs +127 -0
|
@@ -49,6 +49,9 @@ class Queue extends WatchableObject.WatchableObject {
|
|
|
49
49
|
this.set(this.tail, value);
|
|
50
50
|
this.tail++;
|
|
51
51
|
}
|
|
52
|
+
add(value) {
|
|
53
|
+
this.enqueue(value);
|
|
54
|
+
}
|
|
52
55
|
awaitEnqueue(value) {
|
|
53
56
|
return future.Future.of((resolve, reject, signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
54
57
|
while (this.objectMaxSize && this.size() >= this.objectMaxSize) {
|
|
@@ -16,6 +16,7 @@ export declare class Queue<T> extends WatchableObject<number, T> implements Iter
|
|
|
16
16
|
clone(): Queue<T>;
|
|
17
17
|
ingest(stream: Stream<T>): Future<void>;
|
|
18
18
|
enqueue(value: T): void;
|
|
19
|
+
add(value: T): void;
|
|
19
20
|
awaitEnqueue(value: T): Future<void>;
|
|
20
21
|
dequeue(): T;
|
|
21
22
|
awaitDequeue(abortSignal?: AbortSignal): Future<T>;
|
|
@@ -47,6 +47,9 @@ class Queue extends WatchableObject {
|
|
|
47
47
|
this.set(this.tail, value);
|
|
48
48
|
this.tail++;
|
|
49
49
|
}
|
|
50
|
+
add(value) {
|
|
51
|
+
this.enqueue(value);
|
|
52
|
+
}
|
|
50
53
|
awaitEnqueue(value) {
|
|
51
54
|
return Future.of((resolve, reject, signal) => __awaiter(this, void 0, void 0, function* () {
|
|
52
55
|
while (this.objectMaxSize && this.size() >= this.objectMaxSize) {
|
package/errors/TimeoutError.cjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var FutureCancelled = require('./FutureCancelled.cjs');
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Thrown to indicate that some timed operation has exceeded the maximum duration
|
|
7
5
|
*/
|
|
8
|
-
class TimeoutError extends
|
|
6
|
+
class TimeoutError extends Error {
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
exports.TimeoutError = TimeoutError;
|
package/errors/TimeoutError.d.ts
CHANGED
package/errors/TimeoutError.mjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { FutureCancelled } from './FutureCancelled.mjs';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Thrown to indicate that some timed operation has exceeded the maximum duration
|
|
5
3
|
*/
|
|
6
|
-
class TimeoutError extends
|
|
4
|
+
class TimeoutError extends Error {
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
export { TimeoutError };
|
package/future/future.cjs
CHANGED
|
@@ -91,7 +91,7 @@ class Future {
|
|
|
91
91
|
const timeableFuture = Future.sleep(timeout)
|
|
92
92
|
.registerSignal(value.defaultSignal)
|
|
93
93
|
.catch(() => { });
|
|
94
|
-
return Future.of((resolve, reject) => Promise.race([timeableFuture, value
|
|
94
|
+
return Future.of((resolve, reject) => Promise.race([timeableFuture, value])
|
|
95
95
|
.then((v) => {
|
|
96
96
|
if (value.done) {
|
|
97
97
|
timeableFuture.cancel();
|
|
@@ -130,19 +130,28 @@ class Future {
|
|
|
130
130
|
* @param value
|
|
131
131
|
*/
|
|
132
132
|
static completed(value) {
|
|
133
|
-
|
|
133
|
+
const future = new Future(() => { });
|
|
134
|
+
future.underLyingPromise = Promise.resolve(value);
|
|
135
|
+
future.completedResult = value;
|
|
136
|
+
future.fulfilled = true;
|
|
137
|
+
future.isRunning = false;
|
|
138
|
+
return future;
|
|
134
139
|
}
|
|
135
140
|
/**
|
|
136
141
|
* Returns a future that fails with the given value
|
|
137
142
|
* @param value
|
|
138
143
|
*/
|
|
139
144
|
static exceptionally(value) {
|
|
140
|
-
|
|
145
|
+
const future = new Future(() => { });
|
|
146
|
+
future.isRunning = false;
|
|
147
|
+
future.failureResult = value;
|
|
148
|
+
future.underLyingPromise = Promise.reject(value);
|
|
149
|
+
return future;
|
|
141
150
|
}
|
|
142
151
|
/**
|
|
143
152
|
* Returns the first completed or failed. If this is cancelled, then all futures provided will also be cancelled
|
|
144
153
|
* @param futures list of futures
|
|
145
|
-
* @param signal
|
|
154
|
+
* @param signal optional abort signal
|
|
146
155
|
*/
|
|
147
156
|
static firstCompleted(futures, signal) {
|
|
148
157
|
return Future.of((resolve, reject, signal) => {
|
|
@@ -243,7 +252,7 @@ class Future {
|
|
|
243
252
|
* Checks if the future failed
|
|
244
253
|
*/
|
|
245
254
|
get failed() {
|
|
246
|
-
return this.error instanceof Error;
|
|
255
|
+
return this.error !== undefined && this.error instanceof Error;
|
|
247
256
|
}
|
|
248
257
|
/**
|
|
249
258
|
* Retrieves the result of the future, if there is any
|
|
@@ -327,7 +336,7 @@ class Future {
|
|
|
327
336
|
this.signals.forEach((signal) => newFuture.registerSignal(signal));
|
|
328
337
|
return newFuture;
|
|
329
338
|
}
|
|
330
|
-
else if (this.done) {
|
|
339
|
+
else if (this.done || this.failed) {
|
|
331
340
|
const newFuture = Future.wrap(this.underLyingPromise).thenApply(callback);
|
|
332
341
|
return newFuture;
|
|
333
342
|
}
|
|
@@ -438,24 +447,20 @@ class Future {
|
|
|
438
447
|
const resolver = (v) => {
|
|
439
448
|
if (v instanceof Promise) {
|
|
440
449
|
v.then((v) => {
|
|
441
|
-
this.fulfilled = true;
|
|
442
450
|
resolve(v);
|
|
443
451
|
}).catch(reject);
|
|
444
452
|
}
|
|
445
453
|
else if (v instanceof Future) {
|
|
446
454
|
v.run()
|
|
447
455
|
.then((v) => {
|
|
448
|
-
this.fulfilled = true;
|
|
449
456
|
resolve(v);
|
|
450
457
|
})
|
|
451
458
|
.catch(reject);
|
|
452
459
|
}
|
|
453
460
|
else if (v instanceof result.FutureResult) {
|
|
454
|
-
this.fulfilled = true;
|
|
455
461
|
resolve(v.value);
|
|
456
462
|
}
|
|
457
463
|
else {
|
|
458
|
-
this.fulfilled = true;
|
|
459
464
|
resolve(v);
|
|
460
465
|
}
|
|
461
466
|
};
|
|
@@ -482,7 +487,6 @@ class Future {
|
|
|
482
487
|
result$1
|
|
483
488
|
.then(() => {
|
|
484
489
|
if (!this.fulfilled) {
|
|
485
|
-
this.fulfilled = true;
|
|
486
490
|
resolve(null);
|
|
487
491
|
}
|
|
488
492
|
})
|
|
@@ -492,10 +496,13 @@ class Future {
|
|
|
492
496
|
.then((v) => {
|
|
493
497
|
this.completedResult = v;
|
|
494
498
|
onFulfilled === null || onFulfilled === void 0 ? void 0 : onFulfilled(v);
|
|
499
|
+
this.isRunning = false;
|
|
500
|
+
this.fulfilled = true;
|
|
495
501
|
return v;
|
|
496
502
|
})
|
|
497
503
|
.catch((e) => {
|
|
498
504
|
this.failureResult = e instanceof Error ? e : new Error(String(e));
|
|
505
|
+
this.isRunning = false;
|
|
499
506
|
throw this.failureResult;
|
|
500
507
|
})
|
|
501
508
|
.finally(() => {
|
|
@@ -508,7 +515,6 @@ class Future {
|
|
|
508
515
|
})
|
|
509
516
|
.finally(() => {
|
|
510
517
|
this.signals = new Set();
|
|
511
|
-
this.isRunning = false;
|
|
512
518
|
});
|
|
513
519
|
return this.underLyingPromise;
|
|
514
520
|
}
|
package/future/future.d.ts
CHANGED
|
@@ -72,11 +72,11 @@ export declare class Future<T> {
|
|
|
72
72
|
* Returns a future that fails with the given value
|
|
73
73
|
* @param value
|
|
74
74
|
*/
|
|
75
|
-
static exceptionally(value: Error): Future<
|
|
75
|
+
static exceptionally<K>(value: Error): Future<K>;
|
|
76
76
|
/**
|
|
77
77
|
* Returns the first completed or failed. If this is cancelled, then all futures provided will also be cancelled
|
|
78
78
|
* @param futures list of futures
|
|
79
|
-
* @param signal
|
|
79
|
+
* @param signal optional abort signal
|
|
80
80
|
*/
|
|
81
81
|
static firstCompleted<T extends Array<Future<any>>>(futures: T, signal?: AbortSignal): Future<FutureReturnType<T[number]>>;
|
|
82
82
|
/**
|
package/future/future.mjs
CHANGED
|
@@ -70,7 +70,7 @@ class Future {
|
|
|
70
70
|
const timeableFuture = Future.sleep(timeout)
|
|
71
71
|
.registerSignal(value.defaultSignal)
|
|
72
72
|
.catch(() => { });
|
|
73
|
-
return Future.of((resolve, reject) => Promise.race([timeableFuture, value
|
|
73
|
+
return Future.of((resolve, reject) => Promise.race([timeableFuture, value])
|
|
74
74
|
.then((v) => {
|
|
75
75
|
if (value.done) {
|
|
76
76
|
timeableFuture.cancel();
|
|
@@ -109,19 +109,28 @@ class Future {
|
|
|
109
109
|
* @param value
|
|
110
110
|
*/
|
|
111
111
|
static completed(value) {
|
|
112
|
-
|
|
112
|
+
const future = new Future(() => { });
|
|
113
|
+
future.underLyingPromise = Promise.resolve(value);
|
|
114
|
+
future.completedResult = value;
|
|
115
|
+
future.fulfilled = true;
|
|
116
|
+
future.isRunning = false;
|
|
117
|
+
return future;
|
|
113
118
|
}
|
|
114
119
|
/**
|
|
115
120
|
* Returns a future that fails with the given value
|
|
116
121
|
* @param value
|
|
117
122
|
*/
|
|
118
123
|
static exceptionally(value) {
|
|
119
|
-
|
|
124
|
+
const future = new Future(() => { });
|
|
125
|
+
future.isRunning = false;
|
|
126
|
+
future.failureResult = value;
|
|
127
|
+
future.underLyingPromise = Promise.reject(value);
|
|
128
|
+
return future;
|
|
120
129
|
}
|
|
121
130
|
/**
|
|
122
131
|
* Returns the first completed or failed. If this is cancelled, then all futures provided will also be cancelled
|
|
123
132
|
* @param futures list of futures
|
|
124
|
-
* @param signal
|
|
133
|
+
* @param signal optional abort signal
|
|
125
134
|
*/
|
|
126
135
|
static firstCompleted(futures, signal) {
|
|
127
136
|
return Future.of((resolve, reject, signal) => {
|
|
@@ -222,7 +231,7 @@ class Future {
|
|
|
222
231
|
* Checks if the future failed
|
|
223
232
|
*/
|
|
224
233
|
get failed() {
|
|
225
|
-
return this.error instanceof Error;
|
|
234
|
+
return this.error !== undefined && this.error instanceof Error;
|
|
226
235
|
}
|
|
227
236
|
/**
|
|
228
237
|
* Retrieves the result of the future, if there is any
|
|
@@ -306,7 +315,7 @@ class Future {
|
|
|
306
315
|
this.signals.forEach((signal) => newFuture.registerSignal(signal));
|
|
307
316
|
return newFuture;
|
|
308
317
|
}
|
|
309
|
-
else if (this.done) {
|
|
318
|
+
else if (this.done || this.failed) {
|
|
310
319
|
const newFuture = Future.wrap(this.underLyingPromise).thenApply(callback);
|
|
311
320
|
return newFuture;
|
|
312
321
|
}
|
|
@@ -417,24 +426,20 @@ class Future {
|
|
|
417
426
|
const resolver = (v) => {
|
|
418
427
|
if (v instanceof Promise) {
|
|
419
428
|
v.then((v) => {
|
|
420
|
-
this.fulfilled = true;
|
|
421
429
|
resolve(v);
|
|
422
430
|
}).catch(reject);
|
|
423
431
|
}
|
|
424
432
|
else if (v instanceof Future) {
|
|
425
433
|
v.run()
|
|
426
434
|
.then((v) => {
|
|
427
|
-
this.fulfilled = true;
|
|
428
435
|
resolve(v);
|
|
429
436
|
})
|
|
430
437
|
.catch(reject);
|
|
431
438
|
}
|
|
432
439
|
else if (v instanceof FutureResult) {
|
|
433
|
-
this.fulfilled = true;
|
|
434
440
|
resolve(v.value);
|
|
435
441
|
}
|
|
436
442
|
else {
|
|
437
|
-
this.fulfilled = true;
|
|
438
443
|
resolve(v);
|
|
439
444
|
}
|
|
440
445
|
};
|
|
@@ -461,7 +466,6 @@ class Future {
|
|
|
461
466
|
result
|
|
462
467
|
.then(() => {
|
|
463
468
|
if (!this.fulfilled) {
|
|
464
|
-
this.fulfilled = true;
|
|
465
469
|
resolve(null);
|
|
466
470
|
}
|
|
467
471
|
})
|
|
@@ -471,10 +475,13 @@ class Future {
|
|
|
471
475
|
.then((v) => {
|
|
472
476
|
this.completedResult = v;
|
|
473
477
|
onFulfilled === null || onFulfilled === void 0 ? void 0 : onFulfilled(v);
|
|
478
|
+
this.isRunning = false;
|
|
479
|
+
this.fulfilled = true;
|
|
474
480
|
return v;
|
|
475
481
|
})
|
|
476
482
|
.catch((e) => {
|
|
477
483
|
this.failureResult = e instanceof Error ? e : new Error(String(e));
|
|
484
|
+
this.isRunning = false;
|
|
478
485
|
throw this.failureResult;
|
|
479
486
|
})
|
|
480
487
|
.finally(() => {
|
|
@@ -487,7 +494,6 @@ class Future {
|
|
|
487
494
|
})
|
|
488
495
|
.finally(() => {
|
|
489
496
|
this.signals = new Set();
|
|
490
|
-
this.isRunning = false;
|
|
491
497
|
});
|
|
492
498
|
return this.underLyingPromise;
|
|
493
499
|
}
|
|
@@ -131,7 +131,7 @@ class WebSocketService extends NetworkService.NetworkService {
|
|
|
131
131
|
data = body.object();
|
|
132
132
|
}
|
|
133
133
|
data = R__namespace.set(lens, guid, data);
|
|
134
|
-
yield this.socket.
|
|
134
|
+
yield this.socket.sendNow(JSON.stringify(data));
|
|
135
135
|
return 1;
|
|
136
136
|
})))
|
|
137
137
|
.map(() => this.socket.streamView(R__namespace.compose(R__namespace.equals(guid), R__namespace.view(lens)), config.socketRequestReply.objectMaxSize, config.socketRequestReply.expiryPeriod))
|
|
@@ -162,13 +162,13 @@ class WebSocketService extends NetworkService.NetworkService {
|
|
|
162
162
|
yield this.socket.open();
|
|
163
163
|
}
|
|
164
164
|
if (body instanceof model.Model) {
|
|
165
|
-
yield this.socket.
|
|
165
|
+
yield this.socket.sendNow(body.blob());
|
|
166
166
|
}
|
|
167
167
|
else if (body instanceof ArrayBuffer || body instanceof Blob) {
|
|
168
|
-
yield this.socket.
|
|
168
|
+
yield this.socket.sendNow(body);
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
|
-
yield this.socket.
|
|
171
|
+
yield this.socket.sendNow(JSON.stringify(body));
|
|
172
172
|
}
|
|
173
173
|
const result = oldMethod();
|
|
174
174
|
if (result instanceof Promise) {
|
|
@@ -110,7 +110,7 @@ class WebSocketService extends NetworkService {
|
|
|
110
110
|
data = body.object();
|
|
111
111
|
}
|
|
112
112
|
data = R.set(lens, guid, data);
|
|
113
|
-
yield this.socket.
|
|
113
|
+
yield this.socket.sendNow(JSON.stringify(data));
|
|
114
114
|
return 1;
|
|
115
115
|
})))
|
|
116
116
|
.map(() => this.socket.streamView(R.compose(R.equals(guid), R.view(lens)), config.socketRequestReply.objectMaxSize, config.socketRequestReply.expiryPeriod))
|
|
@@ -141,13 +141,13 @@ class WebSocketService extends NetworkService {
|
|
|
141
141
|
yield this.socket.open();
|
|
142
142
|
}
|
|
143
143
|
if (body instanceof Model) {
|
|
144
|
-
yield this.socket.
|
|
144
|
+
yield this.socket.sendNow(body.blob());
|
|
145
145
|
}
|
|
146
146
|
else if (body instanceof ArrayBuffer || body instanceof Blob) {
|
|
147
|
-
yield this.socket.
|
|
147
|
+
yield this.socket.sendNow(body);
|
|
148
148
|
}
|
|
149
149
|
else {
|
|
150
|
-
yield this.socket.
|
|
150
|
+
yield this.socket.sendNow(JSON.stringify(body));
|
|
151
151
|
}
|
|
152
152
|
const result = oldMethod();
|
|
153
153
|
if (result instanceof Promise) {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"gingersnap","version":"0.23.
|
|
1
|
+
{"name":"gingersnap","version":"0.23.3","description":"A general purpose library built with the aim of filling the gaps of javascript shortcomings","dependencies":{"@msgpack/msgpack":"^3.0.0-beta2","browser-or-node":"^3.0.0-pre.0","modern-isomorphic-ws":"^1.0.5","object-hash":"^3.0.0","papaparse":"^5.4.1","protobufjs":"^7.2.6","ramda":"^0.30.1","reflect-metadata":"^0.2.2","tslib":"^2.6.3","uuid":"^9.0.1","ws":"^8.16.0","x2js":"^3.4.4"},"author":"CookieNerds LLC","exports":{"./synchronize":{"import":{"types":"./synchronize.d.ts","default":"./synchronize.mjs"},"require":{"types":"./synchronize.d.ts","default":"./synchronize.cjs"}},"./mocks":{"import":{"types":"./mocks.d.ts","default":"./mocks.mjs"},"require":{"types":"./mocks.d.ts","default":"./mocks.cjs"}},"./socket":{"import":{"types":"./socket.d.ts","default":"./socket.mjs"},"require":{"types":"./socket.d.ts","default":"./socket.cjs"}},"./typing":{"import":{"types":"./typing.d.ts","default":"./typing.mjs"},"require":{"types":"./typing.d.ts","default":"./typing.cjs"}},"./stream":{"import":{"types":"./stream/index.d.ts","default":"./stream.mjs"},"require":{"types":"./stream/index.d.ts","default":"./stream.cjs"}},"./reflection/injector":{"import":{"types":"./reflection/injector.d.ts","default":"./reflection/injector.mjs"},"require":{"types":"./reflection/injector.d.ts","default":"./reflection/injector.cjs"}},"./stream/call":{"import":{"types":"./stream/call.d.ts","default":"./stream/call.mjs"},"require":{"types":"./stream/call.d.ts","default":"./stream/call.cjs"}},"./stream/state":{"import":{"types":"./stream/state.d.ts","default":"./stream/state.mjs"},"require":{"types":"./stream/state.d.ts","default":"./stream/state.cjs"}},"./stream/collector":{"import":{"types":"./stream/collector.d.ts","default":"./stream/collector.mjs"},"require":{"types":"./stream/collector.d.ts","default":"./stream/collector.cjs"}},"./stream/observable":{"import":{"types":"./stream/observable.d.ts","default":"./stream/observable.mjs"},"require":{"types":"./stream/observable.d.ts","default":"./stream/observable.cjs"}},"./networking":{"import":{"types":"./networking/index.d.ts","default":"./networking.mjs"},"require":{"types":"./networking/index.d.ts","default":"./networking.cjs"}},"./managers":{"import":{"types":"./managers/index.d.ts","default":"./managers.mjs"},"require":{"types":"./managers/index.d.ts","default":"./managers.cjs"}},"./future":{"import":{"types":"./future/index.d.ts","default":"./future.mjs"},"require":{"types":"./future/index.d.ts","default":"./future.cjs"}},"./errors":{"import":{"types":"./errors/index.d.ts","default":"./errors.mjs"},"require":{"types":"./errors/index.d.ts","default":"./errors.cjs"}},"./data-structures/array":{"import":{"types":"./data-structures/array/index.d.ts","default":"./data-structures/array.mjs"},"require":{"types":"./data-structures/array/index.d.ts","default":"./data-structures/array.cjs"}},"./data-structures/object":{"import":{"types":"./data-structures/object/index.d.ts","default":"./data-structures/object.mjs"},"require":{"types":"./data-structures/object/index.d.ts","default":"./data-structures/object.cjs"}},"./data/decoders":{"import":{"types":"./data/decoders/index.d.ts","default":"./data/decoders.mjs"},"require":{"types":"./data/decoders/index.d.ts","default":"./data/decoders.cjs"}},"./data/model":{"import":{"types":"./data/model/index.d.ts","default":"./data/model.mjs"},"require":{"types":"./data/model/index.d.ts","default":"./data/model.cjs"}},"./data/bus":{"import":{"types":"./data/bus.d.ts","default":"./data/bus.mjs"},"require":{"types":"./data/bus.d.ts","default":"./data/bus.cjs"}},"./data/value":{"import":{"types":"./data/value.d.ts","default":"./data/value.mjs"},"require":{"types":"./data/value.d.ts","default":"./data/value.cjs"}},"./store":{"import":{"types":"./store/index.d.ts","default":"./store.mjs"},"require":{"types":"./store/index.d.ts","default":"./store.cjs"}},"./functools":{"import":{"types":"./functools/index.d.ts","default":"./functools.mjs"},"require":{"types":"./functools/index.d.ts","default":"./functools.cjs"}}}}
|
package/socket.cjs
CHANGED
|
@@ -11,6 +11,7 @@ require('ramda');
|
|
|
11
11
|
require('uuid');
|
|
12
12
|
var stream = require('./stream.cjs');
|
|
13
13
|
var future = require('./future/future.cjs');
|
|
14
|
+
var result = require('./future/result.cjs');
|
|
14
15
|
var synchronize = require('./synchronize.cjs');
|
|
15
16
|
var stream_state = require('./stream/state.cjs');
|
|
16
17
|
var WebSocket = require('modern-isomorphic-ws');
|
|
@@ -155,15 +156,28 @@ class StreamableWebSocket {
|
|
|
155
156
|
this.signal.dispatchEvent(new CustomEvent("abort"));
|
|
156
157
|
}
|
|
157
158
|
/**
|
|
158
|
-
* Sends data via socket
|
|
159
|
+
* Sends data via socket as soon as possible
|
|
159
160
|
* @param data
|
|
160
161
|
*/
|
|
161
|
-
|
|
162
|
+
sendNow(data) {
|
|
162
163
|
var _a;
|
|
163
164
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
164
165
|
(_a = this.getSocket()) === null || _a === void 0 ? void 0 : _a.send(data instanceof Blob ? yield data.arrayBuffer() : data);
|
|
165
166
|
});
|
|
166
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Sends data via socket, awaiting socket connection if currently disconnected
|
|
170
|
+
* @param data
|
|
171
|
+
*/
|
|
172
|
+
send(data) {
|
|
173
|
+
return this.open().thenApply(() => _tslib.__awaiter(this, void 0, void 0, function* () { var _a; return (_a = this.getSocket()) === null || _a === void 0 ? void 0 : _a.send(data instanceof Blob ? yield data.arrayBuffer() : data); }));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Gets a stream of messages that match the given filter provided
|
|
177
|
+
* @param lens filter function to select specific messages
|
|
178
|
+
* @param objectMaxSize max messages to buffer if reading from this stream is slower than messages coming in
|
|
179
|
+
* @param expiryPeriod how long to store buffered messages if not read
|
|
180
|
+
*/
|
|
167
181
|
streamView(lens, objectMaxSize, expiryPeriod) {
|
|
168
182
|
const queue = new Queue.Queue(objectMaxSize, expiryPeriod);
|
|
169
183
|
const tuple = Pair.pair(queue, lens);
|
|
@@ -200,6 +214,21 @@ class StreamableWebSocket {
|
|
|
200
214
|
this.messageQueues = this.messageQueues.filter((v) => v !== queue);
|
|
201
215
|
});
|
|
202
216
|
}
|
|
217
|
+
with(functor) {
|
|
218
|
+
return future.Future.of((_, __, signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
219
|
+
const stream = this.stream().buffer(this.cacheSize);
|
|
220
|
+
yield this.open().registerSignal(signal);
|
|
221
|
+
try {
|
|
222
|
+
functor(new result.FutureResult(stream, signal));
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
if (!this.closed) {
|
|
226
|
+
this.close();
|
|
227
|
+
}
|
|
228
|
+
stream.cancel();
|
|
229
|
+
}
|
|
230
|
+
})).schedule();
|
|
231
|
+
}
|
|
203
232
|
addEventListener(type, functor) {
|
|
204
233
|
this.socketListeners.push([type, functor]);
|
|
205
234
|
if (this.socket) {
|
package/socket.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Stream } from "./stream";
|
|
2
|
-
import { Future, WaitPeriod } from "./future";
|
|
2
|
+
import { Future, FutureResult, WaitPeriod } from "./future";
|
|
3
3
|
import { Decoder } from "./data/decoders";
|
|
4
|
+
import { ContextManager } from "./managers";
|
|
4
5
|
interface WebSocketConfiguration {
|
|
5
6
|
retryOnDisconnect?: boolean;
|
|
6
7
|
cacheSize?: number;
|
|
@@ -11,7 +12,7 @@ interface WebSocketConfiguration {
|
|
|
11
12
|
/**
|
|
12
13
|
* Future-based web sockets
|
|
13
14
|
*/
|
|
14
|
-
export declare class StreamableWebSocket<T> {
|
|
15
|
+
export declare class StreamableWebSocket<T> implements ContextManager<Stream<T>> {
|
|
15
16
|
private readonly maxReconnectAttempt;
|
|
16
17
|
private readonly retryOnDisconnect;
|
|
17
18
|
private openFuture?;
|
|
@@ -49,15 +50,27 @@ export declare class StreamableWebSocket<T> {
|
|
|
49
50
|
*/
|
|
50
51
|
close(): void;
|
|
51
52
|
/**
|
|
52
|
-
* Sends data via socket
|
|
53
|
+
* Sends data via socket as soon as possible
|
|
53
54
|
* @param data
|
|
54
55
|
*/
|
|
55
|
-
|
|
56
|
+
sendNow(data: string | ArrayBufferView | Blob | ArrayBufferLike): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Sends data via socket, awaiting socket connection if currently disconnected
|
|
59
|
+
* @param data
|
|
60
|
+
*/
|
|
61
|
+
send(data: string | ArrayBufferView | Blob | ArrayBufferLike): Future<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Gets a stream of messages that match the given filter provided
|
|
64
|
+
* @param lens filter function to select specific messages
|
|
65
|
+
* @param objectMaxSize max messages to buffer if reading from this stream is slower than messages coming in
|
|
66
|
+
* @param expiryPeriod how long to store buffered messages if not read
|
|
67
|
+
*/
|
|
56
68
|
streamView(lens: (v: T) => boolean, objectMaxSize?: number, expiryPeriod?: WaitPeriod): Stream<T>;
|
|
57
69
|
/**
|
|
58
70
|
* Gets the stream for messages received via this socket
|
|
59
71
|
*/
|
|
60
72
|
stream(): Stream<T>;
|
|
73
|
+
with(functor: (value: FutureResult<Stream<T>>) => any): Future<void>;
|
|
61
74
|
private addEventListener;
|
|
62
75
|
private createSocket;
|
|
63
76
|
private getSocket;
|
package/socket.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import 'ramda';
|
|
|
9
9
|
import 'uuid';
|
|
10
10
|
import { Stream } from './stream.mjs';
|
|
11
11
|
import { Future } from './future/future.mjs';
|
|
12
|
+
import { FutureResult } from './future/result.mjs';
|
|
12
13
|
import { FutureEvent, Lock } from './synchronize.mjs';
|
|
13
14
|
import { ExecutorState } from './stream/state.mjs';
|
|
14
15
|
import WebSocket from 'modern-isomorphic-ws';
|
|
@@ -153,15 +154,28 @@ class StreamableWebSocket {
|
|
|
153
154
|
this.signal.dispatchEvent(new CustomEvent("abort"));
|
|
154
155
|
}
|
|
155
156
|
/**
|
|
156
|
-
* Sends data via socket
|
|
157
|
+
* Sends data via socket as soon as possible
|
|
157
158
|
* @param data
|
|
158
159
|
*/
|
|
159
|
-
|
|
160
|
+
sendNow(data) {
|
|
160
161
|
var _a;
|
|
161
162
|
return __awaiter(this, void 0, void 0, function* () {
|
|
162
163
|
(_a = this.getSocket()) === null || _a === void 0 ? void 0 : _a.send(data instanceof Blob ? yield data.arrayBuffer() : data);
|
|
163
164
|
});
|
|
164
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Sends data via socket, awaiting socket connection if currently disconnected
|
|
168
|
+
* @param data
|
|
169
|
+
*/
|
|
170
|
+
send(data) {
|
|
171
|
+
return this.open().thenApply(() => __awaiter(this, void 0, void 0, function* () { var _a; return (_a = this.getSocket()) === null || _a === void 0 ? void 0 : _a.send(data instanceof Blob ? yield data.arrayBuffer() : data); }));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Gets a stream of messages that match the given filter provided
|
|
175
|
+
* @param lens filter function to select specific messages
|
|
176
|
+
* @param objectMaxSize max messages to buffer if reading from this stream is slower than messages coming in
|
|
177
|
+
* @param expiryPeriod how long to store buffered messages if not read
|
|
178
|
+
*/
|
|
165
179
|
streamView(lens, objectMaxSize, expiryPeriod) {
|
|
166
180
|
const queue = new Queue(objectMaxSize, expiryPeriod);
|
|
167
181
|
const tuple = pair(queue, lens);
|
|
@@ -198,6 +212,21 @@ class StreamableWebSocket {
|
|
|
198
212
|
this.messageQueues = this.messageQueues.filter((v) => v !== queue);
|
|
199
213
|
});
|
|
200
214
|
}
|
|
215
|
+
with(functor) {
|
|
216
|
+
return Future.of((_, __, signal) => __awaiter(this, void 0, void 0, function* () {
|
|
217
|
+
const stream = this.stream().buffer(this.cacheSize);
|
|
218
|
+
yield this.open().registerSignal(signal);
|
|
219
|
+
try {
|
|
220
|
+
functor(new FutureResult(stream, signal));
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
if (!this.closed) {
|
|
224
|
+
this.close();
|
|
225
|
+
}
|
|
226
|
+
stream.cancel();
|
|
227
|
+
}
|
|
228
|
+
})).schedule();
|
|
229
|
+
}
|
|
201
230
|
addEventListener(type, functor) {
|
|
202
231
|
this.socketListeners.push([type, functor]);
|
|
203
232
|
if (this.socket) {
|
package/stream/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
33
33
|
protected cancelHooks: Set<() => any>;
|
|
34
34
|
protected completionHooks: Set<() => any>;
|
|
35
35
|
protected completionHookInvoked: boolean;
|
|
36
|
+
protected monitorHooks: Set<(v: T) => void>;
|
|
37
|
+
private frozen;
|
|
36
38
|
protected done: boolean;
|
|
37
39
|
protected backlog: Array<{
|
|
38
40
|
records: T[] | Stream<T>;
|
|
@@ -92,11 +94,44 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
92
94
|
*/
|
|
93
95
|
get future(): Future<T>;
|
|
94
96
|
get readableStream(): ReadableStream<T>;
|
|
97
|
+
/**
|
|
98
|
+
* Breaks up a stream into 2 other streams based on the callback result. If callback result is true, data will go to
|
|
99
|
+
* the first stream, otherwise it will go to the second stream. Note that splitting the stream will immediately invoke
|
|
100
|
+
* the parent stream if it's not already running
|
|
101
|
+
*
|
|
102
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
103
|
+
* stream)
|
|
104
|
+
* @param callback
|
|
105
|
+
*/
|
|
106
|
+
split(callback: (v: T) => boolean | Promise<boolean> | Future<boolean>): [Stream<T>, Stream<T>];
|
|
107
|
+
/**
|
|
108
|
+
* Creates a new branch from the main stream, that monitors and collects values that matches the filter specified.
|
|
109
|
+
* Note, this does not trigger the main stream to run nor does it alter the main stream. It only collects matched
|
|
110
|
+
* records from main stream once main stream is running.
|
|
111
|
+
*
|
|
112
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
113
|
+
* stream)
|
|
114
|
+
* @param filter
|
|
115
|
+
* @param objectMaxSize max records to keep in queue, provided you start reading from this stream slower than data is
|
|
116
|
+
* being collected from main stream
|
|
117
|
+
* @param expiryPeriod
|
|
118
|
+
*/
|
|
119
|
+
subStream(filter: (v: T) => boolean | Promise<boolean> | Future<boolean>, objectMaxSize?: number, expiryPeriod?: WaitPeriod): Stream<T>;
|
|
95
120
|
/**
|
|
96
121
|
* Cancel the stream on the given signal
|
|
97
122
|
* @param signal
|
|
98
123
|
*/
|
|
99
124
|
cancelOnSignal(signal: AbortSignal): this;
|
|
125
|
+
/**
|
|
126
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
127
|
+
* @param period
|
|
128
|
+
*/
|
|
129
|
+
waitFor(period: WaitPeriod): Stream<T>;
|
|
130
|
+
/**
|
|
131
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
132
|
+
* @param period
|
|
133
|
+
*/
|
|
134
|
+
waitFirstFor(period: WaitPeriod): Stream<T>;
|
|
100
135
|
parallel(concurrentlyLimit?: number): Stream<T>;
|
|
101
136
|
/**
|
|
102
137
|
* Transforms each data on the stream using the callback provided
|
|
@@ -253,5 +288,6 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
253
288
|
private yieldTrueResult;
|
|
254
289
|
private forwardExecute;
|
|
255
290
|
private collectResult;
|
|
291
|
+
private get canAlterStream();
|
|
256
292
|
}
|
|
257
293
|
export {};
|
package/stream/observable.cjs
CHANGED
|
@@ -39,6 +39,30 @@ class Observable {
|
|
|
39
39
|
this.publish(reqTopic, data);
|
|
40
40
|
return future.Future.waitFor(this.subscribe(replyTopic, 2).future, timeout).thenApply(({ value }) => value.data);
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Provides a Request-Multiple-Reply model by sending data over the given topic, and
|
|
44
|
+
* stream responses from the second topic provided. If you cancel the reply stream, a cancellation message
|
|
45
|
+
* can be sent via the cancellationTopic
|
|
46
|
+
* @param reqTopic request topic
|
|
47
|
+
* @param replyTopic reply topic which will be used to form the reply stream
|
|
48
|
+
* @param data request data
|
|
49
|
+
* @param cancellationTopic topic used to send a message if the stream is cancelled
|
|
50
|
+
* @param cancellationData cancellation message
|
|
51
|
+
* @param bufferSize max reply stream message buffer size
|
|
52
|
+
* @param timeout
|
|
53
|
+
*/
|
|
54
|
+
requestStream(reqTopic, replyTopic, data, cancellationTopic, cancellationData, bufferSize = 100, timeout = { seconds: 15 }) {
|
|
55
|
+
this.publish(reqTopic, data);
|
|
56
|
+
const stream = this.subscribe(replyTopic, bufferSize);
|
|
57
|
+
return stream
|
|
58
|
+
.waitFirstFor(timeout)
|
|
59
|
+
.map(({ data }) => data)
|
|
60
|
+
.onCancellation(() => {
|
|
61
|
+
if (cancellationTopic) {
|
|
62
|
+
this.publish(cancellationTopic, cancellationData);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
42
66
|
}
|
|
43
67
|
/**
|
|
44
68
|
* Provides Publisher-Subscriber service around an EventTarget
|
package/stream/observable.d.ts
CHANGED
|
@@ -38,6 +38,19 @@ export declare abstract class Observable<T> {
|
|
|
38
38
|
* @param timeout how long to wait for a response, defaults to 15 seconds
|
|
39
39
|
*/
|
|
40
40
|
request(reqTopic: string, replyTopic: string, data: T, timeout?: WaitPeriod): Future<T>;
|
|
41
|
+
/**
|
|
42
|
+
* Provides a Request-Multiple-Reply model by sending data over the given topic, and
|
|
43
|
+
* stream responses from the second topic provided. If you cancel the reply stream, a cancellation message
|
|
44
|
+
* can be sent via the cancellationTopic
|
|
45
|
+
* @param reqTopic request topic
|
|
46
|
+
* @param replyTopic reply topic which will be used to form the reply stream
|
|
47
|
+
* @param data request data
|
|
48
|
+
* @param cancellationTopic topic used to send a message if the stream is cancelled
|
|
49
|
+
* @param cancellationData cancellation message
|
|
50
|
+
* @param bufferSize max reply stream message buffer size
|
|
51
|
+
* @param timeout
|
|
52
|
+
*/
|
|
53
|
+
requestStream(reqTopic: string, replyTopic: string, data: T, cancellationTopic?: string, cancellationData?: T, bufferSize?: number, timeout?: WaitPeriod): Stream<T>;
|
|
41
54
|
}
|
|
42
55
|
/**
|
|
43
56
|
* Provides Publisher-Subscriber service around an EventTarget
|
package/stream/observable.mjs
CHANGED
|
@@ -37,6 +37,30 @@ class Observable {
|
|
|
37
37
|
this.publish(reqTopic, data);
|
|
38
38
|
return Future.waitFor(this.subscribe(replyTopic, 2).future, timeout).thenApply(({ value }) => value.data);
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Provides a Request-Multiple-Reply model by sending data over the given topic, and
|
|
42
|
+
* stream responses from the second topic provided. If you cancel the reply stream, a cancellation message
|
|
43
|
+
* can be sent via the cancellationTopic
|
|
44
|
+
* @param reqTopic request topic
|
|
45
|
+
* @param replyTopic reply topic which will be used to form the reply stream
|
|
46
|
+
* @param data request data
|
|
47
|
+
* @param cancellationTopic topic used to send a message if the stream is cancelled
|
|
48
|
+
* @param cancellationData cancellation message
|
|
49
|
+
* @param bufferSize max reply stream message buffer size
|
|
50
|
+
* @param timeout
|
|
51
|
+
*/
|
|
52
|
+
requestStream(reqTopic, replyTopic, data, cancellationTopic, cancellationData, bufferSize = 100, timeout = { seconds: 15 }) {
|
|
53
|
+
this.publish(reqTopic, data);
|
|
54
|
+
const stream = this.subscribe(replyTopic, bufferSize);
|
|
55
|
+
return stream
|
|
56
|
+
.waitFirstFor(timeout)
|
|
57
|
+
.map(({ data }) => data)
|
|
58
|
+
.onCancellation(() => {
|
|
59
|
+
if (cancellationTopic) {
|
|
60
|
+
this.publish(cancellationTopic, cancellationData);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
40
64
|
}
|
|
41
65
|
/**
|
|
42
66
|
* Provides Publisher-Subscriber service around an EventTarget
|
package/stream.cjs
CHANGED
|
@@ -68,6 +68,8 @@ class Stream {
|
|
|
68
68
|
this.completionHookInvoked = false;
|
|
69
69
|
this.runLock = new synchronize.Lock();
|
|
70
70
|
this.concurrencyLimit = 0;
|
|
71
|
+
this.monitorHooks = new Set();
|
|
72
|
+
this.frozen = false;
|
|
71
73
|
}
|
|
72
74
|
/**
|
|
73
75
|
* Used to provide setup logic that should only be invoked once, when stream
|
|
@@ -245,6 +247,66 @@ class Stream {
|
|
|
245
247
|
},
|
|
246
248
|
});
|
|
247
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Breaks up a stream into 2 other streams based on the callback result. If callback result is true, data will go to
|
|
252
|
+
* the first stream, otherwise it will go to the second stream. Note that splitting the stream will immediately invoke
|
|
253
|
+
* the parent stream if it's not already running
|
|
254
|
+
*
|
|
255
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
256
|
+
* stream)
|
|
257
|
+
* @param callback
|
|
258
|
+
*/
|
|
259
|
+
split(callback) {
|
|
260
|
+
this.frozen = true;
|
|
261
|
+
const queue1 = new Queue.Queue();
|
|
262
|
+
const queue2 = new Queue.Queue();
|
|
263
|
+
let canWrite1 = true;
|
|
264
|
+
let canWrite2 = true;
|
|
265
|
+
const future = this.forEach((v) => {
|
|
266
|
+
if (callback(v)) {
|
|
267
|
+
if (canWrite1) {
|
|
268
|
+
queue1.enqueue(v);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
if (canWrite2) {
|
|
273
|
+
queue2.enqueue(v);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (!canWrite1 && !canWrite2) {
|
|
277
|
+
future.cancel();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
return [
|
|
281
|
+
queue1.streamEntries.onCancellation(() => {
|
|
282
|
+
canWrite1 = false;
|
|
283
|
+
}),
|
|
284
|
+
queue2.streamEntries.onCancellation(() => {
|
|
285
|
+
canWrite2 = false;
|
|
286
|
+
}),
|
|
287
|
+
];
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Creates a new branch from the main stream, that monitors and collects values that matches the filter specified.
|
|
291
|
+
* Note, this does not trigger the main stream to run nor does it alter the main stream. It only collects matched
|
|
292
|
+
* records from main stream once main stream is running.
|
|
293
|
+
*
|
|
294
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
295
|
+
* stream)
|
|
296
|
+
* @param filter
|
|
297
|
+
* @param objectMaxSize max records to keep in queue, provided you start reading from this stream slower than data is
|
|
298
|
+
* being collected from main stream
|
|
299
|
+
* @param expiryPeriod
|
|
300
|
+
*/
|
|
301
|
+
subStream(filter, objectMaxSize, expiryPeriod) {
|
|
302
|
+
this.frozen = true;
|
|
303
|
+
const queue = new Queue.Queue(objectMaxSize, expiryPeriod);
|
|
304
|
+
this.monitorHooks.add((v) => {
|
|
305
|
+
if (filter(v))
|
|
306
|
+
queue.enqueue(v);
|
|
307
|
+
});
|
|
308
|
+
return queue.streamEntries;
|
|
309
|
+
}
|
|
248
310
|
/**
|
|
249
311
|
* Cancel the stream on the given signal
|
|
250
312
|
* @param signal
|
|
@@ -253,6 +315,38 @@ class Stream {
|
|
|
253
315
|
signal.addEventListener("abort", () => this.cancel());
|
|
254
316
|
return this;
|
|
255
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
320
|
+
* @param period
|
|
321
|
+
*/
|
|
322
|
+
waitFor(period) {
|
|
323
|
+
const action = () => future.Future.waitFor(this.internalNext(), period);
|
|
324
|
+
return new Stream((signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
325
|
+
return action()
|
|
326
|
+
.registerSignal(signal)
|
|
327
|
+
.thenApply(({ value }) => new stream_state.ExecutorState(value.done, value.value));
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
332
|
+
* @param period
|
|
333
|
+
*/
|
|
334
|
+
waitFirstFor(period) {
|
|
335
|
+
let i = 0;
|
|
336
|
+
const actions = [
|
|
337
|
+
() => future.Future.waitFor(this.internalNext(), period).thenApply(({ value }) => {
|
|
338
|
+
i = 1;
|
|
339
|
+
return value;
|
|
340
|
+
}),
|
|
341
|
+
() => this.internalNext(),
|
|
342
|
+
];
|
|
343
|
+
return new Stream((signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
344
|
+
const action = actions[i];
|
|
345
|
+
return action()
|
|
346
|
+
.registerSignal(signal)
|
|
347
|
+
.thenApply(({ value }) => new stream_state.ExecutorState(value.done, value.value));
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
256
350
|
parallel(concurrentlyLimit = 3) {
|
|
257
351
|
if (concurrentlyLimit < 1) {
|
|
258
352
|
throw new IllegalOperationError.IllegalOperationError("Cannot start parallel stream less than 2");
|
|
@@ -272,6 +366,8 @@ class Stream {
|
|
|
272
366
|
* @param callback
|
|
273
367
|
*/
|
|
274
368
|
map(callback) {
|
|
369
|
+
if (!this.canAlterStream)
|
|
370
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
275
371
|
this.actions.push({ type: ActionType.TRANSFORM, functor: callback });
|
|
276
372
|
return this;
|
|
277
373
|
}
|
|
@@ -280,6 +376,8 @@ class Stream {
|
|
|
280
376
|
* @param callback
|
|
281
377
|
*/
|
|
282
378
|
filter(callback) {
|
|
379
|
+
if (!this.canAlterStream)
|
|
380
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
283
381
|
this.actions.push({
|
|
284
382
|
type: ActionType.FILTER,
|
|
285
383
|
functor: (v) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -296,6 +394,8 @@ class Stream {
|
|
|
296
394
|
return this;
|
|
297
395
|
}
|
|
298
396
|
reduce(initialData, functor, exhaustive = true) {
|
|
397
|
+
if (!this.canAlterStream)
|
|
398
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
299
399
|
let previousData = initialData;
|
|
300
400
|
if (exhaustive) {
|
|
301
401
|
this.actions.push({
|
|
@@ -321,6 +421,8 @@ class Stream {
|
|
|
321
421
|
return this;
|
|
322
422
|
}
|
|
323
423
|
reduceWhile(predicate, initialData, functor, exhaustive = true) {
|
|
424
|
+
if (!this.canAlterStream)
|
|
425
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
324
426
|
let previousData = initialData;
|
|
325
427
|
if (exhaustive) {
|
|
326
428
|
this.actions.push({
|
|
@@ -397,6 +499,8 @@ class Stream {
|
|
|
397
499
|
* for the split criteria should be added to the chunk, if false then the data will be added to the next chunk
|
|
398
500
|
*/
|
|
399
501
|
chunk(value, keepSplitCriteria = false) {
|
|
502
|
+
if (!this.canAlterStream)
|
|
503
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
400
504
|
if (typeof value === "number" && value < 1)
|
|
401
505
|
throw new Error("Invalid chunk size");
|
|
402
506
|
let chunkedResults = [];
|
|
@@ -503,6 +607,8 @@ class Stream {
|
|
|
503
607
|
* @param count
|
|
504
608
|
*/
|
|
505
609
|
take(count) {
|
|
610
|
+
if (!this.canAlterStream)
|
|
611
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
506
612
|
let index = 0;
|
|
507
613
|
this.actions.push({
|
|
508
614
|
type: ActionType.LIMIT,
|
|
@@ -520,6 +626,8 @@ class Stream {
|
|
|
520
626
|
* @param predicate
|
|
521
627
|
*/
|
|
522
628
|
takeWhile(predicate) {
|
|
629
|
+
if (!this.canAlterStream)
|
|
630
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
523
631
|
this.actions.push({
|
|
524
632
|
type: ActionType.LIMIT,
|
|
525
633
|
functor: (value) => {
|
|
@@ -536,6 +644,8 @@ class Stream {
|
|
|
536
644
|
* @param predicate
|
|
537
645
|
*/
|
|
538
646
|
skipWhile(predicate) {
|
|
647
|
+
if (!this.canAlterStream)
|
|
648
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
539
649
|
let startFound = false;
|
|
540
650
|
this.actions.push({
|
|
541
651
|
type: ActionType.FILTER,
|
|
@@ -555,6 +665,8 @@ class Stream {
|
|
|
555
665
|
* @param expiryPeriod
|
|
556
666
|
*/
|
|
557
667
|
dropRepeats(uniqKeyExtractor, expiryPeriod = undefined) {
|
|
668
|
+
if (!this.canAlterStream)
|
|
669
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
558
670
|
const cache = new TimeableObject.TimeableObject(undefined, expiryPeriod);
|
|
559
671
|
this.actions.push({
|
|
560
672
|
type: ActionType.FILTER,
|
|
@@ -580,6 +692,8 @@ class Stream {
|
|
|
580
692
|
* @param count
|
|
581
693
|
*/
|
|
582
694
|
skip(count) {
|
|
695
|
+
if (!this.canAlterStream)
|
|
696
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
583
697
|
let index = 1;
|
|
584
698
|
this.actions.push({
|
|
585
699
|
type: ActionType.FILTER,
|
|
@@ -597,6 +711,8 @@ class Stream {
|
|
|
597
711
|
* @param period
|
|
598
712
|
*/
|
|
599
713
|
throttleBy(period) {
|
|
714
|
+
if (!this.canAlterStream)
|
|
715
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
600
716
|
let future$1;
|
|
601
717
|
this.actions.push({
|
|
602
718
|
type: ActionType.TRANSFORM,
|
|
@@ -616,6 +732,8 @@ class Stream {
|
|
|
616
732
|
* Flattens any nested structure from the data arriving on the stream
|
|
617
733
|
*/
|
|
618
734
|
flatten() {
|
|
735
|
+
if (!this.canAlterStream)
|
|
736
|
+
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
619
737
|
this.actions.push({
|
|
620
738
|
type: ActionType.UNPACK,
|
|
621
739
|
functor: (value) => {
|
|
@@ -772,6 +890,9 @@ class Stream {
|
|
|
772
890
|
const { state, value } = yield (this.sourceStream && this.concurrencyLimit
|
|
773
891
|
? this.forwardExecute().registerSignal(signal)
|
|
774
892
|
: this.__execute__().registerSignal(signal));
|
|
893
|
+
if (value !== null && value !== undefined) {
|
|
894
|
+
this.monitorHooks.forEach((hook) => hook(value));
|
|
895
|
+
}
|
|
775
896
|
if (state !== exports.State.CONTINUE) {
|
|
776
897
|
this.done = true;
|
|
777
898
|
this.invokeCompletionHooks();
|
|
@@ -991,6 +1112,9 @@ class Stream {
|
|
|
991
1112
|
const { state, value } = yield (this.sourceStream && this.concurrencyLimit
|
|
992
1113
|
? this.forwardExecute()
|
|
993
1114
|
: this.__execute__());
|
|
1115
|
+
if (value !== null && value !== undefined) {
|
|
1116
|
+
this.monitorHooks.forEach((hook) => hook(value));
|
|
1117
|
+
}
|
|
994
1118
|
if (state === exports.State.MATCHED && value !== undefined)
|
|
995
1119
|
return { done: false, value };
|
|
996
1120
|
if (state === exports.State.DONE) {
|
|
@@ -1148,6 +1272,9 @@ class Stream {
|
|
|
1148
1272
|
return resolve({ state: exports.State.CONTINUE });
|
|
1149
1273
|
}), signal);
|
|
1150
1274
|
}
|
|
1275
|
+
get canAlterStream() {
|
|
1276
|
+
return !this.frozen;
|
|
1277
|
+
}
|
|
1151
1278
|
}
|
|
1152
1279
|
|
|
1153
1280
|
exports.Stream = Stream;
|
package/stream.mjs
CHANGED
|
@@ -47,6 +47,8 @@ class Stream {
|
|
|
47
47
|
this.completionHookInvoked = false;
|
|
48
48
|
this.runLock = new Lock();
|
|
49
49
|
this.concurrencyLimit = 0;
|
|
50
|
+
this.monitorHooks = new Set();
|
|
51
|
+
this.frozen = false;
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Used to provide setup logic that should only be invoked once, when stream
|
|
@@ -224,6 +226,66 @@ class Stream {
|
|
|
224
226
|
},
|
|
225
227
|
});
|
|
226
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Breaks up a stream into 2 other streams based on the callback result. If callback result is true, data will go to
|
|
231
|
+
* the first stream, otherwise it will go to the second stream. Note that splitting the stream will immediately invoke
|
|
232
|
+
* the parent stream if it's not already running
|
|
233
|
+
*
|
|
234
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
235
|
+
* stream)
|
|
236
|
+
* @param callback
|
|
237
|
+
*/
|
|
238
|
+
split(callback) {
|
|
239
|
+
this.frozen = true;
|
|
240
|
+
const queue1 = new Queue();
|
|
241
|
+
const queue2 = new Queue();
|
|
242
|
+
let canWrite1 = true;
|
|
243
|
+
let canWrite2 = true;
|
|
244
|
+
const future = this.forEach((v) => {
|
|
245
|
+
if (callback(v)) {
|
|
246
|
+
if (canWrite1) {
|
|
247
|
+
queue1.enqueue(v);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
if (canWrite2) {
|
|
252
|
+
queue2.enqueue(v);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (!canWrite1 && !canWrite2) {
|
|
256
|
+
future.cancel();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
return [
|
|
260
|
+
queue1.streamEntries.onCancellation(() => {
|
|
261
|
+
canWrite1 = false;
|
|
262
|
+
}),
|
|
263
|
+
queue2.streamEntries.onCancellation(() => {
|
|
264
|
+
canWrite2 = false;
|
|
265
|
+
}),
|
|
266
|
+
];
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Creates a new branch from the main stream, that monitors and collects values that matches the filter specified.
|
|
270
|
+
* Note, this does not trigger the main stream to run nor does it alter the main stream. It only collects matched
|
|
271
|
+
* records from main stream once main stream is running.
|
|
272
|
+
*
|
|
273
|
+
* Important Note! This will freeze the parent stream (this means you cannot add additional transformers to the parent
|
|
274
|
+
* stream)
|
|
275
|
+
* @param filter
|
|
276
|
+
* @param objectMaxSize max records to keep in queue, provided you start reading from this stream slower than data is
|
|
277
|
+
* being collected from main stream
|
|
278
|
+
* @param expiryPeriod
|
|
279
|
+
*/
|
|
280
|
+
subStream(filter, objectMaxSize, expiryPeriod) {
|
|
281
|
+
this.frozen = true;
|
|
282
|
+
const queue = new Queue(objectMaxSize, expiryPeriod);
|
|
283
|
+
this.monitorHooks.add((v) => {
|
|
284
|
+
if (filter(v))
|
|
285
|
+
queue.enqueue(v);
|
|
286
|
+
});
|
|
287
|
+
return queue.streamEntries;
|
|
288
|
+
}
|
|
227
289
|
/**
|
|
228
290
|
* Cancel the stream on the given signal
|
|
229
291
|
* @param signal
|
|
@@ -232,6 +294,38 @@ class Stream {
|
|
|
232
294
|
signal.addEventListener("abort", () => this.cancel());
|
|
233
295
|
return this;
|
|
234
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
299
|
+
* @param period
|
|
300
|
+
*/
|
|
301
|
+
waitFor(period) {
|
|
302
|
+
const action = () => Future.waitFor(this.internalNext(), period);
|
|
303
|
+
return new Stream((signal) => __awaiter(this, void 0, void 0, function* () {
|
|
304
|
+
return action()
|
|
305
|
+
.registerSignal(signal)
|
|
306
|
+
.thenApply(({ value }) => new ExecutorState(value.done, value.value));
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
311
|
+
* @param period
|
|
312
|
+
*/
|
|
313
|
+
waitFirstFor(period) {
|
|
314
|
+
let i = 0;
|
|
315
|
+
const actions = [
|
|
316
|
+
() => Future.waitFor(this.internalNext(), period).thenApply(({ value }) => {
|
|
317
|
+
i = 1;
|
|
318
|
+
return value;
|
|
319
|
+
}),
|
|
320
|
+
() => this.internalNext(),
|
|
321
|
+
];
|
|
322
|
+
return new Stream((signal) => __awaiter(this, void 0, void 0, function* () {
|
|
323
|
+
const action = actions[i];
|
|
324
|
+
return action()
|
|
325
|
+
.registerSignal(signal)
|
|
326
|
+
.thenApply(({ value }) => new ExecutorState(value.done, value.value));
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
235
329
|
parallel(concurrentlyLimit = 3) {
|
|
236
330
|
if (concurrentlyLimit < 1) {
|
|
237
331
|
throw new IllegalOperationError("Cannot start parallel stream less than 2");
|
|
@@ -251,6 +345,8 @@ class Stream {
|
|
|
251
345
|
* @param callback
|
|
252
346
|
*/
|
|
253
347
|
map(callback) {
|
|
348
|
+
if (!this.canAlterStream)
|
|
349
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
254
350
|
this.actions.push({ type: ActionType.TRANSFORM, functor: callback });
|
|
255
351
|
return this;
|
|
256
352
|
}
|
|
@@ -259,6 +355,8 @@ class Stream {
|
|
|
259
355
|
* @param callback
|
|
260
356
|
*/
|
|
261
357
|
filter(callback) {
|
|
358
|
+
if (!this.canAlterStream)
|
|
359
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
262
360
|
this.actions.push({
|
|
263
361
|
type: ActionType.FILTER,
|
|
264
362
|
functor: (v) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -275,6 +373,8 @@ class Stream {
|
|
|
275
373
|
return this;
|
|
276
374
|
}
|
|
277
375
|
reduce(initialData, functor, exhaustive = true) {
|
|
376
|
+
if (!this.canAlterStream)
|
|
377
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
278
378
|
let previousData = initialData;
|
|
279
379
|
if (exhaustive) {
|
|
280
380
|
this.actions.push({
|
|
@@ -300,6 +400,8 @@ class Stream {
|
|
|
300
400
|
return this;
|
|
301
401
|
}
|
|
302
402
|
reduceWhile(predicate, initialData, functor, exhaustive = true) {
|
|
403
|
+
if (!this.canAlterStream)
|
|
404
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
303
405
|
let previousData = initialData;
|
|
304
406
|
if (exhaustive) {
|
|
305
407
|
this.actions.push({
|
|
@@ -376,6 +478,8 @@ class Stream {
|
|
|
376
478
|
* for the split criteria should be added to the chunk, if false then the data will be added to the next chunk
|
|
377
479
|
*/
|
|
378
480
|
chunk(value, keepSplitCriteria = false) {
|
|
481
|
+
if (!this.canAlterStream)
|
|
482
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
379
483
|
if (typeof value === "number" && value < 1)
|
|
380
484
|
throw new Error("Invalid chunk size");
|
|
381
485
|
let chunkedResults = [];
|
|
@@ -482,6 +586,8 @@ class Stream {
|
|
|
482
586
|
* @param count
|
|
483
587
|
*/
|
|
484
588
|
take(count) {
|
|
589
|
+
if (!this.canAlterStream)
|
|
590
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
485
591
|
let index = 0;
|
|
486
592
|
this.actions.push({
|
|
487
593
|
type: ActionType.LIMIT,
|
|
@@ -499,6 +605,8 @@ class Stream {
|
|
|
499
605
|
* @param predicate
|
|
500
606
|
*/
|
|
501
607
|
takeWhile(predicate) {
|
|
608
|
+
if (!this.canAlterStream)
|
|
609
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
502
610
|
this.actions.push({
|
|
503
611
|
type: ActionType.LIMIT,
|
|
504
612
|
functor: (value) => {
|
|
@@ -515,6 +623,8 @@ class Stream {
|
|
|
515
623
|
* @param predicate
|
|
516
624
|
*/
|
|
517
625
|
skipWhile(predicate) {
|
|
626
|
+
if (!this.canAlterStream)
|
|
627
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
518
628
|
let startFound = false;
|
|
519
629
|
this.actions.push({
|
|
520
630
|
type: ActionType.FILTER,
|
|
@@ -534,6 +644,8 @@ class Stream {
|
|
|
534
644
|
* @param expiryPeriod
|
|
535
645
|
*/
|
|
536
646
|
dropRepeats(uniqKeyExtractor, expiryPeriod = undefined) {
|
|
647
|
+
if (!this.canAlterStream)
|
|
648
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
537
649
|
const cache = new TimeableObject(undefined, expiryPeriod);
|
|
538
650
|
this.actions.push({
|
|
539
651
|
type: ActionType.FILTER,
|
|
@@ -559,6 +671,8 @@ class Stream {
|
|
|
559
671
|
* @param count
|
|
560
672
|
*/
|
|
561
673
|
skip(count) {
|
|
674
|
+
if (!this.canAlterStream)
|
|
675
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
562
676
|
let index = 1;
|
|
563
677
|
this.actions.push({
|
|
564
678
|
type: ActionType.FILTER,
|
|
@@ -576,6 +690,8 @@ class Stream {
|
|
|
576
690
|
* @param period
|
|
577
691
|
*/
|
|
578
692
|
throttleBy(period) {
|
|
693
|
+
if (!this.canAlterStream)
|
|
694
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
579
695
|
let future;
|
|
580
696
|
this.actions.push({
|
|
581
697
|
type: ActionType.TRANSFORM,
|
|
@@ -595,6 +711,8 @@ class Stream {
|
|
|
595
711
|
* Flattens any nested structure from the data arriving on the stream
|
|
596
712
|
*/
|
|
597
713
|
flatten() {
|
|
714
|
+
if (!this.canAlterStream)
|
|
715
|
+
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
598
716
|
this.actions.push({
|
|
599
717
|
type: ActionType.UNPACK,
|
|
600
718
|
functor: (value) => {
|
|
@@ -751,6 +869,9 @@ class Stream {
|
|
|
751
869
|
const { state, value } = yield (this.sourceStream && this.concurrencyLimit
|
|
752
870
|
? this.forwardExecute().registerSignal(signal)
|
|
753
871
|
: this.__execute__().registerSignal(signal));
|
|
872
|
+
if (value !== null && value !== undefined) {
|
|
873
|
+
this.monitorHooks.forEach((hook) => hook(value));
|
|
874
|
+
}
|
|
754
875
|
if (state !== State.CONTINUE) {
|
|
755
876
|
this.done = true;
|
|
756
877
|
this.invokeCompletionHooks();
|
|
@@ -970,6 +1091,9 @@ class Stream {
|
|
|
970
1091
|
const { state, value } = yield (this.sourceStream && this.concurrencyLimit
|
|
971
1092
|
? this.forwardExecute()
|
|
972
1093
|
: this.__execute__());
|
|
1094
|
+
if (value !== null && value !== undefined) {
|
|
1095
|
+
this.monitorHooks.forEach((hook) => hook(value));
|
|
1096
|
+
}
|
|
973
1097
|
if (state === State.MATCHED && value !== undefined)
|
|
974
1098
|
return { done: false, value };
|
|
975
1099
|
if (state === State.DONE) {
|
|
@@ -1127,6 +1251,9 @@ class Stream {
|
|
|
1127
1251
|
return resolve({ state: State.CONTINUE });
|
|
1128
1252
|
}), signal);
|
|
1129
1253
|
}
|
|
1254
|
+
get canAlterStream() {
|
|
1255
|
+
return !this.frozen;
|
|
1256
|
+
}
|
|
1130
1257
|
}
|
|
1131
1258
|
|
|
1132
1259
|
export { State, Stream };
|