@decentnetwork/lan 0.1.133 → 0.1.135

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.
Binary file
Binary file
Binary file
Binary file
@@ -83,6 +83,10 @@ const HEALTH_TIMEOUT_MS = 4000;
83
83
  // of transient jitter on a long-haul path (don't blackout a region on one blip).
84
84
  const DOWN_AFTER_FAILS = 3;
85
85
  const CONNECT_TIMEOUT_MS = 8000;
86
+ // An exit that carried a real tunnel within this window is treated as healthy
87
+ // regardless of what the synthetic probe says (the probe adds load and flaps on
88
+ // a busy/jittery exit; live traffic is the truth).
89
+ const RECENT_SUCCESS_MS = 10_000;
86
90
  /**
87
91
  * Start the multi-exit router. Returns a stop() that closes the listener.
88
92
  * Runs until stopped (the CLI command keeps the process alive).
@@ -108,6 +112,7 @@ export function startMultiExitRouter(opts) {
108
112
  active: 0,
109
113
  served: 0,
110
114
  lastRtt: null,
115
+ lastSuccessMs: null,
111
116
  }));
112
117
  // Per-host routing decision, logged once on first sight so the user can SEE
113
118
  // why a hostname went DIRECT vs through a region (e.g. a CCTV video CDN that
@@ -170,6 +175,13 @@ export function startMultiExitRouter(opts) {
170
175
  }
171
176
  }
172
177
  else {
178
+ // A probe miss does NOT mark an exit down while real tunnels are still
179
+ // succeeding through it — live traffic overrides the synthetic probe.
180
+ const liveTraffic = exit.lastSuccessMs !== null && Date.now() - exit.lastSuccessMs < RECENT_SUCCESS_MS;
181
+ if (liveTraffic) {
182
+ exit.fails = 0;
183
+ continue;
184
+ }
173
185
  exit.fails++;
174
186
  exit.oks = 0;
175
187
  if (exit.healthy && exit.fails >= DOWN_AFTER_FAILS) {
@@ -184,8 +196,12 @@ export function startMultiExitRouter(opts) {
184
196
  }
185
197
  // ---- exit selection (scoped to one region) --------------------------------
186
198
  function pickOrder(region) {
199
+ const now = Date.now();
200
+ // An exit is usable if the probe says healthy OR it carried a real tunnel
201
+ // recently (live traffic beats a flapping probe).
202
+ const isUp = (e) => e.healthy || (e.lastSuccessMs !== null && now - e.lastSuccessMs < RECENT_SUCCESS_MS);
187
203
  const inRegion = exits.filter((e) => e.region === region);
188
- const healthy = inRegion.filter((e) => e.healthy);
204
+ const healthy = inRegion.filter(isUp);
189
205
  // Best-effort fallback: if NO exit currently passes health checks but the
190
206
  // region HAS exits, try them anyway instead of 503-ing the user. A single
191
207
  // high-latency exit under load makes the probe flap DOWN/UP every few
@@ -230,6 +246,16 @@ export function startMultiExitRouter(opts) {
230
246
  established = true;
231
247
  exit.active++;
232
248
  exit.served++;
249
+ // Live traffic proves the exit is up — clear any probe-driven failure
250
+ // and mark it healthy so a flapping probe can't take it DOWN while
251
+ // tunnels are flowing.
252
+ exit.lastSuccessMs = Date.now();
253
+ exit.fails = 0;
254
+ if (!exit.healthy) {
255
+ exit.healthy = true;
256
+ log(`✓ ${exit.name} [${exit.region}] UP (live traffic)`);
257
+ printPool();
258
+ }
233
259
  up.setTimeout(0);
234
260
  client.write("HTTP/1.1 200 Connection Established\r\n\r\n");
235
261
  if (head && head.length)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/lan",
3
- "version": "0.1.133",
3
+ "version": "0.1.135",
4
4
  "description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -79,7 +79,7 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "@decentnetwork/dora": "^0.1.11",
82
- "@decentnetwork/peer": "^0.1.69",
82
+ "@decentnetwork/peer": "^0.1.70",
83
83
  "ink": "^5.2.1",
84
84
  "js-yaml": "^4.1.0",
85
85
  "react": "^18.3.1",