speechflow 1.3.1 → 1.4.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/CHANGELOG.md +23 -0
- package/etc/stx.conf +54 -58
- package/package.json +25 -106
- package/{etc → speechflow-cli/etc}/eslint.mjs +1 -2
- package/speechflow-cli/etc/stx.conf +77 -0
- package/speechflow-cli/package.json +116 -0
- package/{src → speechflow-cli/src}/speechflow-node-a2a-gender.ts +148 -64
- package/speechflow-cli/src/speechflow-node-a2a-meter.ts +217 -0
- package/{src → speechflow-cli/src}/speechflow-node-a2a-mute.ts +39 -11
- package/speechflow-cli/src/speechflow-node-a2a-vad.ts +384 -0
- package/{src → speechflow-cli/src}/speechflow-node-a2a-wav.ts +27 -11
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +313 -0
- package/{src → speechflow-cli/src}/speechflow-node-t2a-elevenlabs.ts +59 -12
- package/{src → speechflow-cli/src}/speechflow-node-t2a-kokoro.ts +11 -4
- package/{src → speechflow-cli/src}/speechflow-node-t2t-deepl.ts +9 -4
- package/{src → speechflow-cli/src}/speechflow-node-t2t-format.ts +2 -2
- package/{src → speechflow-cli/src}/speechflow-node-t2t-ollama.ts +1 -1
- package/{src → speechflow-cli/src}/speechflow-node-t2t-openai.ts +1 -1
- package/{src → speechflow-cli/src}/speechflow-node-t2t-sentence.ts +37 -20
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +276 -0
- package/{src → speechflow-cli/src}/speechflow-node-t2t-transformers.ts +4 -3
- package/{src → speechflow-cli/src}/speechflow-node-x2x-filter.ts +9 -5
- package/{src → speechflow-cli/src}/speechflow-node-x2x-trace.ts +16 -8
- package/{src → speechflow-cli/src}/speechflow-node-xio-device.ts +12 -8
- package/{src → speechflow-cli/src}/speechflow-node-xio-file.ts +9 -3
- package/{src → speechflow-cli/src}/speechflow-node-xio-mqtt.ts +5 -2
- package/{src → speechflow-cli/src}/speechflow-node-xio-websocket.ts +12 -12
- package/{src → speechflow-cli/src}/speechflow-node.ts +7 -0
- package/{src → speechflow-cli/src}/speechflow-utils.ts +78 -44
- package/{src → speechflow-cli/src}/speechflow.ts +188 -53
- package/speechflow-ui-db/etc/eslint.mjs +106 -0
- package/speechflow-ui-db/etc/htmllint.json +55 -0
- package/speechflow-ui-db/etc/stx.conf +79 -0
- package/speechflow-ui-db/etc/stylelint.js +46 -0
- package/speechflow-ui-db/etc/stylelint.yaml +33 -0
- package/speechflow-ui-db/etc/tsc-client.json +30 -0
- package/speechflow-ui-db/etc/tsc.node.json +9 -0
- package/speechflow-ui-db/etc/vite-client.mts +63 -0
- package/speechflow-ui-db/package.d/htmllint-cli+0.0.7.patch +20 -0
- package/speechflow-ui-db/package.json +75 -0
- package/speechflow-ui-db/src/app-icon.ai +1989 -4
- package/speechflow-ui-db/src/app-icon.svg +26 -0
- package/speechflow-ui-db/src/app.styl +64 -0
- package/speechflow-ui-db/src/app.vue +221 -0
- package/speechflow-ui-db/src/index.html +23 -0
- package/speechflow-ui-db/src/index.ts +26 -0
- package/{dst/speechflow.d.ts → speechflow-ui-db/src/lib.d.ts} +5 -3
- package/speechflow-ui-db/src/tsconfig.json +3 -0
- package/speechflow-ui-st/etc/eslint.mjs +106 -0
- package/speechflow-ui-st/etc/htmllint.json +55 -0
- package/speechflow-ui-st/etc/stx.conf +79 -0
- package/speechflow-ui-st/etc/stylelint.js +46 -0
- package/speechflow-ui-st/etc/stylelint.yaml +33 -0
- package/speechflow-ui-st/etc/tsc-client.json +30 -0
- package/speechflow-ui-st/etc/tsc.node.json +9 -0
- package/speechflow-ui-st/etc/vite-client.mts +63 -0
- package/speechflow-ui-st/package.d/htmllint-cli+0.0.7.patch +20 -0
- package/speechflow-ui-st/package.json +79 -0
- package/speechflow-ui-st/src/app-icon.ai +1989 -4
- package/speechflow-ui-st/src/app-icon.svg +26 -0
- package/speechflow-ui-st/src/app.styl +64 -0
- package/speechflow-ui-st/src/app.vue +142 -0
- package/speechflow-ui-st/src/index.html +23 -0
- package/speechflow-ui-st/src/index.ts +26 -0
- package/speechflow-ui-st/src/lib.d.ts +9 -0
- package/speechflow-ui-st/src/tsconfig.json +3 -0
- package/dst/speechflow-node-a2a-ffmpeg.d.ts +0 -13
- package/dst/speechflow-node-a2a-ffmpeg.js +0 -153
- package/dst/speechflow-node-a2a-ffmpeg.js.map +0 -1
- package/dst/speechflow-node-a2a-gender.d.ts +0 -18
- package/dst/speechflow-node-a2a-gender.js +0 -271
- package/dst/speechflow-node-a2a-gender.js.map +0 -1
- package/dst/speechflow-node-a2a-meter.d.ts +0 -12
- package/dst/speechflow-node-a2a-meter.js +0 -155
- package/dst/speechflow-node-a2a-meter.js.map +0 -1
- package/dst/speechflow-node-a2a-mute.d.ts +0 -16
- package/dst/speechflow-node-a2a-mute.js +0 -91
- package/dst/speechflow-node-a2a-mute.js.map +0 -1
- package/dst/speechflow-node-a2a-vad.d.ts +0 -16
- package/dst/speechflow-node-a2a-vad.js +0 -285
- package/dst/speechflow-node-a2a-vad.js.map +0 -1
- package/dst/speechflow-node-a2a-wav.d.ts +0 -11
- package/dst/speechflow-node-a2a-wav.js +0 -195
- package/dst/speechflow-node-a2a-wav.js.map +0 -1
- package/dst/speechflow-node-a2t-deepgram.d.ts +0 -15
- package/dst/speechflow-node-a2t-deepgram.js +0 -255
- package/dst/speechflow-node-a2t-deepgram.js.map +0 -1
- package/dst/speechflow-node-t2a-elevenlabs.d.ts +0 -16
- package/dst/speechflow-node-t2a-elevenlabs.js +0 -195
- package/dst/speechflow-node-t2a-elevenlabs.js.map +0 -1
- package/dst/speechflow-node-t2a-kokoro.d.ts +0 -13
- package/dst/speechflow-node-t2a-kokoro.js +0 -149
- package/dst/speechflow-node-t2a-kokoro.js.map +0 -1
- package/dst/speechflow-node-t2t-deepl.d.ts +0 -15
- package/dst/speechflow-node-t2t-deepl.js +0 -142
- package/dst/speechflow-node-t2t-deepl.js.map +0 -1
- package/dst/speechflow-node-t2t-format.d.ts +0 -11
- package/dst/speechflow-node-t2t-format.js +0 -82
- package/dst/speechflow-node-t2t-format.js.map +0 -1
- package/dst/speechflow-node-t2t-ollama.d.ts +0 -13
- package/dst/speechflow-node-t2t-ollama.js +0 -247
- package/dst/speechflow-node-t2t-ollama.js.map +0 -1
- package/dst/speechflow-node-t2t-openai.d.ts +0 -13
- package/dst/speechflow-node-t2t-openai.js +0 -227
- package/dst/speechflow-node-t2t-openai.js.map +0 -1
- package/dst/speechflow-node-t2t-sentence.d.ts +0 -17
- package/dst/speechflow-node-t2t-sentence.js +0 -234
- package/dst/speechflow-node-t2t-sentence.js.map +0 -1
- package/dst/speechflow-node-t2t-subtitle.d.ts +0 -13
- package/dst/speechflow-node-t2t-subtitle.js +0 -278
- package/dst/speechflow-node-t2t-subtitle.js.map +0 -1
- package/dst/speechflow-node-t2t-transformers.d.ts +0 -14
- package/dst/speechflow-node-t2t-transformers.js +0 -265
- package/dst/speechflow-node-t2t-transformers.js.map +0 -1
- package/dst/speechflow-node-x2x-filter.d.ts +0 -11
- package/dst/speechflow-node-x2x-filter.js +0 -117
- package/dst/speechflow-node-x2x-filter.js.map +0 -1
- package/dst/speechflow-node-x2x-trace.d.ts +0 -11
- package/dst/speechflow-node-x2x-trace.js +0 -111
- package/dst/speechflow-node-x2x-trace.js.map +0 -1
- package/dst/speechflow-node-xio-device.d.ts +0 -13
- package/dst/speechflow-node-xio-device.js +0 -226
- package/dst/speechflow-node-xio-device.js.map +0 -1
- package/dst/speechflow-node-xio-file.d.ts +0 -11
- package/dst/speechflow-node-xio-file.js +0 -210
- package/dst/speechflow-node-xio-file.js.map +0 -1
- package/dst/speechflow-node-xio-mqtt.d.ts +0 -13
- package/dst/speechflow-node-xio-mqtt.js +0 -185
- package/dst/speechflow-node-xio-mqtt.js.map +0 -1
- package/dst/speechflow-node-xio-websocket.d.ts +0 -13
- package/dst/speechflow-node-xio-websocket.js +0 -278
- package/dst/speechflow-node-xio-websocket.js.map +0 -1
- package/dst/speechflow-node.d.ts +0 -65
- package/dst/speechflow-node.js +0 -180
- package/dst/speechflow-node.js.map +0 -1
- package/dst/speechflow-utils.d.ts +0 -69
- package/dst/speechflow-utils.js +0 -486
- package/dst/speechflow-utils.js.map +0 -1
- package/dst/speechflow.js +0 -768
- package/dst/speechflow.js.map +0 -1
- package/src/speechflow-node-a2a-meter.ts +0 -130
- package/src/speechflow-node-a2a-vad.ts +0 -285
- package/src/speechflow-node-a2t-deepgram.ts +0 -234
- package/src/speechflow-node-t2t-subtitle.ts +0 -149
- /package/{etc → speechflow-cli/etc}/biome.jsonc +0 -0
- /package/{etc → speechflow-cli/etc}/oxlint.jsonc +0 -0
- /package/{etc → speechflow-cli/etc}/speechflow.bat +0 -0
- /package/{etc → speechflow-cli/etc}/speechflow.sh +0 -0
- /package/{etc → speechflow-cli/etc}/speechflow.yaml +0 -0
- /package/{etc → speechflow-cli/etc}/tsconfig.json +0 -0
- /package/{package.d → speechflow-cli/package.d}/@ericedouard+vad-node-realtime+0.2.0.patch +0 -0
- /package/{src → speechflow-cli/src}/lib.d.ts +0 -0
- /package/{src → speechflow-cli/src}/speechflow-logo.ai +0 -0
- /package/{src → speechflow-cli/src}/speechflow-logo.svg +0 -0
- /package/{src → speechflow-cli/src}/speechflow-node-a2a-ffmpeg.ts +0 -0
- /package/{tsconfig.json → speechflow-cli/tsconfig.json} +0 -0
|
@@ -64,15 +64,15 @@ export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
|
|
|
64
64
|
const url = new URL(this.params.listen)
|
|
65
65
|
const websockets = new Set<ws.WebSocket>()
|
|
66
66
|
const chunkQueue = new utils.SingleQueue<SpeechFlowChunk>()
|
|
67
|
-
|
|
67
|
+
this.server = new ws.WebSocketServer({
|
|
68
68
|
host: url.hostname,
|
|
69
69
|
port: Number.parseInt(url.port),
|
|
70
70
|
path: url.pathname
|
|
71
71
|
})
|
|
72
|
-
server.on("listening", () => {
|
|
72
|
+
this.server.on("listening", () => {
|
|
73
73
|
this.log("info", `listening on URL ${this.params.listen}`)
|
|
74
74
|
})
|
|
75
|
-
server.on("connection", (ws, request) => {
|
|
75
|
+
this.server.on("connection", (ws, request) => {
|
|
76
76
|
const peer = `${request.socket.remoteAddress}:${request.socket.remotePort}`
|
|
77
77
|
this.log("info", `connection opened on URL ${this.params.listen} by peer ${peer}`)
|
|
78
78
|
websockets.add(ws)
|
|
@@ -105,7 +105,7 @@ export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
|
|
|
105
105
|
chunkQueue.write(chunk)
|
|
106
106
|
})
|
|
107
107
|
})
|
|
108
|
-
server.on("error", (error) => {
|
|
108
|
+
this.server.on("error", (error) => {
|
|
109
109
|
this.log("error", `error of some connection on URL ${this.params.listen}: ${error.message}`)
|
|
110
110
|
})
|
|
111
111
|
const type = this.params.type
|
|
@@ -124,7 +124,7 @@ export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
|
|
|
124
124
|
callback(new Error("still no Websocket connections available"))
|
|
125
125
|
else {
|
|
126
126
|
const data = utils.streamChunkEncode(chunk)
|
|
127
|
-
const results = []
|
|
127
|
+
const results: Promise<void>[] = []
|
|
128
128
|
for (const websocket of websockets.values()) {
|
|
129
129
|
results.push(new Promise<void>((resolve, reject) => {
|
|
130
130
|
websocket.send(data, (error) => {
|
|
@@ -175,12 +175,12 @@ export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
|
|
|
175
175
|
const chunkQueue = new utils.SingleQueue<SpeechFlowChunk>()
|
|
176
176
|
this.client.addEventListener("message", (ev: MessageEvent) => {
|
|
177
177
|
if (this.params.mode === "w") {
|
|
178
|
-
this.log("warning", `connection to URL ${this.params.
|
|
178
|
+
this.log("warning", `connection to URL ${this.params.connect}: ` +
|
|
179
179
|
"received remote data on write-only node")
|
|
180
180
|
return
|
|
181
181
|
}
|
|
182
182
|
if (!(ev.data instanceof ArrayBuffer)) {
|
|
183
|
-
this.log("warning", `connection to URL ${this.params.
|
|
183
|
+
this.log("warning", `connection to URL ${this.params.connect}: ` +
|
|
184
184
|
"received non-binary message")
|
|
185
185
|
return
|
|
186
186
|
}
|
|
@@ -204,15 +204,15 @@ export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
|
|
|
204
204
|
callback(new Error(`written chunk is not of ${type} type`))
|
|
205
205
|
else if (!client.OPEN)
|
|
206
206
|
callback(new Error("still no Websocket connection available"))
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
else {
|
|
208
|
+
const data = utils.streamChunkEncode(chunk)
|
|
209
|
+
client.send(data)
|
|
210
|
+
callback()
|
|
211
|
+
}
|
|
210
212
|
},
|
|
211
213
|
read (size: number) {
|
|
212
214
|
if (mode === "w")
|
|
213
215
|
throw new Error("read operation on write-only node")
|
|
214
|
-
if (!client.OPEN)
|
|
215
|
-
throw new Error("still no Websocket connection available")
|
|
216
216
|
chunkQueue.read().then((chunk) => {
|
|
217
217
|
this.push(chunk, "binary")
|
|
218
218
|
})
|
|
@@ -96,6 +96,13 @@ export default class SpeechFlowNode extends Events.EventEmitter {
|
|
|
96
96
|
this.emit("send-response", args)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/* emit dashboard information */
|
|
100
|
+
dashboardInfo (type: "audio", id: string, kind: "final" | "intermediate", value: number): void
|
|
101
|
+
dashboardInfo (type: "text", id: string, kind: "final" | "intermediate", value: string): void
|
|
102
|
+
dashboardInfo (type: "audio" | "text", id: string, kind: "final" | "intermediate", value: number | string): void {
|
|
103
|
+
this.emit("dashboard-info", { type, id, kind, value })
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
/* INTERNAL: utility function: create "params" attribute from constructor of sub-classes */
|
|
100
107
|
configure (spec: { [ id: string ]: { type: string, pos?: number, val?: any, match?: RegExp | ((x: any) => boolean) } }) {
|
|
101
108
|
for (const name of Object.keys(spec)) {
|
|
@@ -24,11 +24,19 @@ export function audioBufferDuration (
|
|
|
24
24
|
channels = 1,
|
|
25
25
|
littleEndian = true
|
|
26
26
|
) {
|
|
27
|
+
/* sanity check parameters */
|
|
27
28
|
if (!Buffer.isBuffer(buffer))
|
|
28
29
|
throw new Error("invalid input (Buffer expected)")
|
|
29
30
|
if (littleEndian !== true)
|
|
30
31
|
throw new Error("only Little Endian supported")
|
|
32
|
+
if (sampleRate <= 0)
|
|
33
|
+
throw new Error("sample rate must be positive")
|
|
34
|
+
if (bitDepth <= 0 || bitDepth % 8 !== 0)
|
|
35
|
+
throw new Error("bit depth must be positive and multiple of 8")
|
|
36
|
+
if (channels <= 0)
|
|
37
|
+
throw new Error("channels must be positive")
|
|
31
38
|
|
|
39
|
+
/* calculate duration */
|
|
32
40
|
const bytesPerSample = bitDepth / 8
|
|
33
41
|
const totalSamples = buffer.length / (bytesPerSample * channels)
|
|
34
42
|
return totalSamples / sampleRate
|
|
@@ -40,12 +48,23 @@ export function audioArrayDuration (
|
|
|
40
48
|
sampleRate = 48000,
|
|
41
49
|
channels = 1
|
|
42
50
|
) {
|
|
51
|
+
/* sanity check parameters */
|
|
52
|
+
if (arr.length === 0)
|
|
53
|
+
return 0
|
|
54
|
+
if (sampleRate <= 0)
|
|
55
|
+
throw new Error("sample rate must be positive")
|
|
56
|
+
if (channels <= 0)
|
|
57
|
+
throw new Error("channels must be positive")
|
|
58
|
+
|
|
59
|
+
/* calculate duration */
|
|
43
60
|
const totalSamples = arr.length / channels
|
|
44
61
|
return totalSamples / sampleRate
|
|
45
62
|
}
|
|
46
63
|
|
|
47
64
|
/* helper function: convert Buffer in PCM/I16 to Float32Array in PCM/F32 format */
|
|
48
65
|
export function convertBufToF32 (buf: Buffer, littleEndian = true) {
|
|
66
|
+
if (buf.length % 2 !== 0)
|
|
67
|
+
throw new Error("buffer length must be even for 16-bit samples")
|
|
49
68
|
const dataView = new DataView(buf.buffer)
|
|
50
69
|
const arr = new Float32Array(buf.length / 2)
|
|
51
70
|
for (let i = 0; i < arr.length; i++)
|
|
@@ -55,9 +74,15 @@ export function convertBufToF32 (buf: Buffer, littleEndian = true) {
|
|
|
55
74
|
|
|
56
75
|
/* helper function: convert Float32Array in PCM/F32 to Buffer in PCM/I16 format */
|
|
57
76
|
export function convertF32ToBuf (arr: Float32Array) {
|
|
77
|
+
if (arr.length === 0)
|
|
78
|
+
return Buffer.alloc(0)
|
|
58
79
|
const int16Array = new Int16Array(arr.length)
|
|
59
|
-
for (let i = 0; i < arr.length; i++)
|
|
60
|
-
|
|
80
|
+
for (let i = 0; i < arr.length; i++) {
|
|
81
|
+
let sample = arr[i]
|
|
82
|
+
if (Number.isNaN(sample))
|
|
83
|
+
sample = 0
|
|
84
|
+
int16Array[i] = Math.max(-32768, Math.min(32767, Math.round(sample * 32768)))
|
|
85
|
+
}
|
|
61
86
|
return Buffer.from(int16Array.buffer)
|
|
62
87
|
}
|
|
63
88
|
|
|
@@ -274,26 +299,19 @@ export class QueuePointer<T extends QueueElement> extends EventEmitter {
|
|
|
274
299
|
}
|
|
275
300
|
position (index?: number): number {
|
|
276
301
|
if (index !== undefined) {
|
|
277
|
-
this.index = index
|
|
278
|
-
if (this.index < 0)
|
|
279
|
-
this.index = 0
|
|
280
|
-
else if (this.index >= this.queue.elements.length)
|
|
281
|
-
this.index = this.queue.elements.length
|
|
302
|
+
this.index = Math.max(0, Math.min(index, this.queue.elements.length))
|
|
282
303
|
this.emit("position", this.index)
|
|
283
304
|
}
|
|
284
305
|
return this.index
|
|
285
306
|
}
|
|
286
307
|
walk (num: number) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
308
|
+
const indexOld = this.index
|
|
309
|
+
if (num > 0)
|
|
310
|
+
this.index = Math.min(this.index + num, this.queue.elements.length)
|
|
311
|
+
else if (num < 0)
|
|
312
|
+
this.index = Math.max(this.index + num, 0)
|
|
313
|
+
if (this.index !== indexOld)
|
|
290
314
|
this.emit("position", { start: this.index })
|
|
291
|
-
}
|
|
292
|
-
else if (num < 0) {
|
|
293
|
-
for (let i = 0; i < Math.abs(num) && this.index > 0; i++)
|
|
294
|
-
this.index--
|
|
295
|
-
this.emit("position", { start: this.index })
|
|
296
|
-
}
|
|
297
315
|
}
|
|
298
316
|
walkForwardUntil (type: T["type"]) {
|
|
299
317
|
while (this.index < this.queue.elements.length
|
|
@@ -330,12 +348,7 @@ export class QueuePointer<T extends QueueElement> extends EventEmitter {
|
|
|
330
348
|
peek (position?: number) {
|
|
331
349
|
if (position === undefined)
|
|
332
350
|
position = this.index
|
|
333
|
-
|
|
334
|
-
if (position < 0)
|
|
335
|
-
position = 0
|
|
336
|
-
else if (position > this.queue.elements.length)
|
|
337
|
-
position = this.queue.elements.length
|
|
338
|
-
}
|
|
351
|
+
position = Math.max(0, Math.min(position, this.queue.elements.length))
|
|
339
352
|
const element = this.queue.elements[position]
|
|
340
353
|
this.queue.emit("read", { start: position, end: position })
|
|
341
354
|
return element
|
|
@@ -351,11 +364,8 @@ export class QueuePointer<T extends QueueElement> extends EventEmitter {
|
|
|
351
364
|
let slice: T[]
|
|
352
365
|
const start = this.index
|
|
353
366
|
if (size !== undefined) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
else if (size > this.queue.elements.length - this.index)
|
|
357
|
-
size = this.queue.elements.length - this.index
|
|
358
|
-
slice = this.queue.elements.slice(this.index, size)
|
|
367
|
+
size = Math.max(0, Math.min(size, this.queue.elements.length - this.index))
|
|
368
|
+
slice = this.queue.elements.slice(this.index, this.index + size)
|
|
359
369
|
this.index += size
|
|
360
370
|
}
|
|
361
371
|
else {
|
|
@@ -415,45 +425,58 @@ export class Queue<T extends QueueElement> extends EventEmitter {
|
|
|
415
425
|
min = pointer.position()
|
|
416
426
|
|
|
417
427
|
/* trim the maximum amount of first elements */
|
|
418
|
-
|
|
428
|
+
if (min > 0) {
|
|
429
|
+
this.elements.splice(0, min)
|
|
419
430
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
431
|
+
/* shift all pointers */
|
|
432
|
+
for (const pointer of this.pointers.values())
|
|
433
|
+
pointer.position(pointer.position() - min)
|
|
434
|
+
}
|
|
423
435
|
}
|
|
424
436
|
}
|
|
425
437
|
|
|
426
438
|
/* utility class for wrapping a custom stream into a regular Transform stream */
|
|
427
439
|
export class StreamWrapper extends Stream.Transform {
|
|
428
440
|
private foreignStream: any
|
|
441
|
+
private onData = (chunk: any) => { this.push(chunk) }
|
|
442
|
+
private onError = (err: Error) => { this.emit("error", err) }
|
|
443
|
+
private onEnd = () => { this.push(null) }
|
|
429
444
|
constructor (foreignStream: any, options: Stream.TransformOptions = {}) {
|
|
430
445
|
options.readableObjectMode = true
|
|
431
446
|
options.writableObjectMode = true
|
|
432
447
|
super(options)
|
|
433
448
|
this.foreignStream = foreignStream
|
|
434
|
-
this.foreignStream.on
|
|
435
|
-
this.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
})
|
|
440
|
-
this.foreignStream.on("end", () => {
|
|
441
|
-
this.push(null)
|
|
442
|
-
})
|
|
449
|
+
if (typeof this.foreignStream.on === "function") {
|
|
450
|
+
this.foreignStream.on("data", this.onData)
|
|
451
|
+
this.foreignStream.on("error", this.onError)
|
|
452
|
+
this.foreignStream.on("end", this.onEnd)
|
|
453
|
+
}
|
|
443
454
|
}
|
|
444
455
|
_transform (chunk: any, encoding: BufferEncoding, callback: Stream.TransformCallback): void {
|
|
456
|
+
if (this.destroyed) {
|
|
457
|
+
callback(new Error("stream already destroyed"))
|
|
458
|
+
return
|
|
459
|
+
}
|
|
445
460
|
try {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
461
|
+
if (typeof this.foreignStream.write === "function") {
|
|
462
|
+
const canContinue = this.foreignStream.write(chunk)
|
|
463
|
+
if (canContinue)
|
|
464
|
+
callback()
|
|
465
|
+
else
|
|
466
|
+
this.foreignStream.once("drain", callback)
|
|
467
|
+
}
|
|
449
468
|
else
|
|
450
|
-
|
|
469
|
+
throw new Error("foreign stream lacks write method")
|
|
451
470
|
}
|
|
452
471
|
catch (err) {
|
|
453
472
|
callback(err as Error)
|
|
454
473
|
}
|
|
455
474
|
}
|
|
456
475
|
_flush (callback: Stream.TransformCallback): void {
|
|
476
|
+
if (this.destroyed) {
|
|
477
|
+
callback(new Error("stream already destroyed"))
|
|
478
|
+
return
|
|
479
|
+
}
|
|
457
480
|
try {
|
|
458
481
|
if (typeof this.foreignStream.end === "function")
|
|
459
482
|
this.foreignStream.end()
|
|
@@ -463,6 +486,14 @@ export class StreamWrapper extends Stream.Transform {
|
|
|
463
486
|
callback(err as Error)
|
|
464
487
|
}
|
|
465
488
|
}
|
|
489
|
+
_destroy (error: Error | null, callback: Stream.TransformCallback): void {
|
|
490
|
+
if (typeof this.foreignStream.removeListener === "function") {
|
|
491
|
+
this.foreignStream.removeListener("data", this.onData)
|
|
492
|
+
this.foreignStream.removeListener("error", this.onError)
|
|
493
|
+
this.foreignStream.removeListener("end", this.onEnd)
|
|
494
|
+
}
|
|
495
|
+
super._destroy(error, callback)
|
|
496
|
+
}
|
|
466
497
|
}
|
|
467
498
|
|
|
468
499
|
/* meta store */
|
|
@@ -485,4 +516,7 @@ export class TimeStore<T> extends EventEmitter {
|
|
|
485
516
|
if (interval.low < before && interval.high < before)
|
|
486
517
|
this.tree.remove(interval)
|
|
487
518
|
}
|
|
519
|
+
clear (): void {
|
|
520
|
+
this.tree = new IntervalTree.IntervalTree<TimeStoreInterval<T>>()
|
|
521
|
+
}
|
|
488
522
|
}
|