use multiaddr from updated ppppp-net

This commit is contained in:
Andre Staltz 2024-01-16 11:32:16 +02:00
parent c62e7fc3bf
commit ff9971389e
No known key found for this signature in database
GPG Key ID: 9EDE23EA7E8A4890
4 changed files with 114 additions and 76 deletions

View File

@ -4,6 +4,8 @@ const pull = require('pull-stream')
const getSeverity = require('ssb-network-errors') const getSeverity = require('ssb-network-errors')
/** /**
* @typedef {ReturnType<import('ppppp-net').init>} PPPPPNet
* @typedef {{net: PPPPPNet, shse: {pubkey: string}}} Peer
* @typedef {(pull.Sink<AttendantsEvent> & {abort: () => void})} Drain * @typedef {(pull.Sink<AttendantsEvent> & {abort: () => void})} Drain
* @typedef {{type: 'state', pubkeys: Array<string>}} AttendantsEventState * @typedef {{type: 'state', pubkeys: Array<string>}} AttendantsEventState
* @typedef {{type: 'joined', pubkey: string}} AttendantsEventJoined * @typedef {{type: 'joined', pubkey: string}} AttendantsEventJoined
@ -15,49 +17,31 @@ const getSeverity = require('ssb-network-errors')
*/ */
module.exports = class HubObserver { module.exports = class HubObserver {
/** /**@readonly @type {Peer}*/
* @readonly
* @type {any}
*/
#peer #peer
/**@type {string}*/
/**
* @type {string}
*/
#hubPubkey #hubPubkey
/**@type {`/${string}`}*/
/** #multiaddr
* @type {string} /**@type {{name: string, admin: string}}*/
*/
#address
/**
* @type {{name: string, admin: string}}
*/
#hubMetadata #hubMetadata
/**@type {Set<string>}*/
/**
* @type {Set<string>}
*/
#attendants #attendants
/**@type {Drain | undefined}*/
/**
* @type {Drain | undefined}
*/
#attendantsDrain #attendantsDrain
/** /**
* @param {any} peer * @param {Peer} peer
* @param {string} hubPubkey * @param {string} hubPubkey
* @param {string} address * @param {`/${string}`} multiaddr
* @param {{name: string, admin: string}} hubMetadata * @param {{name: string, admin: string}} hubMetadata
* @param {any} rpc * @param {any} rpc
* @param {any} onConnect * @param {any} onConnect
*/ */
constructor(peer, hubPubkey, address, hubMetadata, rpc, onConnect) { constructor(peer, hubPubkey, multiaddr, hubMetadata, rpc, onConnect) {
this.#peer = peer this.#peer = peer
this.#hubPubkey = hubPubkey this.#hubPubkey = hubPubkey
this.#address = address this.#multiaddr = multiaddr
this.#hubMetadata = hubMetadata this.#hubMetadata = hubMetadata
this.#attendants = new Set() this.#attendants = new Set()
@ -80,12 +64,12 @@ module.exports = class HubObserver {
this.#hubMetadata && this.#hubMetadata &&
Object.keys(this.#hubMetadata).length >= 1 Object.keys(this.#hubMetadata).length >= 1
) { ) {
/** @type {Record<string, string>} */ /** @type {any} */
const metadata = { type: 'hub' } const metadata = { type: 'hub' }
const { name, admin } = this.#hubMetadata const { name, admin } = this.#hubMetadata
if (name) metadata.name = name if (name) metadata.name = name
if (admin) metadata.admin = admin if (admin) metadata.admin = admin
this.#peer.net.updateInfo(this.#address, metadata) this.#peer.net.updateInfo(this.#multiaddr, metadata)
} }
debug('Announcing myself to hub %s', this.#hubPubkey) debug('Announcing myself to hub %s', this.#hubPubkey)
@ -125,7 +109,7 @@ module.exports = class HubObserver {
// Update onlineCount metadata for this hub // Update onlineCount metadata for this hub
const onlineCount = this.#attendants.size const onlineCount = this.#attendants.size
this.#peer.net.updateInfo(this.#address, { onlineCount }) this.#peer.net.updateInfo(this.#multiaddr, /**@type {any}*/ ({ onlineCount }))
const hubName = this.#hubMetadata?.name const hubName = this.#hubMetadata?.name
if (event.type === 'state') { if (event.type === 'state') {
@ -135,9 +119,9 @@ module.exports = class HubObserver {
} else if (event.type === 'joined') { } else if (event.type === 'joined') {
this.#notifyNewAttendant(event.pubkey, this.#hubPubkey, hubName) this.#notifyNewAttendant(event.pubkey, this.#hubPubkey, hubName)
} else if (event.type === 'left') { } else if (event.type === 'left') {
const address = this.#getAddress(event.pubkey) const multiaddr = this.#getMultiaddr(event.pubkey)
debug('Will disconnect and unstage %s', address) debug('Will disconnect and unstage %s', multiaddr)
this.#peer.net.disconnect(address) this.#peer.net.disconnect(multiaddr)
} }
} }
@ -163,9 +147,10 @@ module.exports = class HubObserver {
#notifyNewAttendant(attendantPubkey, hubPubkey, hubName) { #notifyNewAttendant(attendantPubkey, hubPubkey, hubName) {
if (attendantPubkey === hubPubkey) return if (attendantPubkey === hubPubkey) return
if (attendantPubkey === this.#peer.shse.pubkey) return if (attendantPubkey === this.#peer.shse.pubkey) return
const address = this.#getAddress(attendantPubkey) const multiaddr = this.#getMultiaddr(attendantPubkey)
// @ts-ignore
this.#peer.hubClient._notifyDiscoveredAttendant({ this.#peer.hubClient._notifyDiscoveredAttendant({
address, multiaddr,
attendantPubkey, attendantPubkey,
hubPubkey, hubPubkey,
hubName, hubName,
@ -190,8 +175,8 @@ module.exports = class HubObserver {
/** /**
* @param {string} pubkey * @param {string} pubkey
*/ */
#getAddress(pubkey) { #getMultiaddr(pubkey) {
return `tunnel:${this.#hubPubkey}:${pubkey}~shse:${pubkey}` return `/tunnel/${this.#hubPubkey}.${pubkey}/shse/${pubkey}`
} }
/** /**
@ -208,12 +193,12 @@ module.exports = class HubObserver {
close() { close() {
this.#attendantsDrain?.abort() this.#attendantsDrain?.abort()
for (const pubkey of this.#attendants) { for (const pubkey of this.#attendants) {
const address = this.#getAddress(pubkey) const multiaddr = this.#getMultiaddr(pubkey)
this.#peer.net.forget(address) this.#peer.net.forget(multiaddr)
} }
this.rpc.close(true, (/** @type {any} */ err) => { this.rpc.close(true, (/** @type {any} */ err) => {
if (err) debug('error when closing connection with room: %o', err) if (err) debug('error when closing connection with room: %o', err)
}) })
this.#peer.net.disconnect(this.#address) this.#peer.net.disconnect(this.#multiaddr)
} }
} }

