fix: guild mesh dual-conn uses Holepunch initiator tie-break

Keep/drop sockets with shouldKeepNewConnection, wire peerInfo on
connection handlers, and preserve leave grace for stable peer maps.
This commit is contained in:
Raven Scott
2026-07-13 03:05:37 -04:00
parent 4495cb38ef
commit 1acb62b9a7
+32 -16
View File
@@ -1716,8 +1716,9 @@ class PearcordGuild extends EventEmitter {
if (this._meshConnectionHandler) {
this.swarm.removeListener('connection', this._meshConnectionHandler)
}
this._meshConnectionHandler = (conn) => {
this._registerMeshPeer(conn, { emitPeer: true })
// Holepunch: connection handler is (socket, peerInfo)
this._meshConnectionHandler = (conn, peerInfo) => {
this._registerMeshPeer(conn, { emitPeer: true, peerInfo: peerInfo || null })
}
this._meshHandlerBound = true
this.swarm.on('connection', this._meshConnectionHandler)
@@ -1758,25 +1759,40 @@ class PearcordGuild extends EventEmitter {
_registerMeshPeer (conn, opts = {}) {
if (!conn?.remotePublicKey) return { peerId: null, isNew: false }
const emitPeer = opts.emitPeer !== false
const peerInfo = opts.peerInfo || null
const peerId = b4a.toString(conn.remotePublicKey, 'hex')
const prevConn = this.peers.get(peerId)
const isReplacement = prevConn && prevConn !== conn
// Hyperswarm often opens two sockets; keep the live one and drop the duplicate
// so join/leave does not thrash the mesh status and gossip outbox.
// Holepunch dual-connection tie-break (same rules as hyperswarm/index.js).
const { shouldKeepNewConnection, wireSwarmConnection } = require('pearcord-shared')
wireSwarmConnection(conn)
if (isReplacement && prevConn && !prevConn.destroyed && !prevConn.closed) {
const keepNew = shouldKeepNewConnection(prevConn, conn)
if (!keepNew) {
try {
if (typeof prevConn.sendKeepAlive === 'function') prevConn.sendKeepAlive()
} catch {
// ignore
}
try {
conn.destroy()
} catch {
// ignore
}
this._ensureMeshPeerWires(peerId, prevConn)
const pending = this._peerLeaveGraceTimers?.get?.(peerId)
if (pending) {
clearTimeout(pending)
this._peerLeaveGraceTimers.delete(peerId)
}
return { peerId, isNew: false, duplicate: true, peerInfo }
}
// Keep new: tear down old without emitting leave (swap).
try {
conn.destroy()
prevConn.destroy()
} catch {
// ignore
}
this._ensureMeshPeerWires(peerId, prevConn)
// Cancel a pending leave grace if the peer is still live.
const pending = this._peerLeaveGraceTimers?.get?.(peerId)
if (pending) {
clearTimeout(pending)
this._peerLeaveGraceTimers.delete(peerId)
}
return { peerId, isNew: false, duplicate: true }
}
const isNew = !prevConn
if (isReplacement) {
@@ -1819,12 +1835,12 @@ class PearcordGuild extends EventEmitter {
})
}
if (emitPeer && isNew) {
this.emit('peer', { peerId, type: 'join' })
this.emit('peer', { peerId, type: 'join', peerInfo })
} else if (emitPeer && isReplacement) {
// Soft rewire only — avoid full peer-join handshake storms.
this.emit('peer', { peerId, type: 'replace' })
this.emit('peer', { peerId, type: 'replace', peerInfo })
}
return { peerId, isNew }
return { peerId, isNew, peerInfo }
}
reconcileMeshConnectionsFromSwarm () {