/**
* ReplicationManager — Hyperswarm P2P replication
*
* Announces local notebook drives on the swarm, joins remote drives.
* Uses store.replicate(conn) so only cores the remote requests by
* discovery key are served — the registry core's key is never shared.
*/
import Hyperswarm from 'hyperswarm'
export class ReplicationManager {
constructor (store, driveManager) {
this.store = store
this.driveManager = driveManager
this.swarm = null
this._discoveries = new Map() // slug → discovery handle
this._connections = new Set()
}
/**
* Create swarm and wire store.replicate on every connection.
*/
async start () {
this.swarm = new Hyperswarm()
this.swarm.on('connection', (conn, info) => {
this.store.replicate(conn)
this._connections.add(conn)
conn.on('close', () => { this._connections.delete(conn) })
conn.on('error', () => {}) // error is followed by close, which handles cleanup
})
}
/**
* Destroy swarm cleanly.
*/
async stop () {
if (!this.swarm) return
await this.swarm.destroy()
this.swarm = null
this._discoveries.clear()
this._connections.clear()
}
/**
* Announce a local notebook on the swarm (server + client mode).
*/
async announce (slug) {
if (!this.swarm) return
const info = await this.driveManager.getDriveInfo(slug)
if (!info) return
const discoveryKey = Buffer.from(info.discoveryKey, 'hex')
const discovery = this.swarm.join(discoveryKey, { server: true, client: true })
this._discoveries.set(slug, discovery)
await this.driveManager.setShared(slug, true)
}
/**
* Stop announcing a notebook.
*/
async unannounce (slug) {
const discovery = this._discoveries.get(slug)
if (discovery) {
await discovery.destroy()
this._discoveries.delete(slug)
}
await this.driveManager.setShared(slug, false)
}
/**
* Announce all notebooks that have isShared === true.
*/
async announceAll () {
const drives = await this.driveManager.listDrives()
for (const entry of drives) {
if (entry.isShared && entry.isLocal) {
await this.announce(entry.slug)
}
}
}
/**
* Join a remote notebook topic (client-only mode).
*/
async joinRemote (slug) {
if (!this.swarm) return
const info = await this.driveManager.getDriveInfo(slug)
if (!info) return
const discoveryKey = Buffer.from(info.discoveryKey, 'hex')
const discovery = this.swarm.join(discoveryKey, { server: false, client: true })
this._discoveries.set(slug, discovery)
}
/**
* Get current sync status.
*/
getStatus () {
return {
swarmActive: this.swarm !== null,
peersConnected: this._connections.size,
announced: [...this._discoveries.keys()]
}
}
}
export default ReplicationManager