+60
-11
@@ -101,7 +101,10 @@
|
||||
|
||||
/**
|
||||
* BridgeSwarm: join topics, receive connection events, leave/destroy.
|
||||
* @param {{ appName?: string }} [options] - Passed to Hyperswarm (e.g. appName).
|
||||
* @param {{ appName?: string, maxPeers?: number, swarmId?: string, seedHex?: string }} [options]
|
||||
* - appName / maxPeers: Hyperswarm-ish options (appName is metadata for the dashboard)
|
||||
* - swarmId: reuse an existing host swarm (page reload / session resume)
|
||||
* - seedHex: 64-char hex seed for a stable Noise keypair across destroys
|
||||
*/
|
||||
function BridgeSwarm(options) {
|
||||
EventEmitter.call(this);
|
||||
@@ -113,8 +116,9 @@
|
||||
defaults.maxPeers != null && defaults.maxPeers > 0 && opts.maxPeers == null && { maxPeers: defaults.maxPeers },
|
||||
opts
|
||||
);
|
||||
// Unique swarmId for each tab to have its own keyPair
|
||||
this.swarmId = 'swarm_' + Math.random().toString(36).slice(2, 10);
|
||||
// Prefer caller-provided swarmId so reloads can resume the host swarm
|
||||
const requestedId = typeof opts.swarmId === 'string' ? opts.swarmId.trim() : '';
|
||||
this.swarmId = requestedId || ('swarm_' + Math.random().toString(36).slice(2, 10));
|
||||
this._initPromise = null;
|
||||
this._eventUnsub = null;
|
||||
this._boundOnEvent = this._onEvent.bind(this);
|
||||
@@ -248,17 +252,62 @@
|
||||
|
||||
/**
|
||||
* Get the public key (hex) of this swarm's key pair.
|
||||
* Ensures the host swarm is initialized first (safe to call before join).
|
||||
* @returns {Promise<string>} Public key as 64-character hex string.
|
||||
*/
|
||||
BridgeSwarm.prototype.getPublicKey = function () {
|
||||
return sendToBridge({
|
||||
id: generateId(),
|
||||
type: 'swarmKey',
|
||||
payload: { swarmId: this.swarmId },
|
||||
}).then((res) => {
|
||||
if (res && !res.ok) throw new Error(res.error || 'Failed to get public key');
|
||||
return res.publicKey;
|
||||
});
|
||||
return this._init().then(() =>
|
||||
sendToBridge({
|
||||
id: generateId(),
|
||||
type: 'swarmKey',
|
||||
payload: { swarmId: this.swarmId },
|
||||
}).then((res) => {
|
||||
if (res && !res.ok) throw new Error(res.error || 'Failed to get public key');
|
||||
return res.publicKey;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Re-attach page wrappers for connections that already exist on the host
|
||||
* (e.g. after a page reload with the same swarmId). Emits a `connection`
|
||||
* event for each live peer that is not already tracked.
|
||||
* @returns {Promise<BridgeSwarmConnection[]>}
|
||||
*/
|
||||
BridgeSwarm.prototype.resumeConnections = function () {
|
||||
const swarm = this;
|
||||
return this._init().then(() =>
|
||||
sendToBridge({
|
||||
id: generateId(),
|
||||
type: 'listConnections',
|
||||
payload: { swarmId: swarm.swarmId },
|
||||
}).then((res) => {
|
||||
if (res && !res.ok) throw new Error(res.error || 'listConnections failed');
|
||||
if (!swarm._connections) swarm._connections = new Map();
|
||||
const out = [];
|
||||
const list = (res && res.connections) || [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (!item || !item.connId) continue;
|
||||
if (swarm._connections.has(item.connId)) {
|
||||
out.push(swarm._connections.get(item.connId));
|
||||
continue;
|
||||
}
|
||||
const conn = new BridgeSwarmConnection(item.connId, swarm.swarmId);
|
||||
swarm._connections.set(item.connId, conn);
|
||||
conn.on('end', () => {
|
||||
if (swarm._connections) swarm._connections.delete(item.connId);
|
||||
});
|
||||
const peerInfo = Object.assign({}, item.peerInfo || {});
|
||||
peerInfo.ban = function (banned) {
|
||||
return swarm.ban(peerInfo.publicKey, banned !== false);
|
||||
};
|
||||
swarm.emit('connection', conn, peerInfo, { resumed: true, connId: item.connId });
|
||||
out.push(conn);
|
||||
}
|
||||
return out;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user