forked from snxraven/p2ns
Fixes
This commit is contained in:
+3
-1
@@ -103,7 +103,9 @@ TOPIC_SEED=p2ns-dns
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Master Node Configuration
|
# Master Node Configuration
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# These settings only apply when running with --master flag
|
# Master mode: pass --master on the command line OR set P2NS_MASTER=true (for Docker/PM2).
|
||||||
|
# P2NS_MASTER=true
|
||||||
|
# These settings only apply in master mode
|
||||||
# Base interval in seconds for reconnection attempts when peers disconnect (default: 5)
|
# Base interval in seconds for reconnection attempts when peers disconnect (default: 5)
|
||||||
# Master nodes will attempt to reconnect to disconnected peers with exponential backoff
|
# Master nodes will attempt to reconnect to disconnected peers with exponential backoff
|
||||||
MASTER_RECONNECT_INTERVAL=5
|
MASTER_RECONNECT_INTERVAL=5
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ async function handleStatusRoutes(req, res) {
|
|||||||
const query = url.parse(req.url, true).query;
|
const query = url.parse(req.url, true).query;
|
||||||
const probeType = query.probe || 'liveness';
|
const probeType = query.probe || 'liveness';
|
||||||
|
|
||||||
const dnsHealthy = !!state.dnsPass && state.dnsPass.ready;
|
const dnsHealthy = !!state.dnsPass && state.dnsPass.opened !== false;
|
||||||
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
||||||
const swarmHealthy = state.connectedPeers !== undefined;
|
const swarmHealthy = state.connectedPeers !== undefined;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ async function handleStatusRoutes(req, res) {
|
|||||||
healthy: dnsHealthy,
|
healthy: dnsHealthy,
|
||||||
initialized: !!state.dnsPass,
|
initialized: !!state.dnsPass,
|
||||||
details: {
|
details: {
|
||||||
passReady: !!state.dnsPass?.ready,
|
passReady: state.dnsPass?.opened !== false,
|
||||||
domainsCount: state.domainToIPMap?.size || 0
|
domainsCount: state.domainToIPMap?.size || 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ function broadcastHealth() {
|
|||||||
if (adminClients.size === 0) return;
|
if (adminClients.size === 0) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const dnsHealthy = !!state.dnsPass && state.dnsPass.ready;
|
const dnsHealthy = !!state.dnsPass && state.dnsPass.opened !== false;
|
||||||
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
||||||
const swarmHealthy = state.connectedPeers !== undefined;
|
const swarmHealthy = state.connectedPeers !== undefined;
|
||||||
const corestoreHealthy = state.dnsPass && state.dnsPass.base && state.dnsPass.base.writable !== undefined;
|
const corestoreHealthy = state.dnsPass && state.dnsPass.base && state.dnsPass.base.writable !== undefined;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ async function handleStatusRoutes(req, res) {
|
|||||||
const query = url.parse(req.url, true).query;
|
const query = url.parse(req.url, true).query;
|
||||||
const probeType = query.probe || 'liveness';
|
const probeType = query.probe || 'liveness';
|
||||||
|
|
||||||
const dnsHealthy = !!state.dnsPass && state.dnsPass.ready;
|
const dnsHealthy = !!state.dnsPass && state.dnsPass.opened !== false;
|
||||||
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true';
|
||||||
const swarmHealthy = state.connectedPeers !== undefined;
|
const swarmHealthy = state.connectedPeers !== undefined;
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ async function handleStatusRoutes(req, res) {
|
|||||||
healthy: dnsHealthy,
|
healthy: dnsHealthy,
|
||||||
initialized: !!state.dnsPass,
|
initialized: !!state.dnsPass,
|
||||||
details: {
|
details: {
|
||||||
passReady: !!state.dnsPass?.ready,
|
passReady: state.dnsPass?.opened !== false,
|
||||||
domainsCount: state.domainToIPMap?.size || 0
|
domainsCount: state.domainToIPMap?.size || 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ const countedTies = new Set(); // Set of tie keys: "domain:claimant"
|
|||||||
function isDnsPassUsable(pass) {
|
function isDnsPassUsable(pass) {
|
||||||
if (!pass) return false;
|
if (!pass) return false;
|
||||||
if (pass.closed) return false;
|
if (pass.closed) return false;
|
||||||
|
if (pass.opened === false) return false;
|
||||||
const base = pass.base;
|
const base = pass.base;
|
||||||
if (!base) return false;
|
if (!base) return false;
|
||||||
if (base.closed || base.closing) return false;
|
if (base.closed || base.closing) return false;
|
||||||
if (!pass.ready) return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Resolve whether this process is the Autopass master (invite authority).
|
||||||
|
* Docker/PM2 often omit argv flags; P2NS_MASTER=true is supported as an alternative to --master.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function resolveIsMaster() {
|
||||||
|
if (process.argv.includes('--master')) return true;
|
||||||
|
const v = process.env.P2NS_MASTER ?? process.env.MASTER;
|
||||||
|
if (v === undefined || v === '') return false;
|
||||||
|
const normalized = String(v).trim().toLowerCase();
|
||||||
|
return normalized === '1' || normalized === 'true' || normalized === 'yes';
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { resolveIsMaster };
|
||||||
@@ -68,7 +68,7 @@ module.exports = {
|
|||||||
holesailStartTimes: new Map(), // Track when each p2p-domain holesail connection was started
|
holesailStartTimes: new Map(), // Track when each p2p-domain holesail connection was started
|
||||||
persistentConnections: new Set(), // Track which connections are persistent
|
persistentConnections: new Set(), // Track which connections are persistent
|
||||||
localDnsRecords: [],
|
localDnsRecords: [],
|
||||||
isMaster: process.argv.includes('--master'),
|
isMaster: require('./master-mode').resolveIsMaster(),
|
||||||
sendRemovalRequest: null,
|
sendRemovalRequest: null,
|
||||||
sendConsensusRequest: null,
|
sendConsensusRequest: null,
|
||||||
domainsWithBoth: new Set(),
|
domainsWithBoth: new Set(),
|
||||||
|
|||||||
@@ -142,14 +142,17 @@ async function main() {
|
|||||||
|
|
||||||
logInfo('Main', 'Starting main function...');
|
logInfo('Main', 'Starting main function...');
|
||||||
// Check for flags
|
// Check for flags
|
||||||
const isMaster = process.argv.includes('--master');
|
const { resolveIsMaster } = require('./includes/infrastructure/master-mode');
|
||||||
|
const isMaster = resolveIsMaster();
|
||||||
state.isMaster = isMaster;
|
state.isMaster = isMaster;
|
||||||
const cleanStorage = process.argv.includes('--clean');
|
const cleanStorage = process.argv.includes('--clean');
|
||||||
logInfo('Main', `Master flag detected: ${isMaster}`);
|
const masterViaArgv = process.argv.includes('--master');
|
||||||
|
const masterViaEnv = isMaster && !masterViaArgv;
|
||||||
|
logInfo('Main', `Master mode: ${isMaster} (argv --master: ${masterViaArgv}${masterViaEnv ? ', env P2NS_MASTER/MASTER: true' : ''})`);
|
||||||
if (isMaster) {
|
if (isMaster) {
|
||||||
logInfo('Main', 'Running as MASTER — this node can create and send Autopass invites');
|
logInfo('Main', 'Running as MASTER — this node creates Autopass invites for joiners');
|
||||||
} else {
|
} else {
|
||||||
logInfo('Main', 'Running as JOINER — requires a peer started with --master to receive an invite');
|
logInfo('Main', 'Running as JOINER — needs a peer with --master or P2NS_MASTER=true to receive an invite');
|
||||||
}
|
}
|
||||||
logInfo('Main', `Clean storage flag detected: ${cleanStorage}`);
|
logInfo('Main', `Clean storage flag detected: ${cleanStorage}`);
|
||||||
// Clean storage if requested
|
// Clean storage if requested
|
||||||
@@ -630,20 +633,19 @@ async function main() {
|
|||||||
10000,
|
10000,
|
||||||
'Autopass ready'
|
'Autopass ready'
|
||||||
);
|
);
|
||||||
logDebug('Swarm', 'Paired Autopass ready');
|
logInfo('Swarm', 'Paired Autopass ready — dnsPass initialized');
|
||||||
// Use helper to ensure consistent state
|
// Use helper to ensure consistent state
|
||||||
setDnsPass(newPass);
|
setDnsPass(newPass);
|
||||||
logDebug('Swarm', `Core retrieved for joiner. Writable: ${core.writable}`);
|
logInfo('Swarm', `Joiner core ready. Writable: ${core.writable}`);
|
||||||
// Sync initial data
|
// Sync initial data
|
||||||
await core.update();
|
await core.update();
|
||||||
logDebug('Swarm', 'Synced initial data from master');
|
logDebug('Swarm', 'Synced initial data from master');
|
||||||
|
|
||||||
// Ensure dnsPass is fully ready before proceeding with dependent operations
|
// Ensure dnsPass is fully ready before proceeding with dependent operations
|
||||||
const currentDnsPass = getDnsPass();
|
const currentDnsPass = getDnsPass();
|
||||||
if (currentDnsPass && !currentDnsPass.ready) {
|
if (currentDnsPass && currentDnsPass.opened === false) {
|
||||||
logDebug('Swarm', 'Waiting for dnsPass to be fully ready...');
|
logDebug('Swarm', 'Waiting for dnsPass to finish opening...');
|
||||||
await currentDnsPass.ready();
|
await currentDnsPass.ready();
|
||||||
logDebug('Swarm', 'dnsPass is now fully ready');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup domains watcher for joiner
|
// Setup domains watcher for joiner
|
||||||
@@ -817,7 +819,7 @@ async function main() {
|
|||||||
// Ignore send errors - channel might be closed
|
// Ignore send errors - channel might be closed
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logDebug('Swarm', `Cannot provide invite to ${peerId} - also a joiner waiting for invite from master`);
|
logInfo('Swarm', `Cannot provide invite to ${peerId} — this node is a joiner (no --master / P2NS_MASTER); peer needs the authoritative master`);
|
||||||
try {
|
try {
|
||||||
channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, 'invite_unavailable:joiner');
|
channelManager.sendToPeer(CORE_DOMAIN, 'request', peerId, 'invite_unavailable:joiner');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -846,7 +848,10 @@ async function main() {
|
|||||||
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) {
|
||||||
await channelManager.waitForBidirectionalOpen(invitePeerChannel, 8000);
|
const opened = await channelManager.waitForBidirectionalOpen(invitePeerChannel, 3000);
|
||||||
|
if (!opened) {
|
||||||
|
logWarn('Swarm', `Invite channel not fully open for ${peerId}, sending invite anyway (protomux may queue)`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const inv = await createInvite(pass);
|
const inv = await createInvite(pass);
|
||||||
const invWire = inviteToWire(inv);
|
const invWire = inviteToWire(inv);
|
||||||
@@ -991,7 +996,7 @@ async function main() {
|
|||||||
|
|
||||||
// Ensure dnsPass is fully ready before proceeding with dependent operations
|
// Ensure dnsPass is fully ready before proceeding with dependent operations
|
||||||
const currentDnsPass = getDnsPass();
|
const currentDnsPass = getDnsPass();
|
||||||
if (currentDnsPass && !currentDnsPass.ready) {
|
if (currentDnsPass && currentDnsPass.opened === false) {
|
||||||
logDebug('Swarm', 'Waiting for dnsPass to be fully ready...');
|
logDebug('Swarm', 'Waiting for dnsPass to be fully ready...');
|
||||||
await currentDnsPass.ready();
|
await currentDnsPass.ready();
|
||||||
logDebug('Swarm', 'dnsPass is now fully ready');
|
logDebug('Swarm', 'dnsPass is now fully ready');
|
||||||
@@ -1661,16 +1666,21 @@ async function main() {
|
|||||||
if (!isDnsPassUsable(newPass)) {
|
if (!isDnsPassUsable(newPass)) {
|
||||||
logError('Main', 'Autopass base core is not usable after ready(). Storage may be from Autopass 2 or corrupted.');
|
logError('Main', 'Autopass base core is not usable after ready(). Storage may be from Autopass 2 or corrupted.');
|
||||||
logError('Main', 'Stop the process and restart with: node p2ns.js --clean --master');
|
logError('Main', 'Stop the process and restart with: node p2ns.js --clean --master');
|
||||||
|
} else {
|
||||||
|
logInfo('Main', `Autopass dnsPass ready (writable: ${core.writable})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logInfo('Main', `Core retrieved. Writable: ${core.writable}, Key: ${core.key.toString('hex')}`);
|
logInfo('Main', `Core retrieved. Writable: ${core.writable}, Key: ${core.key.toString('hex')}`);
|
||||||
// Setup domains watcher for master
|
// Setup domains watcher for master
|
||||||
setupDomainsWatcher();
|
setupDomainsWatcher();
|
||||||
setupListeners();
|
setupListeners();
|
||||||
|
} else if (!getDnsPass()) {
|
||||||
|
logInfo('Main', 'Joiner: dnsPass not loaded — will request an invite after peers connect');
|
||||||
}
|
}
|
||||||
// Join the topic with both server and client modes for better local network discovery
|
// Join the topic with both server and client modes for better local network discovery
|
||||||
swarm.join(topic, { server: true, client: true });
|
swarm.join(topic, { server: true, client: true });
|
||||||
logInfo('Main', 'Joined Hyperswarm topic (server: true, client: true)');
|
logInfo('Main', 'Joined Hyperswarm topic (server: true, client: true)');
|
||||||
|
logInfo('Main', `Network ready: role=${isMaster ? 'MASTER' : 'JOINER'}, dnsPass=${getDnsPass() ? 'initialized' : 'pending invite'}`);
|
||||||
|
|
||||||
// Set up periodic topic rejoin to ensure swarm stays connected
|
// Set up periodic topic rejoin to ensure swarm stays connected
|
||||||
// This helps all nodes (master and joiner) maintain their connection to the DHT network
|
// This helps all nodes (master and joiner) maintain their connection to the DHT network
|
||||||
|
|||||||
Reference in New Issue
Block a user