OverviewFilesCommitsIssuesDocsReleasesPeers

favela-community / test / live-swarm-e2e.mjs

75 lines · javascript ref:
// LIVE swarm e2e — over the REAL DHT (real Hyperswarm bootstrap, NOT @hyperswarm/testnet, NOT in-process
// pipes). Two INDEPENDENT swarm nodes discover each other on the DHT and replicate a community room:
//   - SEEDER  : an owner room + a real Hyperswarm serving it — the exact mechanism the CLI `serve` uses
//               (base.replicate on every connection, join(discoveryKey)).
//   - READER  : favela-web's exact keyless read path — CommunityRooms(store, realSwarm).members(roomKey).
// Proves: owner `serve` ↔ favela-web keyless read, over a live swarm. Needs NETWORK (DHT bootstrap).
// Run: npm run e2e   (NOT part of the offline `npm test`).
import process from 'bare-process'
import Corestore from 'corestore'
import Hyperswarm from 'hyperswarm'
import { CommunityRoom, CommunityRooms } from '../index.js'

const stamp = Date.now()
const SEED_STORE = 'data/e2e-seed-' + stamp
const READ_STORE = 'data/e2e-read-' + stamp
const MEMBERS = ['did:plc:alice2222222222222222222', 'did:plc:bob222222222222222222222', 'did:plc:carol22222222222222222222']
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
const log = (...a) => console.log('[e2e]', ...a)

let seedStore, readStore, seedSwarm, readSwarm, rooms, ownerRoom
async function cleanup () {
  try { if (seedSwarm) await seedSwarm.destroy() } catch {}
  try { if (readSwarm) await readSwarm.destroy() } catch {}
  try { if (rooms) await rooms.close() } catch {}
  try { if (ownerRoom) await ownerRoom.close() } catch {}
  try { if (seedStore) await seedStore.close() } catch {}
  try { if (readStore) await readStore.close() } catch {}
}

async function main () {
  // ── SEEDER: owner creates + populates a room, then serves it on a real swarm ──
  seedStore = new Corestore(SEED_STORE)
  ownerRoom = await CommunityRoom.create(seedStore, { name: 'Live E2E' })
  const KEY = ownerRoom.key
  for (const did of MEMBERS) await ownerRoom.addMember(did)
  await ownerRoom.update()
  log('owner created + populated room', KEY, '(' + (await ownerRoom.members()).length + ' members)')

  seedSwarm = new Hyperswarm()
  seedSwarm.on('connection', (conn) => { conn.on('error', () => {}); ownerRoom.base.replicate(conn) }) // the CLI `serve` mechanism
  seedSwarm.join(ownerRoom.discoveryKey, { server: true, client: true })
  await seedSwarm.flush()
  log('seeder announced on the DHT (discoveryKey', Buffer.from(ownerRoom.discoveryKey).toString('hex').slice(0, 16) + '…)')

  // ── READER: favela-web's exact keyless read over an INDEPENDENT real swarm ──
  readStore = new Corestore(READ_STORE)
  readSwarm = new Hyperswarm()
  rooms = new CommunityRooms(readStore, readSwarm) // joins the room's discoveryKey on first members()
  log('reader joining the DHT + waiting for a live connection + replication…')

  let got = []
  const end = Date.now() + 90000
  let firstSeen = 0
  while (Date.now() < end) {
    try { got = await rooms.members(KEY) } catch {}
    const conns = readSwarm.connections.size
    if (conns && !firstSeen) { firstSeen = Date.now(); log('reader connected to a peer (' + conns + ') — replicating…') }
    if (got.length >= MEMBERS.length) break
    await sleep(1500)
  }

  const room = await rooms.room(KEY)
  const keyless = !room.writable
  const ok = keyless && got.length === MEMBERS.length && MEMBERS.every((m) => got.includes(m))
  log('reader keyless (not writable):', keyless)
  log('reader read', got.length, '/', MEMBERS.length, 'members over the live swarm:', JSON.stringify(got))
  log(ok
    ? '\nPASS — an independent keyless reader discovered the served room on the real DHT and read the full roster.'
    : '\nFAIL — reader did not converge on the roster over the live swarm within 90s.')
  return ok
}

main().then(async (ok) => { await cleanup(); process.exit(ok ? 0 : 1) })
  .catch(async (e) => { console.error('[e2e] ERROR:', e && (e.stack || e.message)); await cleanup(); process.exit(1) })