@@ -258,101 +258,13 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
258258 } ;
259259} ;
260260
261- /**
262- * Selects the most suitable exit node from a list of ping results.
263- *
264- * The selection algorithm follows these steps:
265- *
266- * 1. **Filter Invalid Nodes**: Excludes nodes with errors or zero weight.
267- *
268- * 2. **Sort by Latency**: Sorts valid nodes in ascending order of latency.
269- *
270- * 3. **Preferred Selection**:
271- * - If the lowest-latency node has sufficient capacity (≥10% weight),
272- * check if a previously connected node is also acceptable.
273- * - The previously connected node is preferred if its latency is within
274- * 30ms or 15% of the best node’s latency.
275- *
276- * 4. **Fallback to Next Best**:
277- * - If the lowest-latency node is under capacity, find the next node
278- * with acceptable capacity.
279- *
280- * 5. **Final Fallback**:
281- * - If no nodes meet the capacity threshold, fall back to the node
282- * with the highest weight (i.e., most available capacity).
283- *
284- */
285261function selectBestExitNode (
286262 pingResults : ExitNodePingResult [ ]
287263) : ExitNodePingResult | null {
288- const MIN_CAPACITY_THRESHOLD = 0.1 ;
289- const LATENCY_TOLERANCE_MS = 30 ;
290- const LATENCY_TOLERANCE_PERCENT = 0.15 ;
291-
292- // Filter out invalid nodes
293- const validNodes = pingResults . filter ( ( n ) => ! n . error && n . weight > 0 ) ;
294-
295- if ( validNodes . length === 0 ) {
296- logger . error ( "No valid exit nodes available" ) ;
264+ if ( ! pingResults || pingResults . length === 0 ) {
265+ logger . warn ( "No ping results provided" ) ;
297266 return null ;
298267 }
299268
300- // Sort by latency (ascending)
301- const sortedNodes = validNodes
302- . slice ( )
303- . sort ( ( a , b ) => a . latencyMs - b . latencyMs ) ;
304- const lowestLatencyNode = sortedNodes [ 0 ] ;
305-
306- logger . info (
307- `Lowest latency node: ${ lowestLatencyNode . exitNodeName } (${ lowestLatencyNode . latencyMs } ms, weight=${ lowestLatencyNode . weight . toFixed ( 2 ) } )`
308- ) ;
309-
310- // If lowest latency node has enough capacity, check if previously connected node is acceptable
311- if ( lowestLatencyNode . weight >= MIN_CAPACITY_THRESHOLD ) {
312- const previouslyConnectedNode = sortedNodes . find (
313- ( n ) =>
314- n . wasPreviouslyConnected && n . weight >= MIN_CAPACITY_THRESHOLD
315- ) ;
316-
317- if ( previouslyConnectedNode ) {
318- const latencyDiff =
319- previouslyConnectedNode . latencyMs - lowestLatencyNode . latencyMs ;
320- const percentDiff = latencyDiff / lowestLatencyNode . latencyMs ;
321-
322- if (
323- latencyDiff <= LATENCY_TOLERANCE_MS ||
324- percentDiff <= LATENCY_TOLERANCE_PERCENT
325- ) {
326- logger . info (
327- `Sticking with previously connected node: ${ previouslyConnectedNode . exitNodeName } ` +
328- `(${ previouslyConnectedNode . latencyMs } ms), latency diff = ${ latencyDiff . toFixed ( 1 ) } ms ` +
329- `/ ${ ( percentDiff * 100 ) . toFixed ( 1 ) } %.`
330- ) ;
331- return previouslyConnectedNode ;
332- }
333- }
334-
335- return lowestLatencyNode ;
336- }
337-
338- // Otherwise, find the next node (after the lowest) that has enough capacity
339- for ( let i = 1 ; i < sortedNodes . length ; i ++ ) {
340- const node = sortedNodes [ i ] ;
341- if ( node . weight >= MIN_CAPACITY_THRESHOLD ) {
342- logger . info (
343- `Lowest latency node under capacity. Using next best: ${ node . exitNodeName } ` +
344- `(${ node . latencyMs } ms, weight=${ node . weight . toFixed ( 2 ) } )`
345- ) ;
346- return node ;
347- }
348- }
349-
350- // Fallback: pick the highest weight node
351- const fallbackNode = validNodes . reduce ( ( a , b ) =>
352- a . weight > b . weight ? a : b
353- ) ;
354- logger . warn (
355- `No nodes with ≥10% weight. Falling back to highest capacity node: ${ fallbackNode . exitNodeName } `
356- ) ;
357- return fallbackNode ;
269+ return pingResults [ 0 ] ;
358270}
0 commit comments