autobase-discovery
Version:
Automatic service discovery with self-registering services, using autobase
105 lines (85 loc) • 4.02 kB
JavaScript
const Corestore = require('corestore')
const IdEnc = require('hypercore-id-encoding')
const Hyperswarm = require('hyperswarm')
const goodbye = require('graceful-goodbye')
const { command, flag, arg } = require('paparam')
const HyperInstrumentation = require('hyper-instrument')
const pino = require('pino')
const path = require('path')
const Autodiscovery = require('.')
const runCmd = command('run',
arg('<rpcAllowedPublicKey>', 'public key of peers that are allowed to send requests over RPC (in hex or z32 format)'),
flag('--storage|-s [path]', 'storage path, defaults to ./autodiscovery'),
flag('--scraper-public-key [scraper-public-key]', 'Public key of a dht-prometheus scraper'),
flag('--scraper-secret [scraper-secret]', 'Secret of the dht-prometheus scraper'),
flag('--scraper-alias [scraper-alias]', '(optional) Alias with which to register to the scraper'),
flag('--bootstrap [bootstrap]', '(for tests) Bootstrap DHT node to use, in format <host>:<port> (e.g. 127.0.0.1:10000)'),
async function ({ flags, args }) {
const logger = pino({ name: 'autobase-discovery' })
const storage = path.resolve(flags.storage || 'autodiscovery')
const rpcAllowedPublicKey = IdEnc.decode(args.rpcAllowedPublicKey)
let bootstrap = null
if (flags.bootstrap) {
const [host, port] = flags.bootstrap.split(':')
bootstrap = [{ port: parseInt(port), host }]
logger.warn(`Using non-standard bootstrap: ${bootstrap[0].host}:${bootstrap[0].port}`)
}
logger.info(`Using storage: ${storage}`)
const store = new Corestore(storage)
await store.ready()
const swarm = new Hyperswarm(
{ keyPair: await store.createKeyPair('public-key'), bootstrap }
)
swarm.on('connection', (conn, peerInfo) => {
const key = IdEnc.normalize(peerInfo.publicKey)
logger.info(`Opened connection to ${key}`)
conn.on('close', () => logger.info(`Closed connection to ${key}`))
})
let instrumentation = null
if (flags.scraperPublicKey) {
logger.info('Setting up instrumentation')
const scraperPublicKey = IdEnc.decode(flags.scraperPublicKey)
const scraperSecret = IdEnc.decode(flags.scraperSecret)
const prometheusServiceName = 'autodiscovery'
let prometheusAlias = flags.scraperAlias
if (prometheusAlias && prometheusAlias.length > 99) throw new Error('The Prometheus alias must have length less than 100')
if (!prometheusAlias) {
prometheusAlias = `autodiscovery-${IdEnc.normalize(swarm.keyPair.publicKey)}`.slice(0, 99)
}
instrumentation = new HyperInstrumentation({
swarm,
corestore: store,
scraperPublicKey,
prometheusAlias,
scraperSecret,
prometheusServiceName
})
instrumentation.registerLogger(logger)
}
const service = new Autodiscovery(
store.namespace('autodiscovery'), swarm, rpcAllowedPublicKey
)
service.on('rpc-session', () => {
logger.info('Opened RPC session')
})
goodbye(async () => {
logger.info('Shutting down autodiscovery service')
if (instrumentation) await instrumentation.close()
await swarm.destroy()
await service.close()
})
if (instrumentation) await instrumentation.ready()
logger.info('Starting autodiscovery service')
await service.ready()
swarm.join(service.base.discoveryKey)
swarm.join(service.dbDiscoveryKey, { client: true, server: true }) // Note: needs client: true when being replicated by a blind-peer
logger.info(`DB version: ${service.view.db.core.length}`)
logger.info(`Autobase key: ${IdEnc.normalize(service.base.key)}`)
logger.info(`Name-service database key: ${IdEnc.normalize(service.dbKey)}`)
logger.info(`RPC server public key: ${IdEnc.normalize(service.serverPublicKey)}`)
logger.info(`Accepting RPC connections from public key ${IdEnc.normalize(rpcAllowedPublicKey)}`)
}
)
const cmd = command('autodiscovery', runCmd)
cmd.parse()