@decentnetwork/peer 0.1.94 → 0.1.95

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.
Files changed (2) hide show
  1. package/dist/peer.js +46 -0
  2. package/package.json +1 -1
package/dist/peer.js CHANGED
@@ -358,6 +358,8 @@ export class Peer {
358
358
  // Per-friend tracking sets so we send our nickname/status/greeting once
359
359
  // per session rather than on every PACKET_ID_ONLINE arrival.
360
360
  #profileSentTo = new Set();
361
+ #profileRetryAttempts = new Map();
362
+ #profileRetryTimers = new Map();
361
363
  #greetingSentTo = new Set();
362
364
  #selfAnnouncePromise;
363
365
  #selfAnnouncePauseDepth = 0;
@@ -595,6 +597,10 @@ export class Peer {
595
597
  async stop() {
596
598
  // Stop background producers first so no keepalive/profile packet can race
597
599
  // behind the shutdown notice and make the remote session look live again.
600
+ for (const timer of this.#profileRetryTimers.values())
601
+ clearTimeout(timer);
602
+ this.#profileRetryTimers.clear();
603
+ this.#profileRetryAttempts.clear();
598
604
  if (this.#expressPollTimer) {
599
605
  clearInterval(this.#expressPollTimer);
600
606
  this.#expressPollTimer = undefined;
@@ -981,6 +987,11 @@ export class Peer {
981
987
  this.#tcpOnlyWarningShown.delete(friendId);
982
988
  this.#noEndpointWarned.delete(friendId);
983
989
  this.#profileSentTo.delete(friendId);
990
+ const profileRetry = this.#profileRetryTimers.get(friendId);
991
+ if (profileRetry)
992
+ clearTimeout(profileRetry);
993
+ this.#profileRetryTimers.delete(friendId);
994
+ this.#profileRetryAttempts.delete(friendId);
984
995
  this.#greetingSentTo.delete(friendId);
985
996
  if (existed) {
986
997
  this.#persistFriends();
@@ -3992,6 +4003,10 @@ export class Peer {
3992
4003
  if (info.description !== undefined)
3993
4004
  opts.statusMessage = info.description;
3994
4005
  this.#profileSentTo.clear();
4006
+ for (const timer of this.#profileRetryTimers.values())
4007
+ clearTimeout(timer);
4008
+ this.#profileRetryTimers.clear();
4009
+ this.#profileRetryAttempts.clear();
3995
4010
  for (const [friendId, s] of this.#friendSessions.entries()) {
3996
4011
  if (s.established)
3997
4012
  this.#sendProfileAndGreeting(friendId);
@@ -4005,6 +4020,25 @@ export class Peer {
4005
4020
  description: opts.statusMessage ?? PEER_STATUS_MESSAGE,
4006
4021
  };
4007
4022
  }
4023
+ #scheduleProfileRetry(friendId) {
4024
+ if (this.#profileRetryTimers.has(friendId))
4025
+ return;
4026
+ const session = this.#friendSessions.get(friendId);
4027
+ if (!this.#started || !session?.established)
4028
+ return;
4029
+ const attempt = (this.#profileRetryAttempts.get(friendId) ?? 0) + 1;
4030
+ this.#profileRetryAttempts.set(friendId, attempt);
4031
+ const delayMs = Math.min(30_000, 1_000 * (2 ** Math.min(attempt - 1, 5)));
4032
+ const timer = setTimeout(() => {
4033
+ this.#profileRetryTimers.delete(friendId);
4034
+ if (this.#started && this.#friendSessions.get(friendId)?.established) {
4035
+ this.#sendProfileAndGreeting(friendId);
4036
+ }
4037
+ }, delayMs);
4038
+ timer.unref?.();
4039
+ this.#profileRetryTimers.set(friendId, timer);
4040
+ this.#debugLog(`profile retry ${attempt} for ${friendId} scheduled in ${delayMs}ms`);
4041
+ }
4008
4042
  #sendProfileAndGreeting(friendId) {
4009
4043
  if (!this.#profileSentTo.has(friendId)) {
4010
4044
  this.#profileSentTo.add(friendId);
@@ -4044,9 +4078,16 @@ export class Peer {
4044
4078
  });
4045
4079
  await this.#sendMessengerPacket(friendId, PACKET_ID_STATUSMESSAGE, userInfo);
4046
4080
  this.#debugLog(`userinfo sent to ${friendId} (name="${nick}", descr="${descr}", proto=${AGENTNET_PROTO_VERSION}, platform=${this.#opts.platform ?? process.platform})`);
4081
+ this.#profileRetryAttempts.delete(friendId);
4047
4082
  }
4048
4083
  catch (error) {
4084
+ // PACKET_ID_ONLINE can arrive a fraction before every transport is
4085
+ // ready to accept messenger packets. Do not leave the optimistic
4086
+ // "sent" marker wedged after that race: re-arm it and retry with
4087
+ // bounded backoff while this same session remains established.
4088
+ this.#profileSentTo.delete(friendId);
4049
4089
  this.#debugLog(`send profile failed for ${friendId}: ${error.message}`);
4090
+ this.#scheduleProfileRetry(friendId);
4050
4091
  }
4051
4092
  })();
4052
4093
  }
@@ -5378,6 +5419,11 @@ export class Peer {
5378
5419
  // transitions prevents the user from seeing the same greeting message
5379
5420
  // repeated each time the session bounces.
5380
5421
  this.#profileSentTo.delete(friendId);
5422
+ const profileRetry = this.#profileRetryTimers.get(friendId);
5423
+ if (profileRetry)
5424
+ clearTimeout(profileRetry);
5425
+ this.#profileRetryTimers.delete(friendId);
5426
+ this.#profileRetryAttempts.delete(friendId);
5381
5427
  const friend = this.#friends.get(friendId);
5382
5428
  if (!friend) {
5383
5429
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.94",
3
+ "version": "0.1.95",
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",