Fix swarm bootstrap for logo-less nodes

This commit is contained in:
cyph3rasi
2026-03-07 20:54:30 -08:00
parent 2acebc15a5
commit 853c564755
3 changed files with 32 additions and 2 deletions
+10 -1
View File
@@ -13,11 +13,20 @@ import { buildAnnouncement } from '@/lib/swarm/discovery';
import { verifySwarmRequest } from '@/lib/swarm/signature'; import { verifySwarmRequest } from '@/lib/swarm/signature';
import type { SwarmNodeInfo } from '@/lib/swarm/types'; import type { SwarmNodeInfo } from '@/lib/swarm/types';
const optionalUrlSchema = z.preprocess((value) => {
if (typeof value !== 'string') {
return value;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : undefined;
}, z.string().url().optional());
const announcementSchema = z.object({ const announcementSchema = z.object({
domain: z.string().min(1), domain: z.string().min(1),
name: z.string().optional(), name: z.string().optional(),
description: z.string().optional(), description: z.string().optional(),
logoUrl: z.string().url().optional(), logoUrl: optionalUrlSchema,
publicKey: z.string().optional(), publicKey: z.string().optional(),
softwareVersion: z.string().optional(), softwareVersion: z.string().optional(),
userCount: z.number().optional(), userCount: z.number().optional(),
+12
View File
@@ -64,9 +64,21 @@ async function runBotTasks() {
async function runSwarmGossip() { async function runSwarmGossip() {
try { try {
const stats = await getSwarmStats();
// Recover from empty peer lists by periodically re-announcing to seeds.
if (stats.activeNodes === 0) {
const announceResult = await announceToSeeds();
if (announceResult.successful.length > 0 || announceResult.failed.length > 0) {
log('SWARM', `Re-announced to seeds: ${announceResult.successful.length} successful, ${announceResult.failed.length} failed`);
}
}
const result = await runGossipRound(); const result = await runGossipRound();
if (result.contacted > 0) { if (result.contacted > 0) {
log('SWARM', `Gossip: contacted ${result.contacted}, successful ${result.successful}, received ${result.totalNodesReceived} nodes`); log('SWARM', `Gossip: contacted ${result.contacted}, successful ${result.successful}, received ${result.totalNodesReceived} nodes`);
} else if (stats.activeNodes === 0) {
log('SWARM', 'No active swarm peers yet');
} }
} catch (error) { } catch (error) {
log('SWARM', `Gossip error: ${error}`); log('SWARM', `Gossip error: ${error}`);
+10 -1
View File
@@ -9,6 +9,15 @@ import { eq, sql } from 'drizzle-orm';
import type { SwarmAnnouncement, SwarmNodeInfo, SwarmCapability } from './types'; import type { SwarmAnnouncement, SwarmNodeInfo, SwarmCapability } from './types';
import { upsertSwarmNode, getSeedNodes, markNodeSuccess, markNodeFailure } from './registry'; import { upsertSwarmNode, getSeedNodes, markNodeSuccess, markNodeFailure } from './registry';
function normalizeOptionalUrl(value: string | null | undefined): string | undefined {
if (!value) {
return undefined;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : undefined;
}
/** /**
* Build this node's announcement payload * Build this node's announcement payload
*/ */
@@ -32,7 +41,7 @@ export async function buildAnnouncement(): Promise<SwarmAnnouncement> {
if (node) { if (node) {
name = node.name; name = node.name;
description = node.description ?? undefined; description = node.description ?? undefined;
logoUrl = node.logoUrl ?? undefined; logoUrl = normalizeOptionalUrl(node.logoUrl);
publicKey = node.publicKey ?? ''; publicKey = node.publicKey ?? '';
isNsfw = node.isNsfw; isNsfw = node.isNsfw;
} }