This commit is contained in:
Raven Scott
2026-05-27 20:19:51 -04:00
parent b000e34016
commit f60de776a0
+61 -19
View File
@@ -337,6 +337,7 @@ async function main() {
let processingInvite = false; let processingInvite = false;
let currentInvitePromise = null; let currentInvitePromise = null;
let currentPairOperation = null; // Track active pairing operation for cleanup let currentPairOperation = null; // Track active pairing operation for cleanup
let cachedMasterInviteWire = null;
// Helper function to safely get dnsPass and ensure state consistency // Helper function to safely get dnsPass and ensure state consistency
function getDnsPass() { function getDnsPass() {
@@ -382,6 +383,26 @@ async function main() {
} }
} }
async function prepareMasterInvite(reason = 'startup') {
if (!isMaster) return null;
const pass = getDnsPass();
if (!pass) return null;
if (cachedMasterInviteWire) return cachedMasterInviteWire;
const { createInvite, inviteToWire, invitePreview } = require('./includes/core/dns-pass-queue');
logInfo('Swarm', `Preparing cached Autopass invite (${reason})...`);
const inv = await createInvite(pass);
cachedMasterInviteWire = inviteToWire(inv);
logInfo('Swarm', `Cached Autopass invite ready (${invitePreview(inv)})`);
return cachedMasterInviteWire;
}
function clearCachedMasterInvite(reason = 'unknown') {
if (!cachedMasterInviteWire) return;
cachedMasterInviteWire = null;
logDebug('Swarm', `Cleared cached Autopass invite (${reason})`);
}
// Helper functions for invite processing mutex // Helper functions for invite processing mutex
function isProcessingInvite() { function isProcessingInvite() {
return processingInvite; return processingInvite;
@@ -453,10 +474,10 @@ async function main() {
logInfo('Swarm', `Processing pending invite request from ${peerId} (queued for ${Math.round(age/1000)}s)`); logInfo('Swarm', `Processing pending invite request from ${peerId} (queued for ${Math.round(age/1000)}s)`);
try { try {
const { createInvite, inviteToWire, invitePreview } = require('./includes/core/dns-pass-queue'); const invWire = await prepareMasterInvite(`pending request from ${peerId.substring(0, 16)}...`);
const inv = await createInvite(state.dnsPass); if (!invWire) {
const invWire = inviteToWire(inv); throw new Error('cached master invite unavailable');
logInfo('Swarm', `Created invite for pending request from ${peerId}: ${invitePreview(inv)}`); }
const sent = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire); const sent = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire);
if (sent) { if (sent) {
logInfo('Swarm', `Successfully sent pending invite to ${peerId}`); logInfo('Swarm', `Successfully sent pending invite to ${peerId}`);
@@ -780,6 +801,14 @@ async function main() {
// Handle invite acknowledgment from joiner // Handle invite acknowledgment from joiner
if (message === 'invite_ack') { if (message === 'invite_ack') {
logInfo('Swarm', `Received invite_ack from peer ${peerId}`); logInfo('Swarm', `Received invite_ack from peer ${peerId}`);
clearCachedMasterInvite(`ack from ${peerId.substring(0, 16)}...`);
if (isMaster) {
setTimeout(() => {
prepareMasterInvite('post-ack refresh').catch((err) => {
logWarn('Swarm', `Could not refresh cached invite after ack: ${err.message}`);
});
}, 3000);
}
// Clear pending ack timeout for this peer // Clear pending ack timeout for this peer
const pending = pendingInviteAcks.get(peerId); const pending = pendingInviteAcks.get(peerId);
if (pending) { if (pending) {
@@ -871,8 +900,7 @@ async function main() {
channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, 'invite_unavailable:creation_failed'); channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, 'invite_unavailable:creation_failed');
return; return;
} }
logInfo('Swarm', `Creating Autopass invite for peer ${peerId}...`); logInfo('Swarm', `Sending cached Autopass invite to peer ${peerId}...`);
const { createInvite, inviteToWire, invitePreview } = require('./includes/core/dns-pass-queue');
const inviteChannelInfo = channelManager.getChannelInfo(CORE_DOMAIN, 'invite'); const inviteChannelInfo = channelManager.getChannelInfo(CORE_DOMAIN, 'invite');
const invitePeerChannel = inviteChannelInfo?.peerChannels?.get(peerId); const invitePeerChannel = inviteChannelInfo?.peerChannels?.get(peerId);
if (invitePeerChannel) { if (invitePeerChannel) {
@@ -881,9 +909,11 @@ async function main() {
logWarn('Swarm', `Invite channel not fully open for ${peerId}, sending invite anyway (protomux may queue)`); logWarn('Swarm', `Invite channel not fully open for ${peerId}, sending invite anyway (protomux may queue)`);
} }
} }
const inv = await createInvite(pass); const invWire = await prepareMasterInvite(`request from ${peerId.substring(0, 16)}...`);
const invWire = inviteToWire(inv); if (!invWire) {
logInfo('Swarm', `Created invite for requesting peer ${peerId}: ${invitePreview(inv)}`); throw new Error('cached master invite unavailable');
}
logInfo('Swarm', `Cached invite ready for requesting peer ${peerId}`);
try { try {
const sent = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire); const sent = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire);
if (!sent) { if (!sent) {
@@ -921,14 +951,15 @@ async function main() {
setTimeout(async () => { setTimeout(async () => {
const retryPass = getDnsPass(); const retryPass = getDnsPass();
const { isDnsPassUsable } = require('./includes/core/core'); const { isDnsPassUsable } = require('./includes/core/core');
const { createInvite, inviteToWire, whenDnsPassIdle, ensureDnsPassOpen } = require('./includes/core/dns-pass-queue'); const { whenDnsPassIdle, ensureDnsPassOpen } = require('./includes/core/dns-pass-queue');
if (!connectedPeers.has(peerId) || !retryPass) return; if (!connectedPeers.has(peerId) || !retryPass) return;
await whenDnsPassIdle(); await whenDnsPassIdle();
await ensureDnsPassOpen(retryPass); await ensureDnsPassOpen(retryPass);
if (!isDnsPassUsable(retryPass)) return; if (!isDnsPassUsable(retryPass)) return;
try { try {
const inv = await createInvite(retryPass); const invWire = await prepareMasterInvite(`retry for ${peerId.substring(0, 16)}...`);
channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, inviteToWire(inv)); if (!invWire) return;
channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire);
logInfo('Swarm', `Sent invite to ${peerId} after dnsPass busy retry`); logInfo('Swarm', `Sent invite to ${peerId} after dnsPass busy retry`);
} catch (retryErr) { } catch (retryErr) {
logWarn('Swarm', `Invite retry failed for ${peerId}: ${retryErr.message}`); logWarn('Swarm', `Invite retry failed for ${peerId}: ${retryErr.message}`);
@@ -964,10 +995,14 @@ async function main() {
if (pass && isDnsPassUsable(pass) && (isMaster || process.env.ALLOW_ANY_WRITER_INVITES === 'true')) { if (pass && isDnsPassUsable(pass) && (isMaster || process.env.ALLOW_ANY_WRITER_INVITES === 'true')) {
// We can create an invite - send it back through the relay chain // We can create an invite - send it back through the relay chain
try { try {
const { createInvite, inviteToWire, whenDnsPassIdle } = require('./includes/core/dns-pass-queue'); const { whenDnsPassIdle } = require('./includes/core/dns-pass-queue');
await whenDnsPassIdle(); await whenDnsPassIdle();
const inv = await createInvite(pass); const invWire = isMaster
const invWire = inviteToWire(inv); ? await prepareMasterInvite(`relay for ${originPeerId.substring(0, 16)}...`)
: null;
if (!invWire) {
throw new Error('cached relay invite unavailable');
}
logInfo('Swarm', `Created relay invite for origin ${originPeerId.substring(0, 16)}...`); logInfo('Swarm', `Created relay invite for origin ${originPeerId.substring(0, 16)}...`);
channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, `relay_invite_response:${originPeerId}:${invWire}`); channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, `relay_invite_response:${originPeerId}:${invWire}`);
} catch (err) { } catch (err) {
@@ -1310,10 +1345,11 @@ async function main() {
pendingInviteAcks.delete(peerId); pendingInviteAcks.delete(peerId);
return; return;
} }
const { createInvite, inviteToWire, invitePreview } = require('./includes/core/dns-pass-queue'); const invWire = await prepareMasterInvite(`proactive send to ${peerId.substring(0, 16)}...`);
const inv = await createInvite(pass); if (!invWire) {
const invWire = inviteToWire(inv); throw new Error('cached master invite unavailable');
logInfo('Swarm', `Created proactive invite for peer ${peerId} (attempt ${retryCount}/${maxRetries}): ${invitePreview(inv)}`); }
logInfo('Swarm', `Using cached proactive invite for peer ${peerId} (attempt ${retryCount}/${maxRetries})`);
const success = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire); const success = channelManager.sendToPeer(CORE_DOMAIN, 'invite', peerId, invWire);
if (success) { if (success) {
@@ -1756,6 +1792,12 @@ async function main() {
} }
logInfo('Main', `Core retrieved. Writable: ${core.writable}, Key: ${core.key.toString('hex')}`); logInfo('Main', `Core retrieved. Writable: ${core.writable}, Key: ${core.key.toString('hex')}`);
try {
await prepareMasterInvite('master startup before p2ns swarm join');
} catch (err) {
logError('Main', `Failed to prepare initial Autopass invite before swarm join: ${err.message}`);
logError('Main', 'Restart with --clean --master if this persists; invite requests will fail until an invite can be cached.');
}
// Setup domains watcher for master // Setup domains watcher for master
setupDomainsWatcher(); setupDomainsWatcher();
setupListeners(); setupListeners();