Skip to content

Commit

Permalink
fix: update autonat and upnp-nat services to match fetch etc (#1729)
Browse files Browse the repository at this point in the history
Refactors exports for autonat and upnp-nat to be consistent with
other services - fetch, ping, identify, etc.

---------

Co-authored-by: Chad Nehemiah <chad.nehemiah94@gmail.com>
  • Loading branch information
achingbrain and maschad authored May 5, 2023
1 parent 947639f commit 2c3b64a
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 42 deletions.
14 changes: 14 additions & 0 deletions doc/migrations/v0.44-v0.45.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ const node = createLibp2p({
fetch: {
/** fetch options **/
},
nat: {
/** UPnP NAT options **/
},
autonat: {
/** AutoNAT options **/
},
pubsub: gossipSub(),
dht: kadDHT(),
relay: circuitRelayServer()
Expand All @@ -52,10 +58,12 @@ const node = createLibp2p({

```js
import { createLibp2p } from 'libp2p'
import { autonatService } from 'libp2p/autonat'
import { circuitRelayServer } from 'libp2p/circuit-relay'
import { identifyService } from 'libp2p/identify'
import { pingService } from 'libp2p/ping'
import { fetchService } from 'libp2p/fetch'
import { uPnPNATService } from 'libp2p/upnp-nat'
import { kadDHT } from '@libp2p/kad-dht'
import { gossipSub } from '@ChainSafe/libp2p-gossipsub'

Expand All @@ -71,6 +79,12 @@ const node = createLibp2p({
fetch: fetchService({
/** fetch options **/
}),
uPnPNAT: uPnPNATService({
/** UPnP NAT options **/
}),
autonat: autonatService({
/** AutoNAT options **/
}),
pubsub: gossipSub(),
dht: kadDHT(),
relay: circuitRelayServer()
Expand Down
19 changes: 17 additions & 2 deletions src/autonat/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
/**
* The prefix to use in the protocol
*/
export const PROTOCOL_PREFIX = 'libp2p'

export const PROTOCOL = '/libp2p/autonat/1.0.0'
export const PROTOCOL_VERSION = '1.0.0'
/**
* The name to use in the protocol
*/
export const PROTOCOL_NAME = 'autonat'

/**
* The version to use in the protocol
*/
export const PROTOCOL_VERSION = '1.0.0'
export const TIMEOUT = 30000
export const STARTUP_DELAY = 5000
export const REFRESH_INTERVAL = 60000
export const MAX_INBOUND_STREAMS = 1
export const MAX_OUTBOUND_STREAMS = 1
67 changes: 37 additions & 30 deletions src/autonat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import parallel from 'it-parallel'
import { pipe } from 'it-pipe'
import isPrivateIp from 'private-ip'
import {
PROTOCOL
MAX_INBOUND_STREAMS,
MAX_OUTBOUND_STREAMS,
PROTOCOL_NAME, PROTOCOL_PREFIX, PROTOCOL_VERSION, REFRESH_INTERVAL, STARTUP_DELAY, TIMEOUT
} from './constants.js'
import { Message } from './pb/index.js'
import { anySignal } from 'any-signal'
Expand All @@ -32,45 +34,39 @@ const log = logger('libp2p:autonat')
// https://github.com/libp2p/specs/blob/master/autonat/README.md#autonat-protocol
const REQUIRED_SUCCESSFUL_DIALS = 4

// Wait this long before we start to query autonat nodes
const AUTONAT_STARTUP_DELAY = 5000

// Only try to verify our external address this often
const AUTONAT_REFRESH_INTERVAL = 60000

export interface AutonatServiceInit {
/**
* Allows overriding the protocol prefix used
*/
protocolPrefix: string
protocolPrefix?: string

/**
* How long we should wait for a remote peer to verify our external address
*/
timeout: number
timeout?: number

/**
* How long to wait after startup before trying to verify our external address
*/
startupDelay: number
startupDelay?: number

/**
* Verify our external addresses this often
*/
refreshInterval: number
refreshInterval?: number

/**
* How many parallel inbound autonat streams we allow per-connection
*/
maxInboundStreams: number
maxInboundStreams?: number

/**
* How many parallel outbound autonat streams we allow per-connection
*/
maxOutboundStreams: number
maxOutboundStreams?: number
}

export interface DefaultAutonatComponents {
export interface AutonatComponents {
registrar: Registrar
addressManager: AddressManager
transportManager: TransportManager
Expand All @@ -79,21 +75,26 @@ export interface DefaultAutonatComponents {
peerRouting: PeerRouting
}

export class AutonatService implements Startable {
private readonly components: DefaultAutonatComponents
private readonly _init: AutonatServiceInit
class DefaultAutonatService implements Startable {
private readonly components: AutonatComponents
private readonly startupDelay: number
private readonly refreshInterval: number
private readonly protocol: string
private readonly timeout: number
private readonly maxInboundStreams: number
private readonly maxOutboundStreams: number
private verifyAddressTimeout?: ReturnType<typeof setTimeout>
private started: boolean

constructor (components: DefaultAutonatComponents, init: AutonatServiceInit) {
constructor (components: AutonatComponents, init: AutonatServiceInit) {
this.components = components
this.started = false
this._init = init
this.startupDelay = init.startupDelay ?? AUTONAT_STARTUP_DELAY
this.refreshInterval = init.refreshInterval ?? AUTONAT_REFRESH_INTERVAL

this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`
this.timeout = init.timeout ?? TIMEOUT
this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS
this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS
this.startupDelay = init.startupDelay ?? STARTUP_DELAY
this.refreshInterval = init.refreshInterval ?? REFRESH_INTERVAL
this._verifyExternalAddresses = this._verifyExternalAddresses.bind(this)
}

Expand All @@ -106,14 +107,14 @@ export class AutonatService implements Startable {
return
}

await this.components.registrar.handle(PROTOCOL, (data) => {
await this.components.registrar.handle(this.protocol, (data) => {
void this.handleIncomingAutonatStream(data)
.catch(err => {
log.error(err)
})
}, {
maxInboundStreams: this._init.maxInboundStreams,
maxOutboundStreams: this._init.maxOutboundStreams
maxInboundStreams: this.maxInboundStreams,
maxOutboundStreams: this.maxOutboundStreams
})

this.verifyAddressTimeout = setTimeout(this._verifyExternalAddresses, this.startupDelay)
Expand All @@ -122,7 +123,7 @@ export class AutonatService implements Startable {
}

async stop (): Promise<void> {
await this.components.registrar.unhandle(PROTOCOL)
await this.components.registrar.unhandle(this.protocol)
clearTimeout(this.verifyAddressTimeout)

this.started = false
Expand All @@ -132,7 +133,7 @@ export class AutonatService implements Startable {
* Handle an incoming autonat request
*/
async handleIncomingAutonatStream (data: IncomingStreamData): Promise<void> {
const signal = anySignal([AbortSignal.timeout(this._init.timeout)])
const signal = anySignal([AbortSignal.timeout(this.timeout)])

// this controller may be used while dialing lots of peers so prevent MaxListenersExceededWarning
// appearing in the console
Expand Down Expand Up @@ -403,7 +404,7 @@ export class AutonatService implements Startable {
return
}

const signal = AbortSignal.timeout(this._init.timeout)
const signal = AbortSignal.timeout(this.timeout)

// this controller may be used while dialing lots of peers so prevent MaxListenersExceededWarning
// appearing in the console
Expand Down Expand Up @@ -433,15 +434,15 @@ export class AutonatService implements Startable {
const results: Record<string, { success: number, failure: number }> = {}
const networkSegments: string[] = []

async function verifyAddress (peer: PeerInfo): Promise<Message.DialResponse | undefined> {
const verifyAddress = async (peer: PeerInfo): Promise<Message.DialResponse | undefined> => {
try {
log('Asking %p to verify multiaddr', peer.id)

const connection = await self.components.connectionManager.openConnection(peer.id, {
signal
})

const stream = await connection.newStream(PROTOCOL, {
const stream = await connection.newStream(this.protocol, {
signal
})
const source = abortableDuplex(stream, signal)
Expand Down Expand Up @@ -563,3 +564,9 @@ export class AutonatService implements Startable {
}
}
}

export function autonatService (init: AutonatServiceInit = {}): (components: AutonatComponents) => {} {
return (components) => {
return new DefaultAutonatService(components, init)
}
}
4 changes: 2 additions & 2 deletions src/upnp-nat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface UPnPNATInit {
/**
* Whether to automatically refresh UPnP port mappings when their TTL is reached
*/
keepAlive: boolean
keepAlive?: boolean

/**
* Pass a value to use instead of auto-detection
Expand Down Expand Up @@ -205,7 +205,7 @@ class UPnPNAT implements Startable {
}
}

export function uPnPNAT (init: UPnPNATInit): (components: UPnPNATComponents) => {} {
export function uPnPNATService (init: UPnPNATInit = {}): (components: UPnPNATComponents) => {} {
return (components: UPnPNATComponents) => {
return new UPnPNAT(components, init)
}
Expand Down
10 changes: 5 additions & 5 deletions test/autonat/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { expect } from 'aegir/chai'
import sinon from 'sinon'
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
import { start, stop } from '@libp2p/interfaces/startable'
import { AutonatService, AutonatServiceInit } from '../../src/autonat/index.js'
import { autonatService, AutonatServiceInit } from '../../src/autonat/index.js'
import { StubbedInstance, stubInterface } from 'sinon-ts'
import type { PeerRouting } from '@libp2p/interface-peer-routing'
import { Multiaddr, multiaddr } from '@multiformats/multiaddr'
import type { Registrar } from '@libp2p/interface-registrar'
import type { AddressManager } from '@libp2p/interface-address-manager'
import type { Connection, Stream } from '@libp2p/interface-connection'
import { PROTOCOL } from '../../src/autonat/constants.js'
import { PROTOCOL_NAME, PROTOCOL_PREFIX, PROTOCOL_VERSION } from '../../src/autonat/constants.js'
import { Message } from '../../src/autonat/pb/index.js'
import type { PeerId } from '@libp2p/interface-peer-id'
import { pushable } from 'it-pushable'
Expand All @@ -36,7 +36,7 @@ const defaultInit: AutonatServiceInit = {
}

describe('autonat', () => {
let service: AutonatService
let service: any
let components: Components
let peerRouting: StubbedInstance<PeerRouting>
let registrar: StubbedInstance<Registrar>
Expand Down Expand Up @@ -65,7 +65,7 @@ describe('autonat', () => {
peerStore
})

service = new AutonatService(components, defaultInit)
service = autonatService(defaultInit)(components)

await start(components)
await start(service)
Expand Down Expand Up @@ -94,7 +94,7 @@ describe('autonat', () => {

// stub autonat protocol stream
const stream = stubInterface<Stream>()
connection.newStream.withArgs(PROTOCOL).resolves(stream)
connection.newStream.withArgs(`/${PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`).resolves(stream)

// stub autonat response
const response = Message.encode({
Expand Down
6 changes: 3 additions & 3 deletions test/upnp-nat/upnp-nat.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DefaultTransportManager } from '../../src/transport-manager.js'
import { FaultTolerance } from '@libp2p/interface-transport'
import { tcp } from '@libp2p/tcp'
import { mockUpgrader } from '@libp2p/interface-mocks'
import { uPnPNAT } from '../../src/upnp-nat/index.js'
import { uPnPNATService } from '../../src/upnp-nat/index.js'
import Peers from '../fixtures/peers.js'
import { codes } from '../../src/errors.js'
import { createFromJSON } from '@libp2p/peer-id-factory'
Expand Down Expand Up @@ -51,7 +51,7 @@ describe('UPnP NAT (TCP)', () => {
faultTolerance: FaultTolerance.NO_FATAL
})

const natManager: any = uPnPNAT({
const natManager: any = uPnPNATService({
keepAlive: true,
...natManagerOptions
})(components)
Expand Down Expand Up @@ -229,7 +229,7 @@ describe('UPnP NAT (TCP)', () => {
const peerId = await createFromJSON(Peers[0])

expect(() => {
uPnPNAT({ ttl: 5, keepAlive: true })(defaultComponents({ peerId }))
uPnPNATService({ ttl: 5, keepAlive: true })(defaultComponents({ peerId }))
}).to.throw().with.property('code', codes.ERR_INVALID_PARAMETERS)
})
})

0 comments on commit 2c3b64a

Please sign in to comment.