@decentnetwork/peer 0.1.77 → 0.1.78

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.
@@ -751,8 +751,7 @@ export class FileTransferManager {
751
751
  // so a dup-ack burst can't storm). No window backoff: loss ≠ congestion.
752
752
  st.lastResendMs = nowMs();
753
753
  st.lastLossMs = nowMs(); // the path is lossy → turn adaptive FEC on
754
- if (st.nextSend > st.acked)
755
- st.nextSend = st.acked;
754
+ this.#rewindRetransmit(st);
756
755
  }
757
756
  if (st.acked >= st.size) {
758
757
  this.#completeSend(friendId, st);
@@ -760,6 +759,21 @@ export class FileTransferManager {
760
759
  }
761
760
  void this.#pump(friendId, st);
762
761
  }
762
+ // Rewind for a go-back-N retransmit: move the send cursor back to the ack point
763
+ // AND rewind the FEC high-water mark so the re-sent blocks get FRESH parity.
764
+ // Without the parity rewind a lossy TAIL freezes forever — re-sending the
765
+ // region drops new chunks faster than it fills the old holes, and the receiver
766
+ // has no parity to recover them locally (parity was emitted once, long gone).
767
+ // Re-emitting parity lets the receiver FEC-recover the holes, so the tail
768
+ // converges instead of stalling at 93% (observed on 100 MB+ files).
769
+ #rewindRetransmit(st) {
770
+ if (st.nextSend > st.acked)
771
+ st.nextSend = st.acked;
772
+ const ackBlock = Math.floor(st.acked / MAX_FILE_DATA_SIZE / FEC_K);
773
+ if (ackBlock - 1 < st.parityHighBlock)
774
+ st.parityHighBlock = ackBlock - 1;
775
+ st.lastLossMs = nowMs(); // keep FEC ON so the re-emit actually fires
776
+ }
763
777
  // Single send loop. Awaits each send so net_crypto / the UDP socket applies
764
778
  // backpressure (fire-and-forget blasted the whole window into the macOS UDP
765
779
  // buffer at once → systematic overflow/drops the retransmit couldn't dig out
@@ -803,8 +817,7 @@ export class FileTransferManager {
803
817
  st.cwnd = Math.max(CWND_MIN_CHUNKS, Math.floor(st.cwnd / 2));
804
818
  st.lastAckAdvanceMs = nowMs();
805
819
  st.lastResendMs = nowMs();
806
- if (st.nextSend > st.acked)
807
- st.nextSend = st.acked; // go-back-N
820
+ this.#rewindRetransmit(st); // go-back-N + re-emit tail parity
808
821
  void this.#pump(friendId, st);
809
822
  }, WATCHDOG_MS);
810
823
  if (typeof st.timer.unref === "function")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.77",
3
+ "version": "0.1.78",
4
4
  "description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",