@miso.ai/server-commons 0.6.3-beta.9 → 0.6.4-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -20,5 +20,5 @@
20
20
  "uuid": "^9.0.0",
21
21
  "yargs": "^17.5.1"
22
22
  },
23
- "version": "0.6.3-beta.9"
23
+ "version": "0.6.4-beta.0"
24
24
  }
@@ -0,0 +1,41 @@
1
+ import EventEmitter from 'events';
2
+
3
+ export default class TaskControl {
4
+
5
+ constructor() {
6
+ this._events = new EventEmitter();
7
+ this._ready = true;
8
+ }
9
+
10
+ on(event, listener) {
11
+ this._events.on(event, listener);
12
+ return () => this._events.off(event, listener);
13
+ }
14
+
15
+ once(event, listener) {
16
+ this._events.once(event, listener);
17
+ return () => this._events.off(event, listener);
18
+ }
19
+
20
+ open(id, data) {}
21
+
22
+ close(id) {}
23
+
24
+ get ready() {
25
+ return this._ready;
26
+ }
27
+
28
+ _setReady(value) {
29
+ value = !!value
30
+ if (this._ready === value) {
31
+ return;
32
+ }
33
+ this._ready = value;
34
+ this._events.emit('ready', value);
35
+ }
36
+
37
+ destroy() {
38
+ this._events.removeAllListeners();
39
+ }
40
+
41
+ }
@@ -0,0 +1,38 @@
1
+ import TaskControl from './base.js';
2
+
3
+ export default class CollectiveTaskControl extends TaskControl {
4
+
5
+ constructor(...members) {
6
+ super();
7
+ this._members = members;
8
+ this._unsubscribes = members.map((control) => control.on('ready', () => this._syncReady()));
9
+ this._syncReady();
10
+ }
11
+
12
+ open(id, data) {
13
+ for (const control of this._members) {
14
+ control.open(id, data);
15
+ }
16
+ }
17
+
18
+ close(id) {
19
+ for (const control of this._members) {
20
+ control.close(id);
21
+ }
22
+ }
23
+
24
+ _syncReady() {
25
+ this._setReady(this._members.every((control) => control.ready));
26
+ }
27
+
28
+ destroy() {
29
+ for (const unsubscribe of this._unsubscribes) {
30
+ unsubscribe();
31
+ }
32
+ for (const control of this._members) {
33
+ control.destroy();
34
+ }
35
+ super.destroy();
36
+ }
37
+
38
+ }
@@ -0,0 +1,22 @@
1
+ import TaskControl from './base.js';
2
+ import CollectiveTaskControl from './collective.js';
3
+ import WaterMarkTaskControl from './watermark.js';
4
+ import ThrottledTaskControl from './throttle.js';
5
+
6
+ export function createTaskControl({
7
+ highWaterMark,
8
+ throttle,
9
+ } = {}) {
10
+ const controls = [];
11
+ if (highWaterMark) {
12
+ controls.push(new WaterMarkTaskControl({
13
+ highWaterMark,
14
+ }));
15
+ }
16
+ if (throttle) {
17
+ controls.push(new ThrottledTaskControl({
18
+ interval: throttle,
19
+ }));
20
+ }
21
+ return controls.length > 0 ? new CollectiveTaskControl(...controls) : new TaskControl();
22
+ }
@@ -0,0 +1,5 @@
1
+ export { default as TaskControl } from './base.js';
2
+ export { default as CollectiveTaskControl } from './collective.js';
3
+ export { default as WaterMarkTaskControl } from './watermark.js';
4
+ export { default as ThrottledTaskControl } from './throttle.js';
5
+ export { createTaskControl } from './create.js';
@@ -0,0 +1,28 @@
1
+ import TaskControl from './base.js';
2
+
3
+ export default class ThrottledTaskControl extends TaskControl {
4
+
5
+ constructor({
6
+ interval,
7
+ }) {
8
+ super();
9
+ if (typeof interval !== 'number' || interval <= 0) {
10
+ throw new Error(`interval must be a positive number: ${interval}`);
11
+ }
12
+ this._interval = interval;
13
+ }
14
+
15
+ get interval() {
16
+ return this._interval;
17
+ }
18
+
19
+ open(id, data) {
20
+ this._setReady(false);
21
+ this._timeoutId && clearTimeout(this._timeoutId);
22
+ this._timeoutId = setTimeout(() => {
23
+ this._setReady(true);
24
+ this._timeoutId = undefined;
25
+ }, this._interval);
26
+ }
27
+
28
+ }
@@ -0,0 +1,34 @@
1
+ import TaskControl from './base.js';
2
+
3
+ export default class WaterMarkTaskControl extends TaskControl{
4
+
5
+ constructor({
6
+ highWaterMark,
7
+ }) {
8
+ super();
9
+ if (!Number.isInteger(highWaterMark) || highWaterMark <= 0) {
10
+ throw new Error('highWaterMark must be a positive integer');
11
+ }
12
+ this._highWaterMark = highWaterMark;
13
+ this._waterLevel = 0;
14
+ }
15
+
16
+ get waterLevel() {
17
+ return this._waterLevel;
18
+ }
19
+
20
+ open(id, data) {
21
+ this._waterLevel++;
22
+ this._syncReady();
23
+ }
24
+
25
+ close(id) {
26
+ this._waterLevel--;
27
+ this._syncReady();
28
+ }
29
+
30
+ _syncReady() {
31
+ this._setReady(this._waterLevel < this._highWaterMark);
32
+ }
33
+
34
+ }
package/src/date.js CHANGED
@@ -29,6 +29,10 @@ export function parseDuration(expr, unit) {
29
29
  return value * ts;
30
30
  }
31
31
 
