Skip to content

Commit

Permalink
feat: allow access to UPnP client from types (#2449)
Browse files Browse the repository at this point in the history
Exports types to access the upnp-nat client. This is the smallest change to access the openPorts map.

```
console.log(libp2p.services.upnp.client.openPorts)
```

---------

Co-authored-by: Michael Cole <gitlab@michaelcole.com>
Co-authored-by: Alex Potsides <alex@achingbrain.net>
  • Loading branch information
3 people authored Jun 6, 2024
1 parent 4bd8e4f commit f6fe2cc
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 29 deletions.
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

0 comments on commit f6fe2cc

Please sign in to comment.