Files
peardata/server/db/remote.js
T
Raven Scott 1d46b7b3ad
CI / test (push) Failing after 6s
Release rolling / release (push) Has been cancelled
updates
2026-07-18 19:11:32 -04:00

86 lines
2.4 KiB
JavaScript

/**
* Open linked peer HyperDBs (read-only) after Corestore replication.
*
* Local agent always owns `peardata-meta`. Linked peers' bees are opened by
* `dbKeyHex` so warm `@peardata/metric-point` rows become queryable without
* re-scraping the remote host.
*/
import b4a from 'b4a'
import { PearDataModel } from './model.js'
import { getCorestore } from './index.js'
import logger from '../utils/logger.js'
const log = logger.child('db:remote')
/** @type {Map<string, PearDataModel>} */
const remotes = new Map()
/**
* @param {string} dbKeyHex
* @returns {Promise<PearDataModel|null>}
*/
export async function openRemoteDb(dbKeyHex) {
const keyHex = String(dbKeyHex || '').toLowerCase()
if (!/^[0-9a-f]{64}$/.test(keyHex)) return null
if (remotes.has(keyHex)) return remotes.get(keyHex)
const store = getCorestore()
if (!store) {
log.warn('openRemoteDb: Corestore not open')
return null
}
const core = store.get({ key: b4a.from(keyHex, 'hex') })
const model = new PearDataModel(core, { writable: false, autoUpdate: true })
await model.ready()
remotes.set(keyHex, model)
log.info('Opened remote HyperDB', { dbKeyHex: keyHex.slice(0, 16) })
return model
}
/**
* @param {string} dbKeyHex
*/
export function getRemoteDb(dbKeyHex) {
return remotes.get(String(dbKeyHex || '').toLowerCase()) || null
}
export function listRemoteDbs() {
return [...remotes.entries()].map(([dbKeyHex, model]) => ({
dbKeyHex,
discoveryKeyHex: model.discoveryKeyHex,
length: model.db?.core?.length ?? null,
}))
}
/**
* Query warm metric points across all open remote DBs (first hit wins per call site).
* @param {{ chart: string, afterMs: number, beforeMs: number, limit?: number, tier?: number }} opts
*/
export async function queryRemoteMetricPoints(opts) {
/** @type {Array<{ chart: string, context: string, ts: number, tier: number, values: object }>} */
const all = []
for (const model of remotes.values()) {
try {
const rows = await model.queryMetricPoints(opts)
if (rows?.length) all.push(...rows)
} catch {
// ignore per-remote failures
}
}
all.sort((a, b) => a.ts - b.ts)
const limit = opts.limit || 10_000
return all.length > limit ? all.slice(-limit) : all
}
export async function closeRemoteDbs() {
for (const [key, model] of remotes) {
try {
await model.close()
} catch {
// ignore
}
remotes.delete(key)
}
}