Add exit node selection to the clients

This commit is contained in:
Owen
2026-07-30 11:57:48 -04:00
parent b0e274f5a9
commit 719baa201e
13 changed files with 190 additions and 80 deletions
-14
View File
@@ -339,19 +339,6 @@ export async function calculateUserClientsForOrgs(
continue;
}
// Get exit nodes for this org
const exitNodesList = await getExitNodes(orgId);
if (exitNodesList.length === 0) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no exit nodes found`
);
continue;
}
const randomExitNode =
exitNodesList[Math.floor(Math.random() * exitNodesList.length)];
// Get next available subnet
const { value: newSubnet, release: releaseSubnetLock } =
await getNextAvailableClientSubnet(orgId, trx);
@@ -370,7 +357,6 @@ export async function calculateUserClientsForOrgs(
const newClientData: InferInsertModel<typeof clients> = {
userId,
orgId: userOrg.orgId,
exitNodeId: randomExitNode.exitNodeId,
name: olm.name || "User Client",
subnet: updatedSubnet,
olmId: olm.olmId,
@@ -0,0 +1,40 @@
import { db, sites, clients } from "@server/db";
import { and, eq, count } from "drizzle-orm";
// (MAX_CONNECTIONS - current_connections) / MAX_CONNECTIONS)
// higher = more desirable
// like saying, this node has x% of its capacity left
export async function calculateExitNodeWeight(
exitNodeId: number,
maxConnections: number | null | undefined
): Promise<number | null> {
if (maxConnections === null || maxConnections === undefined) {
return 1;
}
const [[siteConnections], [clientConnections]] = await Promise.all([
db
.select({ count: count() })
.from(sites)
.where(
and(eq(sites.exitNodeId, exitNodeId), eq(sites.online, true))
),
db
.select({ count: count() })
.from(clients)
.where(
and(
eq(clients.exitNodeId, exitNodeId),
eq(clients.online, true)
)
)
]);
const currentConnections = siteConnections.count + clientConnections.count;
if (currentConnections >= maxConnections) {
return null;
}
return (maxConnections - currentConnections) / maxConnections;
}
+10 -1
View File
@@ -1,6 +1,5 @@
import { db, exitNodes, Transaction } from "@server/db";
import logger from "@server/logger";
import { ExitNodePingResult } from "@server/routers/newt";
import { eq } from "drizzle-orm";
export async function verifyExitNodeOrgAccess(
@@ -52,6 +51,16 @@ export async function listExitNodes(
return allExitNodes;
}
export type ExitNodePingResult = {
exitNodeId: number;
latencyMs: number;
weight: number;
error?: string;
exitNodeName: string;
endpoint: string;
wasPreviouslyConnected: boolean;
};
export function selectBestExitNode(
pingResults: ExitNodePingResult[]
): ExitNodePingResult | null {
+1
View File
@@ -2,3 +2,4 @@ export * from "./exitNodes";
export * from "./exitNodeComms";
export * from "./subnet";
export * from "./getCurrentExitNodeId";
export * from "./calculateExitNodeWeight";