react-native-nitro-net 0.5.1 → 0.5.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/src/net.ts CHANGED
@@ -91,6 +91,10 @@ function initWithConfig(config: NetConfig): void {
91
91
  if (config.debug !== undefined) {
92
92
  setVerbose(config.debug);
93
93
  }
94
+ // Inject dispatcher for async events to avoid thread starvation/deadlocks
95
+ if ((Driver as any).installDispatcher) {
96
+ (Driver as any).installDispatcher();
97
+ }
94
98
  Driver.initWithConfig(config);
95
99
  }
96
100
 
@@ -296,6 +300,7 @@ export class Socket extends Duplex {
296
300
  public autoSelectFamilyAttemptedAddresses: string[] = [];
297
301
  private _autoSelectFamily: boolean = false;
298
302
  private _timeout: number = 0;
303
+ private _nativeWriteCallbacks: Array<(error?: Error | null) => void> = [];
299
304
 
300
305
  get localFamily(): string {
301
306
  return this.localAddress && this.localAddress.includes(':') ? 'IPv6' : 'IPv4';
@@ -333,9 +338,8 @@ export class Socket extends Duplex {
333
338
  this._setupEvents();
334
339
  // Enable noDelay by default
335
340
  this._driver.setNoDelay(true);
336
- // Resume the socket since it starts paused on server-accept
337
- this.resume();
338
- // Emit connect for server-side socket? No, it's already connected.
341
+ // For accepted server sockets, defer resume until after the server
342
+ // emits 'connection' so user handlers can attach first.
339
343
  } else {
340
344
  // New client socket
341
345
  ensureInitialized();
@@ -355,8 +359,8 @@ export class Socket extends Duplex {
355
359
  return this;
356
360
  }
357
361
  const ret = super.on(event, listener);
358
- if (event === 'data' && !this.isPaused() && (this as any).readableFlowing !== true) {
359
- debugLog(`Socket on('data'), flowing: ${(this as any).readableFlowing}`);
362
+ if (event === 'data' && (this as any).readableFlowing !== true) {
363
+ debugLog(`Socket on('data'), flowing: ${(this as any).readableFlowing}, paused: ${this.isPaused()}`);
360
364
  this.resume();
361
365
  }
362
366
  return ret;
@@ -392,8 +396,10 @@ export class Socket extends Duplex {
392
396
  if (data && data.byteLength > 0) {
393
397
  const buffer = Buffer.from(data);
394
398
  this.bytesRead += buffer.length;
395
- if (!this.push(buffer)) {
396
- this.pause();
399
+ this.push(buffer);
400
+ if (this.listenerCount('data') > 0 && (this as any).readableFlowing !== true) {
401
+ debugLog(`Socket onEvent(DATA) restoring flowing mode for attached 'data' listeners`);
402
+ this.resume();
397
403
  }
398
404
  }
399
405
  break;
@@ -422,6 +428,11 @@ export class Socket extends Duplex {
422
428
  this._connected = false;
423
429
  this.connecting = false;
424
430
  this.push(null); // EOF
431
+ if (!(this as any).allowHalfOpen && !this.writableEnded && !this.destroyed) {
432
+ // Match Node's default behavior: half-close the writable side
433
+ // when the peer finishes and allowHalfOpen is false.
434
+ this.end();
435
+ }
425
436
  this.emit('close', this._hadError);
426
437
  break;
427
438
  case NetSocketEvent.DRAIN:
@@ -582,18 +593,20 @@ export class Socket extends Duplex {
582
593
  return this;
583
594
  }
584
595
 
585
- end(cb?: () => void): this;
586
- end(chunk: any, cb?: () => void): this;
587
- end(chunk: any, encoding: string, cb?: () => void): this;
588
596
  end(chunk?: any, encoding?: any, cb?: any): this {
589
- debugLog(`Socket (localPort: ${this.localPort}) .end() called`);
590
597
  if (typeof chunk === 'function') {
591
- super.end(chunk);
592
- } else if (chunk == null) {
593
- super.end(cb);
594
- } else {
595
- super.end(chunk, encoding, cb);
598
+ cb = chunk;
599
+ chunk = null;
600
+ encoding = null;
601
+ } else if (typeof encoding === 'function') {
602
+ cb = encoding;
603
+ encoding = null;
604
+ }
605
+ debugLog(`Socket (localPort: ${this.localPort}) .end() called`);
606
+ if (chunk != null) {
607
+ this.write(chunk, encoding);
596
608
  }
609
+ super.end(cb);
597
610
  return this;
598
611
  }
599
612
 
@@ -601,6 +614,19 @@ export class Socket extends Duplex {
601
614
  if (!this._driver) {
602
615
  return callback(new Error('Socket not connected'));
603
616
  }
617
+ if (!this._connected && this.connecting) {
618
+ const onConnect = () => {
619
+ this.removeListener('error', onError);
620
+ this._write(chunk, encoding, callback);
621
+ };
622
+ const onError = (err: Error) => {
623
+ this.removeListener('connect', onConnect);
624
+ callback(err);
625
+ };
626
+ this.once('connect', onConnect);
627
+ this.once('error', onError);
628
+ return;
629
+ }
604
630
  try {
605
631
  const buffer = (chunk instanceof Buffer) ? chunk : Buffer.from(chunk, encoding as any);
606
632
  this.bytesWritten += buffer.length;
@@ -618,9 +644,24 @@ export class Socket extends Duplex {
618
644
  }
619
645
 
620
646
  _final(callback: (error?: Error | null) => void): void {
621
- if (this._driver) {
622
- this._driver.shutdown();
647
+ if (!this._driver) {
648
+ return callback(null);
649
+ }
650
+ if (!this._connected && this.connecting) {
651
+ const onConnect = () => {
652
+ this.removeListener('error', onError);
653
+ this._final(callback);
654
+ };
655
+ const onError = () => {
656
+ this.removeListener('connect', onConnect);
657
+ callback(null); // Already destroyed/errored
658
+ };
659
+ this.once('connect', onConnect);
660
+ this.once('error', onError);
661
+ return;
623
662
  }
663
+ debugLog(`Socket (localPort: ${this.localPort}) ._final() called, shutting down driver`);
664
+ this._driver.shutdown();
624
665
  callback(null);
625
666
  }
626
667
 
@@ -832,6 +873,9 @@ export class Server extends EventEmitter {
832
873
  this._sockets.delete(socket);
833
874
  });
834
875
  this.emit('connection', socket);
876
+ // Start reading only after 'connection' handlers ran.
877
+ // This prevents dropping data when listeners are attached in the callback.
878
+ socket.resume();
835
879
  }
836
880
  }
837
881
  break;