Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow access to UPnP client from types #2449

Merged
merged 3 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions packages/upnp-nat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
* ```
*/

import { UPnPNAT } from './upnp-nat.js'
import { UPnPNAT as UPnPNATClass, type NatAPI, type MapPortOptions } from './upnp-nat.js'
import type { ComponentLogger, NodeInfo, PeerId } from '@libp2p/interface'
import type { AddressManager, TransportManager } from '@libp2p/interface-internal'

export type { NatAPI, MapPortOptions }

export interface PMPOptions {
/**
* Whether to enable PMP as well as UPnP
Expand Down Expand Up @@ -86,8 +88,12 @@ export interface UPnPNATComponents {
addressManager: AddressManager
}

export function uPnPNAT (init: UPnPNATInit = {}): (components: UPnPNATComponents) => unknown {
export interface UPnPNAT {
client: NatAPI
}

export function uPnPNAT (init: UPnPNATInit = {}): (components: UPnPNATComponents) => UPnPNAT {
return (components: UPnPNATComponents) => {
return new UPnPNAT(components, init)
return new UPnPNATClass(components, init)
}
}
38 changes: 15 additions & 23 deletions packages/upnp-nat/src/upnp-nat.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { upnpNat, type NatAPI } from '@achingbrain/nat-port-mapper'
import { upnpNat, type NatAPI, type MapPortOptions } from '@achingbrain/nat-port-mapper'
import { CodeError, ERR_INVALID_PARAMETERS } from '@libp2p/interface'
import { isLoopback } from '@libp2p/utils/multiaddr/is-loopback'
import { isPrivateIp } from '@libp2p/utils/private-ip'
import { fromNodeAddress } from '@multiformats/multiaddr'
import { isBrowser } from 'wherearewe'
import type { UPnPNATComponents, UPnPNATInit } from './index.js'
import type { UPnPNATComponents, UPnPNATInit, UPnPNAT as UPnPNATInterface } from './index.js'
import type { Logger, Startable } from '@libp2p/interface'

const DEFAULT_TTL = 7200

export type { NatAPI, MapPortOptions }

function highPort (min = 1024, max = 65535): number {
return Math.floor(Math.random() * (max - min + 1) + min)
}

export class UPnPNAT implements Startable {
export class UPnPNAT implements Startable, UPnPNATInterface {
public client: NatAPI
private readonly components: UPnPNATComponents
private readonly externalAddress?: string
private readonly localAddress?: string
Expand All @@ -22,7 +25,6 @@ export class UPnPNAT implements Startable {
private readonly keepAlive: boolean
private readonly gateway?: string
private started: boolean
private client?: NatAPI
private readonly log: Logger

constructor (components: UPnPNATComponents, init: UPnPNATInit) {
Expand All @@ -40,6 +42,13 @@ export class UPnPNAT implements Startable {
if (this.ttl < DEFAULT_TTL) {
throw new CodeError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`, ERR_INVALID_PARAMETERS)
}

this.client = upnpNat({
description: this.description,
ttl: this.ttl,
keepAlive: this.keepAlive,
gateway: this.gateway
})
}

isStarted (): boolean {
Expand Down Expand Up @@ -93,8 +102,7 @@ export class UPnPNAT implements Startable {
continue
}

const client = this._getClient()
const publicIp = this.externalAddress ?? await client.externalIp()
const publicIp = this.externalAddress ?? await this.client.externalIp()
const isPrivate = isPrivateIp(publicIp)

if (isPrivate === true) {
Expand All @@ -109,7 +117,7 @@ export class UPnPNAT implements Startable {

this.log(`opening uPnP connection from ${publicIp}:${publicPort} to ${host}:${port}`)

await client.map({
await this.client.map({
publicPort,
localPort: port,
localAddress: this.localAddress,
Expand All @@ -124,21 +132,6 @@ export class UPnPNAT implements Startable {
}
}

_getClient (): NatAPI {
if (this.client != null) {
return this.client
}

this.client = upnpNat({
description: this.description,
ttl: this.ttl,
keepAlive: this.keepAlive,
gateway: this.gateway
})

return this.client
}

/**
* Stops the NAT manager
*/
Expand All @@ -149,7 +142,6 @@ export class UPnPNAT implements Startable {

try {
await this.client.close()
this.client = undefined
} catch (err: any) {
this.log.error(err)
}
Expand Down
4 changes: 1 addition & 3 deletions packages/upnp-nat/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ describe('UPnP NAT (TCP)', () => {

client = stubInterface<NatAPI>()

natManager._getClient = () => {
return client
}
natManager.client = client

teardown.push(async () => {
await stop(natManager)
Expand Down
Loading