OverviewFilesCommitsIssuesDocsReleasesPeers

keet-daemon / test / probe-local-db.js

91 lines · javascript ref:
// probe-local-db.js — open a keet-cli identity dir's local HyperDB (a
// RocksDB column family inside <identity>/0/db) and dump @local/identity,
// @local/rooms, @local/writers WITHOUT booting keet-core. This bypasses
// the onlineBoot deadlock so we can see what state the autocreate-then-
// crash actually left on disk.
//
// Usage:
//   bare test/probe-local-db.js <identity-dir>
//   e.g. bare test/probe-local-db.js ~/.config/keet-cli/identity-1
//
// SAFETY: opens read-only. Will refuse if the RocksDB LOCK file shows
// another process is currently using the dir.

import path from 'bare-path'
import fs from 'bare-fs'
import CorestoreStorage from 'hypercore-storage'
import HyperDB from 'hyperdb'
import spec from '../node_modules/@holepunchto/keet-core/schema/spec/index.js'

function truncBuf (v) {
  if (v && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
    const buf = Buffer.from(v.data)
    return buf.toString('hex').slice(0, 64) + (buf.length > 32 ? '…(' + buf.length + 'b)' : '')
  }
  return v
}

function jsonify (obj) {
  return JSON.parse(JSON.stringify(obj, (k, v) => {
    if (Buffer.isBuffer(v)) return v.toString('hex').slice(0, 64) + (v.length > 32 ? '…(' + v.length + 'b)' : '')
    if (v && v.type === 'Buffer' && Array.isArray(v.data)) {
      const buf = Buffer.from(v.data)
      return buf.toString('hex').slice(0, 64) + (buf.length > 32 ? '…(' + buf.length + 'b)' : '')
    }
    return v
  }))
}

async function dumpCollection (db, name) {
  console.log('\n--- ' + name + ' ---')
  try {
    const entries = await db.find(name).toArray()
    console.log('count: ' + entries.length)
    for (let i = 0; i < entries.length; i++) {
      console.log('[' + i + ']', JSON.stringify(jsonify(entries[i]), null, 2))
    }
  } catch (err) {
    console.log('ERROR reading ' + name + ': ' + err.message)
  }
}

async function main () {
  const dir = Bare.argv[2]
  if (!dir) {
    console.error('usage: bare test/probe-local-db.js <identity-dir>')
    Bare.exit(1)
  }
  const profileDir = path.join(dir, '0')
  if (!fs.existsSync(profileDir)) {
    console.error('not found: ' + profileDir)
    Bare.exit(1)
  }
  console.log('[probe] opening (readOnly):', profileDir)
  const storage = new CorestoreStorage(profileDir, { readOnly: true })
  // Register the column family BEFORE storage.ready() flushes the schema —
  // rocksdb-native only auto-creates column families pre-flush.
  const cf = storage.rocks.columnFamily('keet/local-database')
  await storage.ready()
  console.log('[probe] storage ready')
  const db = HyperDB.rocks(cf, spec.local.hyperdb)
  await db.ready()
  console.log('[probe] hyperdb ready (version ' + (db.version || '?') + ')')

  await dumpCollection(db, '@local/identity')
  await dumpCollection(db, '@local/rooms')
  await dumpCollection(db, '@local/writers')
  await dumpCollection(db, '@local/devices')
  await dumpCollection(db, '@local/migrations')

  await db.close()
  await storage.close()
  console.log('\n[probe] done')
  Bare.exit(0)
}

main().catch(err => {
  console.error('[probe] uncaught:', err && err.message)
  if (err && err.stack) console.error(err.stack)
  Bare.exit(1)
})