thread-stream 0.11.2 → 0.13.1

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/index.js CHANGED
@@ -10,6 +10,9 @@ const {
10
10
  READ_INDEX
11
11
  } = require('./lib/indexes')
12
12
  const buffer = require('buffer')
13
+ const assert = require('assert')
14
+
15
+ const kImpl = Symbol('kImpl')
13
16
 
14
17
  // V8 limit for string size
15
18
  const MAX_STRING = buffer.constants.MAX_STRING_LENGTH
@@ -41,7 +44,8 @@ const registry = new FinalizationRegistry((worker) => {
41
44
  function createWorker (stream, opts) {
42
45
  const { filename, workerData } = opts
43
46
 
44
- const toExecute = join(__dirname, 'lib', 'worker.js')
47
+ const bundlerOverrides = '__bundlerPathsOverrides' in globalThis ? globalThis.__bundlerPathsOverrides : {}
48
+ const toExecute = bundlerOverrides['thread-stream-worker'] || join(__dirname, 'lib', 'worker.js')
45
49
 
46
50
  const worker = new Worker(toExecute, {
47
51
  ...opts.workerOpts,
@@ -49,8 +53,8 @@ function createWorker (stream, opts) {
49
53
  filename: filename.indexOf('file://') === 0
50
54
  ? filename
51
55
  : pathToFileURL(filename).href,
52
- dataBuf: stream._dataBuf,
53
- stateBuf: stream._stateBuf,
56
+ dataBuf: stream[kImpl].dataBuf,
57
+ stateBuf: stream[kImpl].stateBuf,
54
58
  workerData
55
59
  }
56
60
  })
@@ -67,57 +71,62 @@ function createWorker (stream, opts) {
67
71
  }
68
72
 
69
73
  function drain (stream) {
70
- stream.needDrain = false
71
- stream.emit('drain')
74
+ assert(!stream[kImpl].sync)
75
+ if (stream[kImpl].needDrain) {
76
+ stream[kImpl].needDrain = false
77
+ stream.emit('drain')
78
+ }
72
79
  }
73
80
 
74
81
  function nextFlush (stream) {
75
- const writeIndex = Atomics.load(stream._state, WRITE_INDEX)
76
- let leftover = stream._data.length - writeIndex
82
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
83
+ let leftover = stream[kImpl].data.length - writeIndex
77
84
 
78
85
  if (leftover > 0) {
79
- if (stream.buf.length === 0) {
80
- stream.flushing = false
81
- if (!stream.needDrain) {
82
- // process._rawDebug('emitting drain')
83
- stream.needDrain = true
86
+ if (stream[kImpl].buf.length === 0) {
87
+ stream[kImpl].flushing = false
88
+
89
+ if (stream[kImpl].ending) {
90
+ end(stream)
91
+ } else if (stream[kImpl].needDrain) {
84
92
  process.nextTick(drain, stream)
85
93
  }
94
+
86
95
  return
87
96
  }
88
97
 
89
- let toWrite = stream.buf.slice(0, leftover)
98
+ let toWrite = stream[kImpl].buf.slice(0, leftover)
90
99
  let toWriteBytes = Buffer.byteLength(toWrite)
91
100
  if (toWriteBytes <= leftover) {
92
- stream.buf = stream.buf.slice(leftover)
101
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
93
102
  // process._rawDebug('writing ' + toWrite.length)
94
- stream._write(toWrite, nextFlush.bind(null, stream))
103
+ write(stream, toWrite, nextFlush.bind(null, stream))
95
104
  } else {
96
105
  // multi-byte utf-8
97
106
  stream.flush(() => {
98
- Atomics.store(stream._state, READ_INDEX, 0)
99
- Atomics.store(stream._state, WRITE_INDEX, 0)
107
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
108
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
100
109
 
101
110
  // Find a toWrite length that fits the buffer
102
111
  // it must exists as the buffer is at least 4 bytes length
103
112
  // and the max utf-8 length for a char is 4 bytes.
104
- while (toWriteBytes > stream.buf.length) {
113
+ while (toWriteBytes > stream[kImpl].buf.length) {
105
114
  leftover = leftover / 2
106
- toWrite = stream.buf.slice(0, leftover)
115
+ toWrite = stream[kImpl].buf.slice(0, leftover)
107
116
  toWriteBytes = Buffer.byteLength(toWrite)
108
117
  }
109
- stream.buf = stream.buf.slice(leftover)
110
- stream._write(toWrite, nextFlush.bind(null, stream))
118
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
119
+ write(stream, toWrite, nextFlush.bind(null, stream))
111
120
  })
112
121
  }
113
122
  } else if (leftover === 0) {
114
- if (writeIndex === 0 && stream.buf.length === 0) {
123
+ if (writeIndex === 0 && stream[kImpl].buf.length === 0) {
115
124
  // we had a flushSync in the meanwhile
116
125
  return
117
126
  }
118
127
  stream.flush(() => {
119
- Atomics.store(stream._state, READ_INDEX, 0)
120
- Atomics.store(stream._state, WRITE_INDEX, 0)
128
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
129
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
121
130
  nextFlush(stream)
122
131
  })
123
132
  } else {
@@ -140,29 +149,14 @@ function onWorkerMessage (msg) {
140
149
  // Replace the FakeWeakRef with a
141
150
  // proper one.
142
151
  this.stream = new WeakRef(stream)
143
- if (stream._sync) {
144
- stream.ready = true
145
- stream.flushSync()
152
+
153
+ stream.flush(() => {
154
+ stream[kImpl].ready = true
146
155
  stream.emit('ready')
147
- } else {
148
- stream.once('drain', function () {
149
- stream.flush(() => {
150
- stream.ready = true
151
- stream.emit('ready')
152
- })
153
- })
154
- nextFlush(stream)
155
- }
156
+ })
156
157
  break
157
158
  case 'ERROR':
158
- stream.closed = true
159
- stream.worker.exited = true
160
- // TODO only remove our own
161
- stream.worker.removeAllListeners('exit')
162
- stream.worker.terminate().then(null, () => {})
163
- process.nextTick(() => {
164
- stream.emit('error', msg.err)
165
- })
159
+ destroy(stream, msg.err)
166
160
  break
167
161
  default:
168
162
  throw new Error('this should not happen: ' + msg.code)
@@ -176,14 +170,9 @@ function onWorkerExit (code) {
176
170
  return
177
171
  }
178
172
  registry.unregister(stream)
179
- stream.closed = true
180
173
  stream.worker.exited = true
181
- setImmediate(function () {
182
- if (code !== 0) {
183
- stream.emit('error', new Error('The worker thread exited'))
184
- }
185
- stream.emit('close')
186
- })
174
+ stream.worker.off('exit', onWorkerExit)
175
+ destroy(stream, code !== 0 ? new Error('The worker thread exited') : null)
187
176
  }
188
177
 
189
178
  class ThreadStream extends EventEmitter {
@@ -194,125 +183,88 @@ class ThreadStream extends EventEmitter {
194
183
  throw new Error('bufferSize must at least fit a 4-byte utf-8 char')
195
184
  }
196
185
 
197
- this._stateBuf = new SharedArrayBuffer(128)
198
- this._state = new Int32Array(this._stateBuf)
199
- this._dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024)
200
- this._data = Buffer.from(this._dataBuf)
201
- this._sync = opts.sync || false
202
- this.worker = createWorker(this, opts)
203
- this.ready = false
204
- this.ending = false
205
- this.needDrain = false
206
- this.closed = false
207
-
208
- this.buf = ''
209
- }
210
-
211
- _write (data, cb) {
212
- // data is smaller than the shared buffer length
213
- const current = Atomics.load(this._state, WRITE_INDEX)
214
- const length = Buffer.byteLength(data)
215
- this._data.write(data, current)
216
- Atomics.store(this._state, WRITE_INDEX, current + length)
217
- Atomics.notify(this._state, WRITE_INDEX)
218
- cb()
219
- return true
220
- }
221
-
222
- _hasSpace () {
223
- const current = Atomics.load(this._state, WRITE_INDEX)
224
- return this._data.length - this.buf.length - current > 0
186
+ this[kImpl] = {}
187
+ this[kImpl].stateBuf = new SharedArrayBuffer(128)
188
+ this[kImpl].state = new Int32Array(this[kImpl].stateBuf)
189
+ this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024)
190
+ this[kImpl].data = Buffer.from(this[kImpl].dataBuf)
191
+ this[kImpl].sync = opts.sync || false
192
+ this[kImpl].ending = false
193
+ this[kImpl].ended = false
194
+ this[kImpl].needDrain = false
195
+ this[kImpl].destroyed = false
196
+ this[kImpl].flushing = false
197
+ this[kImpl].ready = false
198
+ this[kImpl].finished = false
199
+ this[kImpl].errored = null
200
+ this[kImpl].closed = false
201
+ this[kImpl].buf = ''
202
+
203
+ // TODO (fix): Make private?
204
+ this.worker = createWorker(this, opts) // TODO (fix): make private
225
205
  }
226
206
 
227
207
  write (data) {
228
- if (this.closed) {
208
+ if (this[kImpl].destroyed) {
229
209
  throw new Error('the worker has exited')
230
210
  }
231
211
 
232
- if (this.flushing && this.buf.length + data.length >= MAX_STRING) {
233
- // process._rawDebug('write: flushing')
234
- this._writeSync()
235
- this.flushing = true // we are still flushing
212
+ if (this[kImpl].ending) {
213
+ throw new Error('the worker is ending')
236
214
  }
237
215
 
238
- if (!this.ready || this.flushing) {
239
- this.buf += data
240
- return this._hasSpace()
216
+ if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) {
217
+ try {
218
+ writeSync(this)
219
+ this[kImpl].flushing = true
220
+ } catch (err) {
221
+ destroy(this, err)
222
+ return false
223
+ }
241
224
  }
242
225
 
243
- if (this._sync) {
244
- this.buf += data
245
- this._writeSync()
226
+ this[kImpl].buf += data
246
227
 
247
- return true
228
+ if (this[kImpl].sync) {
229
+ try {
230
+ writeSync(this)
231
+ return true
232
+ } catch (err) {
233
+ destroy(this, err)
234
+ return false
235
+ }
248
236
  }
249
237
 
250
- this.buf = data
251
- this.flushing = true
252
- setImmediate(nextFlush, this)
238
+ if (!this[kImpl].flushing) {
239
+ this[kImpl].flushing = true
240
+ setImmediate(nextFlush, this)
241
+ }
253
242
 
254
- return this._hasSpace()
243
+ this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0
244
+ return !this[kImpl].needDrain
255
245
  }
256
246
 
257
247
  end () {
258
- if (this.closed) {
248
+ if (this[kImpl].destroyed) {
259
249
  throw new Error('the worker has exited')
260
250
  }
261
251
 
262
- if (!this.ready) {
263
- this.once('ready', this.end.bind(this))
264
- return
265
- }
266
-
267
- if (this.flushing) {
268
- this.once('drain', this.end.bind(this))
269
- return
270
- }
271
-
272
- if (this.ending) {
273
- return
274
- }
275
- this.ending = true
276
-
277
- this.flushSync()
278
-
279
- let read = Atomics.load(this._state, READ_INDEX)
280
-
281
- // process._rawDebug('writing index')
282
- Atomics.store(this._state, WRITE_INDEX, -1)
283
- // process._rawDebug(`(end) readIndex (${Atomics.load(this._state, READ_INDEX)}) writeIndex (${Atomics.load(this._state, WRITE_INDEX)})`)
284
- Atomics.notify(this._state, WRITE_INDEX)
285
-
286
- // Wait for the process to complete
287
- let spins = 0
288
- while (read !== -1) {
289
- // process._rawDebug(`read = ${read}`)
290
- Atomics.wait(this._state, READ_INDEX, read, 1000)
291
- read = Atomics.load(this._state, READ_INDEX)
292
-
293
- if (++spins === 10) {
294
- throw new Error('end() took too long (10s)')
295
- }
296
- }
297
-
298
- process.nextTick(() => {
299
- this.emit('finish')
300
- })
301
- // process._rawDebug('end finished...')
252
+ this[kImpl].ending = true
253
+ end(this)
302
254
  }
303
255
 
304
256
  flush (cb) {
305
- if (this.closed) {
257
+ if (this[kImpl].destroyed) {
306
258
  throw new Error('the worker has exited')
307
259
  }
308
260
 
309
261
  // TODO write all .buf
310
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
311
- // process._rawDebug(`(flush) readIndex (${Atomics.load(this._state, READ_INDEX)}) writeIndex (${Atomics.load(this._state, WRITE_INDEX)})`)
312
- wait(this._state, READ_INDEX, writeIndex, Infinity, (err, res) => {
262
+ const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX)
263
+ // process._rawDebug(`(flush) readIndex (${Atomics.load(this.state, READ_INDEX)}) writeIndex (${Atomics.load(this.state, WRITE_INDEX)})`)
264
+ wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => {
313
265
  if (err) {
314
- this.emit('error', err)
315
- cb(err)
266
+ destroy(this, err)
267
+ process.nextTick(cb, err)
316
268
  return
317
269
  }
318
270
  if (res === 'not-equal') {
@@ -320,108 +272,224 @@ class ThreadStream extends EventEmitter {
320
272
  this.flush(cb)
321
273
  return
322
274
  }
323
- cb()
275
+ process.nextTick(cb)
324
276
  })
325
277
  }
326
278
 
327
- _writeSync () {
328
- const cb = () => {
329
- if (!this.needDrain) {
330
- // process._rawDebug('emitting drain')
331
- this.needDrain = true
332
- process.nextTick(drain, this)
333
- }
279
+ flushSync () {
280
+ if (this[kImpl].destroyed) {
281
+ throw new Error('the worker has exited')
334
282
  }
335
- this.flushing = false
336
-
337
- while (this.buf.length !== 0) {
338
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
339
- let leftover = this._data.length - writeIndex
340
- if (leftover === 0) {
341
- this._flushSync()
342
- Atomics.store(this._state, READ_INDEX, 0)
343
- Atomics.store(this._state, WRITE_INDEX, 0)
344
- continue
345
- } else if (leftover < 0) {
346
- // This should never happen
347
- throw new Error('overwritten')
348
- }
349
283
 
350
- let toWrite = this.buf.slice(0, leftover)
351
- let toWriteBytes = Buffer.byteLength(toWrite)
352
- if (toWriteBytes <= leftover) {
353
- this.buf = this.buf.slice(leftover)
354
- // process._rawDebug('writing ' + toWrite.length)
355
- this._write(toWrite, cb)
356
- } else {
357
- // multi-byte utf-8
358
- this._flushSync()
359
- Atomics.store(this._state, READ_INDEX, 0)
360
- Atomics.store(this._state, WRITE_INDEX, 0)
284
+ writeSync(this)
285
+ flushSync(this)
286
+ }
361
287
 
362
- // Find a toWrite length that fits the buffer
363
- // it must exists as the buffer is at least 4 bytes length
364
- // and the max utf-8 length for a char is 4 bytes.
365
- while (toWriteBytes > this.buf.length) {
366
- leftover = leftover / 2
367
- toWrite = this.buf.slice(0, leftover)
368
- toWriteBytes = Buffer.byteLength(toWrite)
369
- }
370
- this.buf = this.buf.slice(leftover)
371
- this._write(toWrite, cb)
372
- }
373
- }
288
+ unref () {
289
+ this.worker.unref()
374
290
  }
375
291
 
376
- flushSync () {
377
- if (this.closed) {
378
- throw new Error('the worker has exited')
379
- }
292
+ ref () {
293
+ this.worker.ref()
294
+ }
380
295
 
381
- this._writeSync()
382
- this._flushSync()
296
+ get ready () {
297
+ return this[kImpl].ready
383
298
  }
384
299
 
385
- _flushSync () {
386
- if (this.flushing) {
387
- throw new Error('unable to flush while flushing')
388
- }
300
+ get destroyed () {
301
+ return this[kImpl].destroyed
302
+ }
389
303
 
390
- // process._rawDebug('flushSync started')
304
+ get closed () {
305
+ return this[kImpl].closed
306
+ }
391
307
 
392
- const writeIndex = Atomics.load(this._state, WRITE_INDEX)
308
+ get writable () {
309
+ return !this[kImpl].destroyed && !this[kImpl].ending
310
+ }
311
+
312
+ get writableEnded () {
313
+ return this[kImpl].ending
314
+ }
315
+
316
+ get writableFinished () {
317
+ return this[kImpl].finished
318
+ }
319
+
320
+ get writableNeedDrain () {
321
+ return this[kImpl].needDrain
322
+ }
323
+
324
+ get writableObjectMode () {
325
+ return false
326
+ }
327
+
328
+ get writableErrored () {
329
+ return this[kImpl].errored
330
+ }
331
+ }
332
+
333
+ function destroy (stream, err) {
334
+ if (stream[kImpl].destroyed) {
335
+ return
336
+ }
337
+ stream[kImpl].destroyed = true
338
+
339
+ if (err) {
340
+ stream[kImpl].errored = err
341
+ stream.emit('error', err)
342
+ }
393
343
 
344
+ if (!stream.worker.exited) {
345
+ stream.worker.terminate()
346
+ .catch(() => {})
347
+ .then(() => {
348
+ stream[kImpl].closed = true
349
+ stream.emit('close')
350
+ })
351
+ } else {
352
+ setImmediate(() => {
353
+ stream[kImpl].closed = true
354
+ stream.emit('close')
355
+ })
356
+ }
357
+ }
358
+
359
+ function write (stream, data, cb) {
360
+ // data is smaller than the shared buffer length
361
+ const current = Atomics.load(stream[kImpl].state, WRITE_INDEX)
362
+ const length = Buffer.byteLength(data)
363
+ stream[kImpl].data.write(data, current)
364
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length)
365
+ Atomics.notify(stream[kImpl].state, WRITE_INDEX)
366
+ cb()
367
+ return true
368
+ }
369
+
370
+ function end (stream) {
371
+ if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) {
372
+ return
373
+ }
374
+ stream[kImpl].ended = true
375
+
376
+ try {
377
+ stream.flushSync()
378
+
379
+ let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
380
+
381
+ // process._rawDebug('writing index')
382
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, -1)
383
+ // process._rawDebug(`(end) readIndex (${Atomics.load(stream.state, READ_INDEX)}) writeIndex (${Atomics.load(stream.state, WRITE_INDEX)})`)
384
+ Atomics.notify(stream[kImpl].state, WRITE_INDEX)
385
+
386
+ // Wait for the process to complete
394
387
  let spins = 0
388
+ while (readIndex !== -1) {
389
+ // process._rawDebug(`read = ${read}`)
390
+ Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1000)
391
+ readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
395
392
 
396
- // TODO handle deadlock
397
- while (true) {
398
- const readIndex = Atomics.load(this._state, READ_INDEX)
399
- // process._rawDebug(`(flushSync) readIndex (${readIndex}) writeIndex (${writeIndex})`)
400
- if (readIndex !== writeIndex) {
401
- // TODO this timeouts for some reason.
402
- Atomics.wait(this._state, READ_INDEX, readIndex, 1000)
403
- } else {
404
- break
393
+ if (readIndex === -2) {
394
+ throw new Error('end() failed')
405
395
  }
406
396
 
407
397
  if (++spins === 10) {
408
- throw new Error('_flushSync took too long (10s)')
398
+ throw new Error('end() took too long (10s)')
409
399
  }
410
400
  }
411
- // process._rawDebug('flushSync finished')
401
+
402
+ process.nextTick(() => {
403
+ stream[kImpl].finished = true
404
+ stream.emit('finish')
405
+ })
406
+ } catch (err) {
407
+ destroy(stream, err)
412
408
  }
409
+ // process._rawDebug('end finished...')
410
+ }
413
411
 
414
- unref () {
415
- this.worker.unref()
412
+ function writeSync (stream) {
413
+ const cb = () => {
414
+ if (stream[kImpl].ending) {
415
+ end(stream)
416
+ } else if (stream[kImpl].needDrain) {
417
+ process.nextTick(drain, stream)
418
+ }
416
419
  }
420
+ stream[kImpl].flushing = false
421
+
422
+ while (stream[kImpl].buf.length !== 0) {
423
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
424
+ let leftover = stream[kImpl].data.length - writeIndex
425
+ if (leftover === 0) {
426
+ flushSync(stream)
427
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
428
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
429
+ continue
430
+ } else if (leftover < 0) {
431
+ // stream should never happen
432
+ throw new Error('overwritten')
433
+ }
417
434
 
418
- ref () {
419
- this.worker.ref()
435
+ let toWrite = stream[kImpl].buf.slice(0, leftover)
436
+ let toWriteBytes = Buffer.byteLength(toWrite)
437
+ if (toWriteBytes <= leftover) {
438
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
439
+ // process._rawDebug('writing ' + toWrite.length)
440
+ write(stream, toWrite, cb)
441
+ } else {
442
+ // multi-byte utf-8
443
+ flushSync(stream)
444
+ Atomics.store(stream[kImpl].state, READ_INDEX, 0)
445
+ Atomics.store(stream[kImpl].state, WRITE_INDEX, 0)
446
+
447
+ // Find a toWrite length that fits the buffer
448
+ // it must exists as the buffer is at least 4 bytes length
449
+ // and the max utf-8 length for a char is 4 bytes.
450
+ while (toWriteBytes > stream[kImpl].buf.length) {
451
+ leftover = leftover / 2
452
+ toWrite = stream[kImpl].buf.slice(0, leftover)
453
+ toWriteBytes = Buffer.byteLength(toWrite)
454
+ }
455
+ stream[kImpl].buf = stream[kImpl].buf.slice(leftover)
456
+ write(stream, toWrite, cb)
457
+ }
420
458
  }
459
+ }
421
460
 
422
- get writable () {
423
- return !this.closed
461
+ function flushSync (stream) {
462
+ if (stream[kImpl].flushing) {
463
+ throw new Error('unable to flush while flushing')
464
+ }
465
+
466
+ // process._rawDebug('flushSync started')
467
+
468
+ const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX)
469
+
470
+ let spins = 0
471
+
472
+ // TODO handle deadlock
473
+ while (true) {
474
+ const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX)
475
+
476
+ if (readIndex === -2) {
477
+ throw new Error('_flushSync failed')
478
+ }
479
+
480
+ // process._rawDebug(`(flushSync) readIndex (${readIndex}) writeIndex (${writeIndex})`)
481
+ if (readIndex !== writeIndex) {
482
+ // TODO stream timeouts for some reason.
483
+ Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1000)
484
+ } else {
485
+ break
486
+ }
487
+
488
+ if (++spins === 10) {
489
+ throw new Error('_flushSync took too long (10s)')
490
+ }
424
491
  }
492
+ // process._rawDebug('flushSync finished')
425
493
  }
426
494
 
427
495
  module.exports = ThreadStream
package/lib/worker.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { realImport, realRequire } = require('real-require')
3
4
  const { workerData, parentPort } = require('worker_threads')
4
5
  const { WRITE_INDEX, READ_INDEX } = require('./indexes')
5
6
  const { waitDiff } = require('./wait')
@@ -17,7 +18,7 @@ const data = Buffer.from(dataBuf)
17
18
  async function start () {
18
19
  let fn
19
20
  try {
20
- fn = (await import(workerData.filename)).default
21
+ fn = (await realImport(workerData.filename)).default
21
22
  } catch (error) {
22
23
  // A yarn user that tries to start a ThreadStream for an external module
23
24
  // provides a filename pointing to a zip file.
@@ -29,7 +30,7 @@ async function start () {
29
30
  // The error codes may change based on the node.js version (ENOTDIR > 12, ERR_MODULE_NOT_FOUND <= 12 )
30
31
  if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND') &&
31
32
  workerData.filename.startsWith('file://')) {
32
- fn = require(workerData.filename.replace('file://', ''))
33
+ fn = realRequire(decodeURIComponent(workerData.filename.replace('file://', '')))
33
34
  } else {
34
35
  throw error
35
36
  }
@@ -37,6 +38,12 @@ async function start () {
37
38
  destination = await fn(workerData.workerData)
38
39
 
39
40
  destination.on('error', function (err) {
41
+ Atomics.store(state, WRITE_INDEX, -2)
42
+ Atomics.notify(state, WRITE_INDEX)
43
+
44
+ Atomics.store(state, READ_INDEX, -2)
45
+ Atomics.notify(state, READ_INDEX)
46
+
40
47
  parentPort.postMessage({
41
48
  code: 'ERROR',
42
49
  err
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "thread-stream",
3
- "version": "0.11.2",
3
+ "version": "0.13.1",
4
4
  "description": "A streaming way to send data to a Node.js Worker Thread",
5
5
  "main": "index.js",
6
+ "dependencies": {
7
+ "real-require": "^0.1.0"
8
+ },
6
9
  "devDependencies": {
7
10
  "desm": "^1.1.0",
8
11
  "fastbench": "^1.0.1",