Send version and try to be reverse compatible

This commit is contained in:
Owen 2025-06-19 16:39:44 -04:00
parent acf25e8ad7
commit bd7e96b8af
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
3 changed files with 96 additions and 1 deletions

View file

@ -138,6 +138,7 @@ export const newts = pgTable("newt", {
newtId: varchar("id").primaryKey(),
secretHash: varchar("secretHash").notNull(),
dateCreated: varchar("dateCreated").notNull(),
version: varchar("version"),
siteId: integer("siteId").references(() => sites.siteId, {
onDelete: "cascade"
})

View file

@ -148,6 +148,7 @@ export const newts = sqliteTable("newt", {
newtId: text("id").primaryKey(),
secretHash: text("secretHash").notNull(),
dateCreated: text("dateCreated").notNull(),
version: text("version"),
siteId: integer("siteId").references(() => sites.siteId, {
onDelete: "cascade"
})

View file

@ -10,6 +10,16 @@ import {
getNextAvailableClientSubnet
} from "@server/lib/ip";
export type ExitNodePingResult = {
exitNodeId: number;
latencyMs: number;
weight: number;
error?: string;
exitNodeName: string;
endpoint: string;
wasPreviouslyConnected: boolean;
};
export const handleNewtRegisterMessage: MessageHandler = async (context) => {
const { message, client, sendToClient } = context;
const newt = client as Newt;
@ -28,12 +38,27 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
const siteId = newt.siteId;
const { publicKey, exitNodeId } = message.data;
const { publicKey, pingResults, backwardsCompatible } = message.data;
if (!publicKey) {
logger.warn("Public key not provided");
return;
}
if (backwardsCompatible) {
logger.debug("Backwards compatible mode detecting - not sending connect message and waiting for ping response.");
return;
}
let exitNodeId: number | undefined;
if (pingResults) {
const bestPingResult = selectBestExitNode(pingResults as ExitNodePingResult[]);
if (!bestPingResult) {
logger.warn("No suitable exit node found based on ping results");
return;
}
exitNodeId = bestPingResult.exitNodeId;
}
const [oldSite] = await db
.select()
.from(sites)
@ -222,3 +247,71 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => {
excludeSender: false // Include sender in broadcast
};
};
function selectBestExitNode(pingResults: ExitNodePingResult[]): ExitNodePingResult | null {
// Configuration constants - can be tweaked as needed
const LATENCY_PENALTY_EXPONENT = 1.5; // make latency matter more
const LAST_NODE_SCORE_BOOST = 1.10; // 10% preference for the last used node
const SCORE_TOLERANCE_PERCENT = 5.0; // allow last node if within 5% of best score
let bestNode = null;
let bestScore = -1e12;
let bestLatency = 1e12;
const candidateNodes = [];
// Calculate scores for each valid node
for (const result of pingResults) {
// Skip nodes with errors or invalid weight
if (result.error || result.weight <= 0) {
continue;
}
const latencyMs = result.latencyMs;
let score = result.weight / Math.pow(latencyMs, LATENCY_PENALTY_EXPONENT);
// Apply boost if this was the previously connected node
if (result.wasPreviouslyConnected === true) {
score *= LAST_NODE_SCORE_BOOST;
}
logger.info(`Exit node ${result.exitNodeName} with score: ${score.toFixed(2)} (latency: ${latencyMs}ms, weight: ${result.weight.toFixed(2)})`);
candidateNodes.push({
node: result,
score: score,
latency: latencyMs
});
// Track the best scoring node
if (score > bestScore) {
bestScore = score;
bestLatency = latencyMs;
bestNode = result;
} else if (score === bestScore && latencyMs < bestLatency) {
bestLatency = latencyMs;
bestNode = result;
}
}
// Check if the previously connected node is close enough in score to stick with it
for (const candidate of candidateNodes) {
if (candidate.node.wasPreviouslyConnected) {
const scoreDifference = bestScore - candidate.score;
const tolerance = bestScore * (SCORE_TOLERANCE_PERCENT / 100.0);
if (scoreDifference <= tolerance) {
logger.info(`Sticking with last used exit node: ${candidate.node.exitNodeName} (${candidate.node.endpoint}), score close enough to best`);
bestNode = candidate.node;
}
break;
}
}
if (bestNode === null) {
logger.error("No suitable exit node found");
return null;
}
logger.info(`Selected exit node: ${bestNode.exitNodeName} (${bestNode.endpoint})`);
return bestNode;
}