32
+ export function getYear(dateStr) {
33
+ return new Date(dateStr).getFullYear();
34
+ }
35
+
32
36
  export function startOfDate(expr) {
33
37
  if (expr === undefined) {
34
38
  return undefined;
@@ -24,12 +24,13 @@ export default class BufferedReadStream extends Readable {
24
24
  this._strategy.initialize(this, source);
25
25
  }
26
26
 
27
- async _construct() {
27
+ async _construct(done) {
28
28
  if (this._source.init) {
29
29
  this._debug(`[BufferedReadStream] init source start`);
30
30
  await this._source.init();
31
31
  this._debug(`[BufferedReadStream] init source done`);
32
32
  }
33
+ done();
33
34
  }
34
35
 
35
36
  async _read() {
@@ -76,10 +76,11 @@ export default class BufferedWriteStream extends Transform {
76
76
  done();
77
77
  }
78
78
 
79
- async _transform(record, _) {
79
+ async _transform(record, _, next) {
80
80
  this._pushStartEventIfNecessary();
81
81
  this._dispatchAll(this._buffer.push(record));
82
82
  await this._pauseIfNecessary();
83
+ next();
83
84
  }
84
85
 
85
86
  async _flush(done) {
@@ -49,13 +49,14 @@ export default class DiffStream extends Transform {
49
49
  }
50
50
  }
51
51
 
52
- async _transform(value, _) {
52
+ _transform(value, _, next) {
53
53
  if (value instanceof Buffer) {
54
54
  value = value.toString();
55
55
  }
56
56
  // dedupe
57
57
  const input = this._inputDataSet;
58
58
  if (input.has(value)) {
59
+ next();
59
60
  return;
60
61
  }
61
62
  input.add(value);
@@ -66,6 +67,7 @@ export default class DiffStream extends Transform {
66
67
  } else {
67
68
  this._output(true, value);
68
69
  }
70
+ next();
69
71
  }
70
72
 
71
73
  async _flush(done) {
@@ -5,3 +5,4 @@ export { default as BufferedWriteStream } from './buffered-write.js';
5
5
  export { default as OutputStream } from './output.js';
6
6
  export { default as LogUpdateStream } from './log-update.js';
7
7
  export { default as DiffStream } from './diff.js';
8
+ export { default as ParallelTransform } from './parallel-transform.js';
@@ -35,13 +35,6 @@ export async function pipeline(...streams) {
35
35
  return new Promise((resolve, reject) => _pipeline(...streams.filter(s => s), err => err ? reject(err) : resolve()));
36
36
  }
37
37
 
38
- export async function pipelineToStdout(...streams) {
39
- return new Promise((resolve, reject) =>
40
- _pipeline(...streams, err => err ? reject(err) : resolve())
41
- .pipe(process.stdout, { end: false })
42
- );
43
- }
44
-
45
38
  export async function collect(stream) {
46
39
  const records = [];
47
40
  for await (const record of stream) {
@@ -72,7 +65,7 @@ export function take(n, { transform: _, ...options } = {}) {
72
65
  let count = 0;
73
66
  return new Transform({
74
67
  ...options,
75
- transform (chunk, _, next) {
68
+ transform(chunk, _, next) {
76
69
  if (count > n) {
77
70
  next(undefined);
78
71
  this.end();
@@ -0,0 +1,82 @@
1
+ import { Duplex } from 'stream';
2
+ import { v4 as uuid } from 'uuid';
3
+ import { createTaskControl } from '../control/index.js';
4
+
5
+ export default class ParallelTransform extends Duplex {
6
+
7
+ constructor({
8
+ transform,
9
+ controls,
10
+ ...options
11
+ } = {}) {
12
+ super(options);
13
+ if (transform !== undefined && typeof transform !== 'function') {
14
+ throw new Error('transform must be a function');
15
+ }
16
+ this._transformFn = transform;
17
+ this._control = createTaskControl(controls);
18
+
19
+ this._next = undefined;
20
+ this._pushPaused = false;
21
+ this._outputBuffer;
22
+
23
+ this._control.on('ready', (ready) => ready && this._callNext());
24
+ this.on('drain', () => this._handleDrain());
25
+ }
26
+
27
+ async _transformFn(chunk, encoding) {
28
+ throw new Error('transform function not defined');
29
+ }
30
+
31
+ _write(chunk, encoding, next) {
32
+ const id = uuid();
33
+ this._next = next;
34
+ this._control.open(id, [chunk, encoding]);
35
+ (async () => {
36
+ try {
37
+ const output = await this._transformFn(chunk, encoding);
38
+ this._control.close(id);
39
+ this._writeOutput(output);
40
+ } catch (error) {
41
+ this._error(error);
42
+ }
43
+ })();
44
+ this._callNext();
45
+ }
46
+
47
+ _callNext() {
48
+ if (this._next && this._control.ready) {
49
+ const next = this._next;
50
+ this._next = undefined;
51
+ next();
52
+ }
53
+ }
54
+
55
+ _writeOutput(output) {
56
+ if (this._outputBuffer) {
57
+ this._outputBuffer.push(output);
58
+ } else if (!this.push(output)) {
59
+ this._outputBuffer = [];
60
+ }
61
+ }
62
+
63
+ _handleDrain() {
64
+ if (!this._outputBuffer) {
65
+ return;
66
+ }
67
+ const buffer = this._outputBuffer;
68
+ for (let i = 0, len = buffer.length; i < len; i++) {
69
+ if (!this.push(buffer[i])) {
70
+ this._outputBuffer = buffer.slice(i + 1);
71
+ break;
72
+ }
73
+ }
74
+ }
75
+
76
+ _read() {}
77
+
78
+ _error(error) {
79
+ this.emit('error', error);
80
+ }
81
+
82
+ }