use multiaddr from updated ppppp-net
This commit is contained in:
parent
c62e7fc3bf
commit
ff9971389e
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue