gingersnap 0.23.0 → 0.23.2
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/README.md +25 -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 +10 -0
- package/stream/observable.cjs +24 -0
- package/stream/observable.d.ts +13 -0
- package/stream/observable.mjs +24 -0
- package/stream.cjs +32 -0
- package/stream.mjs +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## GingerSnap
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Description
|
|
5
|
+
Gingersnap is a general purpose library built with the aim of filling the gaps of javascript shortcomings. First-Class support for networking, IO operations and data validation is at the core of this library.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
To install the package, run `npm install gingersnap`
|
|
9
|
+
|
|
10
|
+
## Roadmap
|
|
11
|
+
- Support request timeout
|
|
12
|
+
- Opt out of using an authenticator for a method's request
|
|
13
|
+
- Support multiple authenticators, and setting Primary authenticator
|
|
14
|
+
- Allow methods to choose authenticator
|
|
15
|
+
- Support endpoint polling with subscription methods
|
|
16
|
+
- Support offline mode with resume feature once net is back
|
|
17
|
+
- Support default response when offline
|
|
18
|
+
- Support grouping requests, if one fail cancel all
|
|
19
|
+
- Support race requests, the first one that finishes/fails cancel all others and return the response
|
|
20
|
+
- Plugin support for services
|
|
21
|
+
- Support for NodeJs
|
|
22
|
+
- Push message support via subscribers
|
|
23
|
+
- Websocket support via subscribers, and methods for sending messages
|
|
24
|
+
- Websocket auth support
|
|
25
|
+
- Improved documentation
|
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.2","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
|
@@ -97,6 +97,16 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
97
97
|
* @param signal
|
|
98
98
|
*/
|
|
99
99
|
cancelOnSignal(signal: AbortSignal): this;
|
|
100
|
+
/**
|
|
101
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
102
|
+
* @param period
|
|
103
|
+
*/
|
|
104
|
+
waitFor(period: WaitPeriod): Stream<T>;
|
|
105
|
+
/**
|
|
106
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
107
|
+
* @param period
|
|
108
|
+
*/
|
|
109
|
+
waitFirstFor(period: WaitPeriod): Stream<T>;
|
|
100
110
|
parallel(concurrentlyLimit?: number): Stream<T>;
|
|
101
111
|
/**
|
|
102
112
|
* Transforms each data on the stream using the callback provided
|
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
|
@@ -253,6 +253,38 @@ class Stream {
|
|
|
253
253
|
signal.addEventListener("abort", () => this.cancel());
|
|
254
254
|
return this;
|
|
255
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
258
|
+
* @param period
|
|
259
|
+
*/
|
|
260
|
+
waitFor(period) {
|
|
261
|
+
const action = () => future.Future.waitFor(this.internalNext(), period);
|
|
262
|
+
return new Stream((signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
return action()
|
|
264
|
+
.registerSignal(signal)
|
|
265
|
+
.thenApply(({ value }) => new stream_state.ExecutorState(value.done, value.value));
|
|
266
|
+
}));
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
270
|
+
* @param period
|
|
271
|
+
*/
|
|
272
|
+
waitFirstFor(period) {
|
|
273
|
+
let i = 0;
|
|
274
|
+
const actions = [
|
|
275
|
+
() => future.Future.waitFor(this.internalNext(), period).thenApply(({ value }) => {
|
|
276
|
+
i = 1;
|
|
277
|
+
return value;
|
|
278
|
+
}),
|
|
279
|
+
() => this.internalNext(),
|
|
280
|
+
];
|
|
281
|
+
return new Stream((signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
282
|
+
const action = actions[i];
|
|
283
|
+
return action()
|
|
284
|
+
.registerSignal(signal)
|
|
285
|
+
.thenApply(({ value }) => new stream_state.ExecutorState(value.done, value.value));
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
256
288
|
parallel(concurrentlyLimit = 3) {
|
|
257
289
|
if (concurrentlyLimit < 1) {
|
|
258
290
|
throw new IllegalOperationError.IllegalOperationError("Cannot start parallel stream less than 2");
|
package/stream.mjs
CHANGED
|
@@ -232,6 +232,38 @@ class Stream {
|
|
|
232
232
|
signal.addEventListener("abort", () => this.cancel());
|
|
233
233
|
return this;
|
|
234
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Waits at most 'period' time for the data upstream to be received, otherwise will cancel the stream
|
|
237
|
+
* @param period
|
|
238
|
+
*/
|
|
239
|
+
waitFor(period) {
|
|
240
|
+
const action = () => Future.waitFor(this.internalNext(), period);
|
|
241
|
+
return new Stream((signal) => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
return action()
|
|
243
|
+
.registerSignal(signal)
|
|
244
|
+
.thenApply(({ value }) => new ExecutorState(value.done, value.value));
|
|
245
|
+
}));
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Waits at most 'period' time for the first data upstream to be received, otherwise will cancel the stream
|
|
249
|
+
* @param period
|
|
250
|
+
*/
|
|
251
|
+
waitFirstFor(period) {
|
|
252
|
+
let i = 0;
|
|
253
|
+
const actions = [
|
|
254
|
+
() => Future.waitFor(this.internalNext(), period).thenApply(({ value }) => {
|
|
255
|
+
i = 1;
|
|
256
|
+
return value;
|
|
257
|
+
}),
|
|
258
|
+
() => this.internalNext(),
|
|
259
|
+
];
|
|
260
|
+
return new Stream((signal) => __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
const action = actions[i];
|
|
262
|
+
return action()
|
|
263
|
+
.registerSignal(signal)
|
|
264
|
+
.thenApply(({ value }) => new ExecutorState(value.done, value.value));
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
235
267
|
parallel(concurrentlyLimit = 3) {
|
|
236
268
|
if (concurrentlyLimit < 1) {
|
|
237
269
|
throw new IllegalOperationError("Cannot start parallel stream less than 2");
|