OverviewFilesCommitsIssuesDocsReleasesPeers

godot-keet / tests / bootstrap-rooms.mjs

165 lines · javascript ref:
/**
 * bootstrap-rooms.mjs — One-shot metadata bootstrap for all rooms
 *
 * Sets topics, discoverable, language, category on all chat rooms.
 * Skips DMs (RoomType=2). Then runs topic.announceAll.
 *
 * Requires: keet-daemon running on /tmp/keet-daemon.sock
 * Usage: bare tests/bootstrap-rooms.mjs
 */

import Pipe from 'bare-pipe'
import FramedStream from 'framed-stream'
import b4a from 'b4a'

const SOCKET = '/tmp/keet-daemon.sock'
let rpcId = 0

// --- Room metadata assignments ---
// Key = room title, Value = { topics, category }
const ROOM_META = {
  'AI Testing Town': { topics: ['ai', 'testing', 'p2p', 'development'], category: 'development' },
  morky: { topics: ['testing', 'random'], category: 'social' },
  'The Lobby': { topics: ['social', 'lobby', 'general'], category: 'social' },
  invite_channel: { topics: ['invite', 'onboarding', 'welcome'], category: 'onboarding' },
  'test 5': { topics: ['testing', 'p2p'], category: 'testing' },
  'fifty seven': { topics: ['testing', 'p2p'], category: 'testing' },
  'clode test room': { topics: ['ai', 'testing', 'bots'], category: 'testing' },
  testy1: { topics: ['testing', 'p2p'], category: 'testing' },
  newtron: { topics: ['testing', 'new'], category: 'testing' },
  'test room 1': { topics: ['testing'], category: 'testing' },
  '(untitled)': { topics: ['testing', 'scratch'], category: 'testing' },
  'test 7': { topics: ['testing'], category: 'testing' }
}

// --- RPC client ---

function connect () {
  const pipe = new Pipe(SOCKET)
  const framed = new FramedStream(pipe)
  const pending = new Map()

  framed.on('data', (buf) => {
    try {
      const msg = JSON.parse(b4a.toString(buf))
      const cb = pending.get(msg.id)
      if (cb) {
        pending.delete(msg.id)
        if (msg.ok !== undefined && msg.data !== undefined) msg.result = msg.data
        cb(msg)
      }
    } catch {}
  })

  function call (method, params = {}) {
    return new Promise((resolve, reject) => {
      const id = ++rpcId
      const timeout = setTimeout(() => {
        pending.delete(id)
        reject(new Error('RPC timeout: ' + method))
      }, 15000)
      pending.set(id, (msg) => {
        clearTimeout(timeout)
        if (msg.error) reject(new Error(msg.error.message || msg.error))
        else resolve(msg.result)
      })
      const payload = JSON.stringify({ jsonrpc: '2.0', id, method, params })
      framed.write(b4a.from(payload))
    })
  }

  function close () {
    framed.destroy()
    pipe.destroy()
  }

  return { call, close }
}

// --- Bootstrap ---

async function run () {
  console.log('=== Room Metadata Bootstrap ===\n')

  const client = connect()
  const rooms = await client.call('rooms')
  console.log('Found ' + rooms.length + ' rooms\n')

  let bootstrapped = 0
  let skipped = 0

  for (const room of rooms) {
    const roomId = room.roomId || room.id
    const title = room.title || '(untitled)'

    // Check room type — skip DMs
    let roomType = 0
    try {
      const info = await client.call('room', { roomId })
      roomType = info.digest?.settings?.roomType || 0
    } catch {}

    if (roomType === 2) {
      console.log('SKIP (DM): ' + title)
      skipped++
      continue
    }

    // Look up metadata assignment
    const assignment = ROOM_META[title]
    if (!assignment) {
      console.log('SKIP (no assignment): ' + title)
      skipped++
      continue
    }

    // Set metadata
    try {
      const result = await client.call('meta.set', {
        roomId,
        metadata: {
          topics: assignment.topics,
          discoverable: true,
          language: 'en',
          category: assignment.category
        }
      })
      console.log('OK: ' + title + ' → topics=' + JSON.stringify(result.topics) + ', discoverable=' + result.discoverable)
      bootstrapped++
    } catch (err) {
      console.log('FAIL: ' + title + ' → ' + err.message)
    }
  }

  // Announce all discoverable rooms on DHT
  console.log('\n--- DHT Announce ---')
  try {
    const result = await client.call('topic.announceAll')
    console.log('OK: Announced ' + result.announced + ' rooms on DHT')
  } catch (err) {
    console.log('FAIL: topic.announceAll → ' + err.message)
  }

  // Verify — read back all metadata
  console.log('\n--- Verification ---')
  for (const room of rooms) {
    const roomId = room.roomId || room.id
    const title = room.title || '(untitled)'
    try {
      const meta = await client.call('meta.get', { roomId })
      if (meta.discoverable) {
        console.log('  ' + title + ': topics=' + JSON.stringify(meta.topics) + ' category=' + meta.category + ' lang=' + meta.language)
      }
    } catch {}
  }

  console.log('\n=== RESULT: ' + bootstrapped + ' bootstrapped, ' + skipped + ' skipped ===')
  client.close()
  setTimeout(() => Bare.exit(0), 500)
}

run().catch(err => {
  console.log('FATAL: ' + err.message)
  Bare.exit(1)
})