Skip to content

Commit c225a54

Browse files
committed
Merge branch 'dev'
2 parents e8793c5 + 5148988 commit c225a54

File tree

3 files changed

+18
-107
lines changed

3 files changed

+18
-107
lines changed

install/config/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ orgs:
3030
email:
3131
smtp_host: "{{.EmailSMTPHost}}"
3232
smtp_port: {{.EmailSMTPPort}}
33-
smtp_user: "{{.EmailSMTPUser}allow_base_domain_resources}"
33+
smtp_user: "{{.EmailSMTPUser}}"
3434
smtp_pass: "{{.EmailSMTPPass}}"
3535
no_reply: "{{.EmailNoReply}}"
3636
{{end}}

server/routers/newt/handleNewtRegisterMessage.ts

Lines changed: 3 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
*/
285261
function 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
}

server/routers/traefik/getTraefikConfig.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Request, Response } from "express";
22
import { db, exitNodes } from "@server/db";
3-
import { and, eq, inArray } from "drizzle-orm";
3+
import { and, eq, inArray, or, isNull } from "drizzle-orm";
44
import logger from "@server/logger";
55
import HttpCode from "@server/types/HttpCode";
66
import config from "@server/lib/config";
@@ -27,13 +27,9 @@ export async function traefikConfigProvider(
2727
})
2828
.from(exitNodes)
2929
.where(eq(exitNodes.name, exitNodeName));
30-
if (!exitNode) {
31-
logger.error(
32-
`Exit node with name ${exitNodeName} not found in the database`
33-
);
34-
return [];
30+
if (exitNode) {
31+
currentExitNodeId = exitNode.exitNodeId;
3532
}
36-
currentExitNodeId = exitNode.exitNodeId;
3733
} else {
3834
const [exitNode] = await tx
3935
.select({
@@ -42,12 +38,9 @@ export async function traefikConfigProvider(
4238
.from(exitNodes)
4339
.limit(1);
4440

45-
if (!exitNode) {
46-
logger.error("No exit node found in the database");
47-
return [];
41+
if (exitNode) {
42+
currentExitNodeId = exitNode.exitNodeId;
4843
}
49-
50-
currentExitNodeId = exitNode.exitNodeId;
5144
}
5245
}
5346

@@ -68,7 +61,7 @@ export async function traefikConfigProvider(
6861
siteId: sites.siteId,
6962
type: sites.type,
7063
subnet: sites.subnet,
71-
exitNodeId: sites.exitNodeId,
64+
exitNodeId: sites.exitNodeId
7265
},
7366
enabled: resources.enabled,
7467
stickySession: resources.stickySession,
@@ -77,7 +70,12 @@ export async function traefikConfigProvider(
7770
})
7871
.from(resources)
7972
.innerJoin(sites, eq(sites.siteId, resources.siteId))
80-
.where(eq(sites.exitNodeId, currentExitNodeId));
73+
.where(
74+
or(
75+
eq(sites.exitNodeId, currentExitNodeId),
76+
isNull(sites.exitNodeId)
77+
)
78+
);
8179

8280
// Get all resource IDs from the first query
8381
const resourceIds = resourcesWithRelations.map((r) => r.resourceId);
@@ -284,7 +282,8 @@ export async function traefikConfigProvider(
284282
} else if (site.type === "newt") {
285283
if (
286284
!target.internalPort ||
287-
!target.method || !site.subnet
285+
!target.method ||
286+
!site.subnet
288287
) {
289288
return false;
290289
}

0 commit comments

Comments
 (0)