View File

@ -1,4 +1,3 @@
const bs58 = require('bs58')
const debug = require('debug')('ppppp:hub-client') const debug = require('debug')('ppppp:hub-client')
const pull = require('pull-stream') const pull = require('pull-stream')
const run = require('promisify-tuple') const run = require('promisify-tuple')
@ -6,27 +5,13 @@ const HubObserver = require('./hub-observer')
const { muxrpcMissing } = require('./utils') const { muxrpcMissing } = require('./utils')
/** /**
* @typedef {ReturnType<import('ppppp-net').init>} PPPPPNet
* @typedef {Map<string, HubObserver>} Hubs * @typedef {Map<string, HubObserver>} Hubs
*/ */
/**
* @param {string} addresses
* @returns {string | undefined}
*/
function extractSHSEPubkey(addresses) {
for (const address of addresses.split(';')) {
for (const [transport, transform] of address.split('~')) {
const [name, pubkey, extra] = transform.split(':')
if (name === 'shse') {
return pubkey
}
}
}
}
/** /**
* @param {Hubs} hubs * @param {Hubs} hubs
* @param {any} peer * @param {{net: PPPPPNet, shse: {pubkey: string}}} peer
*/ */
const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => { const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
const self = { const self = {
@ -45,12 +30,11 @@ const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
pull( pull(
peer.net.listen(), peer.net.listen(),
pull.filter(({ type }) => type === 'connected'), pull.filter(({ type }) => type === 'connected'),
pull.drain(async ({ address, details }) => { pull.drain(async ({ multiaddr, pubkey, details }) => {
const pubkey = extractSHSEPubkey(address)
if (!pubkey) return if (!pubkey) return
if (hubs.has(pubkey)) return if (hubs.has(pubkey)) return
if (!details?.rpc) return if (!details?.rpc) return
if (address.startsWith('tunnel:')) return if (multiaddr.startsWith('/tunnel/')) return
const rpc = details.rpc const rpc = details.rpc
const [err, res] = await run(rpc.hub.metadata)() const [err, res] = await run(rpc.hub.metadata)()
if (muxrpcMissing(err)) return if (muxrpcMissing(err)) return
@ -63,7 +47,14 @@ const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
hubs.get(pubkey)?.cancel() hubs.get(pubkey)?.cancel()
hubs.delete(pubkey) hubs.delete(pubkey)
} }
const obs = new HubObserver(peer, pubkey, address, res, rpc, onConnect) const obs = new HubObserver(
peer,
pubkey,
multiaddr,
res,
rpc,
onConnect
)
hubs.set(pubkey, obs) hubs.set(pubkey, obs)
}) })
) )
@ -72,8 +63,7 @@ const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
pull( pull(
peer.net.listen(), peer.net.listen(),
pull.filter(({ type }) => type === 'disconnected'), pull.filter(({ type }) => type === 'disconnected'),
pull.drain(({ address }) => { pull.drain(({ pubkey }) => {
const pubkey = extractSHSEPubkey(address)
if (!pubkey) return if (!pubkey) return
if (!hubs.has(pubkey)) return if (!hubs.has(pubkey)) return
hubs.get(pubkey)?.close() hubs.get(pubkey)?.close()
@ -97,7 +87,7 @@ const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
* @param {CallableFunction} cb * @param {CallableFunction} cb
*/ */
async client(address, cb) { async client(address, cb) {
debug(`we wish to connect to %o`, address) debug(`We wish to connect to %o`, address)
const opts = self.parse(address) const opts = self.parse(address)
if (!opts) { if (!opts) {
cb(new Error(`invalid tunnel address ${address}`)) cb(new Error(`invalid tunnel address ${address}`))
@ -121,12 +111,12 @@ const makeTunnelPlugin = (hubs, peer) => (/** @type {any}} */ msConfig) => {
return return
} }
debug(`will call createTunnel with ${target} via hub ${hub}`) debug(`Will call createTunnel with ${target} via hub ${hub}`)
const duplex = hubRPC.hub.createTunnel( const duplex = hubRPC.hub.createTunnel(
target, target,
(/** @type {any} */ err) => { (/** @type {any} */ err) => {
// prettier-ignore // prettier-ignore
if (err) debug('tunnel duplex broken with %o because %s', address, err.message ?? err) if (err) debug('Tunnel duplex broken with %o because %s', address, err.message ?? err)
} }
) )
cb(null, duplex) cb(null, duplex)

View File

@ -3,11 +3,34 @@ const DuplexPair = require('pull-pair/duplex') // @ts-ignore
const Notify = require('pull-notify') const Notify = require('pull-notify')
const debug = require('debug')('ppppp:hub-client') const debug = require('debug')('ppppp:hub-client')
const makeTunnelPlugin = require('./ms-tunnel') const makeTunnelPlugin = require('./ms-tunnel')
const { ErrorDuplex } = require('./utils') const { ErrorDuplex, msaddrToMultiaddr, multiaddrToMsaddr } = require('./utils')
const HUBS_SUBDOMAIN = 'hubs'
/**
* @typedef {ReturnType<import('ppppp-net').init>} PPPPPNet
* @typedef {ReturnType<import('ppppp-set').init>} PPPPPSet
* @typedef {import('ppppp-net').Info} Info
* @typedef {{
* net: PPPPPNet,
* set: PPPPPSet,
* multiserver: {
* transport(transport: any): void
* },
* shse: {
* pubkey: string
* }
* }} Peer
*/
/**
* @template T
* @typedef {(...args: [Error] | [null, T]) => void } CB
*/
module.exports = { module.exports = {
name: 'hubClient', name: 'hubClient',
needs: ['net'], needs: ['shse', 'net', 'set'],
manifest: { manifest: {
connect: 'duplex', connect: 'duplex',
}, },
@ -18,7 +41,7 @@ module.exports = {
}, },
/** /**
* @param {any} peer * @param {Peer} peer
* @param {any} config * @param {any} config
*/ */
init(peer, config) { init(peer, config) {
@ -42,6 +65,47 @@ module.exports = {
}) })
return { return {
/**
* @param {`/${string}`} multiaddr
* @param {CB<void>} cb
*/
addHub(multiaddr, cb) {
peer.set.add(HUBS_SUBDOMAIN, multiaddr, (err, _) => {
// prettier-ignore
if (err) return cb(new Error('Failed to add Hub to my Set feed', {cause: err}))
peer.net.connect(multiaddr, (err, rpc) => {
// prettier-ignore
if (err) return cb(new Error('Failed to connect to Hub after adding it to my Set feed', {cause: err}))
cb(null, void 0)
})
})
},
/**
* @param {number} amount
* @param {CB<Array<string>>} cb
*/
getHubs(amount, cb) {
const source = peer.net.peers()
source(null, (err, peers) => {
if (err === true || !peers) return cb(null, [])
// prettier-ignore
if (err) return cb(new Error('Failed to get hubs', { cause: err }))
// @ts-ignore
const infoMap = /**@type {Map<`/${string}`, Info>}*/ (new Map(peers))
const multiaddrs = peer.set.values(HUBS_SUBDOMAIN)
const hubs = []
for (const multiaddr of multiaddrs) {
const stats = infoMap.get(multiaddr)?.stats ?? { failure: 1 }
hubs.push({ multiaddr, stats })
}
hubs.sort((a, b) => (a.stats.failure ?? 1) - (b.stats.failure ?? 1))
hubs.splice(amount)
const returnable = hubs.map((h) => h.multiaddr)
cb(null, returnable)
})
},
/** /**
* @param {string} origin * @param {string} origin
* @returns {import('pull-stream').Duplex<unknown, unknown>} * @returns {import('pull-stream').Duplex<unknown, unknown>}
@ -61,11 +125,6 @@ module.exports = {
} }
}, },
// Needed due to https://github.com/ssb-ngi-pointer/ssb-room-client/pull/3#issuecomment-808322434
ping() {
return Date.now()
},
// Internal method, needed for api-plugin.ts // Internal method, needed for api-plugin.ts
getHubsMap() { getHubsMap() {
return hubs return hubs

View File

@ -23,8 +23,10 @@
"node": ">=16" "node": ">=16"
}, },
"dependencies": { "dependencies": {
"@types/ip": "1.1.3",
"bs58": "^5.0.0", "bs58": "^5.0.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ip": "1.1.8",
"promisify-tuple": "~1.2.0", "promisify-tuple": "~1.2.0",
"pull-notify": "~0.1.2", "pull-notify": "~0.1.2",
"pull-pair": "~1.1.0", "pull-pair": "~1.1.0",
@ -37,6 +39,8 @@
"@types/pull-stream": "^3.6.2", "@types/pull-stream": "^3.6.2",
"c8": "7", "c8": "7",
"husky": "^4.3.0", "husky": "^4.3.0",
"ppppp-net": "github:staltz/ppppp-net",
"ppppp-set": "github:staltz/ppppp-set",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"typescript": "^5.1.3" "typescript": "^5.1.3"