hyperns-service
Version:
HyperNS service, based on autobase
111 lines (86 loc) • 2.72 kB
JavaScript
const { EventEmitter } = require('events')
const IdEnc = require('hypercore-id-encoding')
const cenc = require('compact-encoding')
const BlindPeerClient = require('blind-peer/client.js')
const b4a = require('b4a')
const HyperNsService = require('.')
const opEncoding = HyperNsService.VALUE_ENCODING
class HyperNsRegisterClient extends EventEmitter {
constructor (blindPeerKey, autobaseKey, swarm) {
super()
this.blindPeerKey = IdEnc.decode(blindPeerKey)
this.autobaseKey = IdEnc.decode(autobaseKey)
this.swarm = swarm
this._boundConnHandler = this._connHandler.bind(this)
this.swarm.on('connection', this._boundConnHandler)
this._peer = null
}
open () {
this.swarm.joinPeer(this.blindPeerKey)
}
close () {
this.emit('closing')
this.swarm.off('connection', this._boundConnHandler)
// Note: this can have side effects if we're connecting to that
// peer for other reasons (ignoring that potential issue for now)
this.swarm.leavePeer(this.blindPeerKey)
}
async _connHandler (conn) {
if (!b4a.equals(conn.remotePublicKey, this.blindPeerKey)) return
this.emit('connection-open')
conn.on('close', () => {
this.emit('connection-close')
this._peer = null
})
this._peer = new BlindPeerClient(conn)
}
async ensureConnected (timeoutMs = 5000) {
if (this._peer) return
await new Promise((resolve, reject) => {
let cancelHandler = null
let timeout = null
const cleanup = () => {
this.removeListener('closing', cancelHandler)
clearTimeout(timeout)
}
timeout = setTimeout(
() => {
cleanup()
reject(new Error('Ensure connected timed out'))
},
timeoutMs
)
cancelHandler = () => {
cleanup()
reject(new Error('Register client is closing'))
}
this.on('closing', cancelHandler)
this.once('connection-open', () => {
cleanup()
resolve()
})
})
}
async register (name, publicKey, blindPeers) {
blindPeers = blindPeers || []
const record = {
name,
publicKey: IdEnc.decode(publicKey),
blindPeers
}
// Note: We could also await once(this, 'connection-open') with a timeout,
// for a slightly friendlier UX
if (this._peer === null) throw new Error('Not connected to blind peer')
const message = {
op: HyperNsService.OPS.ADD_RECORD,
record
}
const reply = await this._peer.post({
autobase: this.autobaseKey,
message: cenc.encode(opEncoding, message)
})
const autobaseLength = reply.length
return autobaseLength
}
}
module.exports = HyperNsRegisterClient