Skip to content
This repository has been archived by the owner on Apr 24, 2023. It is now read-only.

fix: update export type #479

Merged
merged 1 commit into from
Oct 13, 2022
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
14 changes: 7 additions & 7 deletions packages/webrtc-star-transport/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ import wrtc from 'wrtc'
import electronWebRTC from 'electron-webrtc'

// Using wrtc in node
const transport = webRTCStar({ wrtc })
const star = webRTCStar({ wrtc })

// Using electron-webrtc in electron
const transport = webRTCStar({ wrtc: electronWebRTC() })
const star = webRTCStar({ wrtc: electronWebRTC() })

const node = await createLibp2pNode({
addresses: {
Expand All @@ -64,10 +64,10 @@ const node = await createLibp2pNode({
]
},
transports: [
transport
star.transport
],
peerDiscovery: [
transport.discovery
star.discovery
]
})
await node.start()
Expand All @@ -81,7 +81,7 @@ await node.dial('/ip4/188.166.203.82/tcp/20000/wss/p2p-webrtc-star/p2p/QmcgpsyWg
import { createLibp2pNode } from 'libp2p'
import { webRTCStar } from '@libp2p/webrtc-star'

const transport = webRTCStar()
const star = webRTCStar()

const node = await createLibp2pNode({
addresses: {
Expand All @@ -90,10 +90,10 @@ const node = await createLibp2pNode({
]
},
transports: [
transport
star.transport
],
peerDiscovery: [
transport.discovery
star.discovery
]
})
await node.start()
Expand Down
306 changes: 14 additions & 292 deletions packages/webrtc-star-transport/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,298 +1,20 @@
import { logger } from '@libp2p/logger'
import errcode from 'err-code'
import { AbortError } from 'abortable-iterator'
import type { Multiaddr } from '@multiformats/multiaddr'
import { multiaddr } from '@multiformats/multiaddr'
import * as mafmt from '@multiformats/mafmt'
import { CODE_CIRCUIT } from './constants.js'
import { createListener } from './listener.js'
import { toMultiaddrConnection } from './socket-to-conn.js'
import { cleanMultiaddr, cleanUrlSIO } from './utils.js'
import { WebRTCInitiator } from '@libp2p/webrtc-peer'
import randomBytes from 'iso-random-stream/src/random.js'
import { toString as uint8ArrayToString } from 'uint8arrays'
import { EventEmitter, CustomEvent } from '@libp2p/interfaces/events'
import type { Startable } from '@libp2p/interfaces/startable'
import { peerIdFromString } from '@libp2p/peer-id'
import { symbol } from '@libp2p/interface-transport'
import type { WRTC, WebRTCInitiatorInit, WebRTCReceiver, WebRTCReceiverInit } from '@libp2p/webrtc-peer'
import type { Connection, MultiaddrConnection } from '@libp2p/interface-connection'
import type { Transport, Listener, DialOptions, CreateListenerOptions } from '@libp2p/interface-transport'
import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interface-peer-discovery'
import type { WebRTCStarSocket, HandshakeSignal } from '@libp2p/webrtc-star-protocol'
import { symbol as peerDiscoverySymbol } from '@libp2p/interface-peer-discovery'
import type { PeerId } from '@libp2p/interface-peer-id'
import type { PeerDiscovery } from '@libp2p/interface-peer-discovery'
import type { Transport } from '@libp2p/interface-transport'
import { WebRTCStar, WebRTCStarComponents, WebRTCStarInit } from './transport.js'

const webrtcSupport = 'RTCPeerConnection' in globalThis
const log = logger('libp2p:webrtc-star')

const noop = () => {}

class WebRTCStarDiscovery extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable {
private started = false

get [peerDiscoverySymbol] (): true {
return true
}

get [Symbol.toStringTag] () {
return '@libp2p/webrtc-star-discovery'
}

isStarted () {
return this.started
}

async start () {
this.started = true
}

async stop () {
this.started = false
}

dispatchEvent (event: CustomEvent) {
if (!this.isStarted()) {
return false
}

return super.dispatchEvent(event)
}
}

export interface WebRTCStarInit {
wrtc?: WRTC
}

export interface WebRTCStarDialOptions extends DialOptions {
channelOptions?: WebRTCInitiatorInit
export interface WebRTCStarTuple {
transport: (components: WebRTCStarComponents) => Transport
discovery: (components?: WebRTCStarComponents) => PeerDiscovery
}

export interface WebRTCStarListenerOptions extends CreateListenerOptions, WebRTCInitiatorInit {
channelOptions?: WebRTCReceiverInit
}

export interface SignalServerServerEvents {
'error': CustomEvent<Error>
'listening': CustomEvent
'peer': CustomEvent<string>
'connection': CustomEvent<Connection>
'disconnect': CustomEvent
'reconnect': CustomEvent
}

export interface SignalServer extends EventEmitter<SignalServerServerEvents> {
signallingAddr: Multiaddr
socket: WebRTCStarSocket
connections: MultiaddrConnection[]
channels: Map<string, WebRTCReceiver>
pendingSignals: Map<string, HandshakeSignal[]>
close: () => Promise<void>
}

export interface WebRTCStarComponents {
peerId: PeerId
}

/**
* @class WebRTCStar
*/
export class WebRTCStar implements Transport {
public wrtc?: WRTC
public discovery: () => PeerDiscovery & Startable
public sigServers: Map<string, SignalServer>
private readonly components: WebRTCStarComponents
private readonly _discovery: WebRTCStarDiscovery

constructor (components: WebRTCStarComponents, init?: WebRTCStarInit) {
if (init?.wrtc != null) {
this.wrtc = init.wrtc
}

this.components = components
export function webRTCStar (init: WebRTCStarInit = {}): WebRTCStarTuple {
const transport = new WebRTCStar(init)

// Keep Signalling references
this.sigServers = new Map()

// Discovery
this._discovery = new WebRTCStarDiscovery()
this.discovery = () => this._discovery
this.peerDiscovered = this.peerDiscovered.bind(this)
}

get [symbol] (): true {
return true
}

get [Symbol.toStringTag] () {
return '@libp2p/webrtc-star'
return {
transport: (components: WebRTCStarComponents) => {
transport.peerId = components.peerId
return transport
},
discovery: transport.discovery
}

async dial (ma: Multiaddr, options: WebRTCStarDialOptions) {
const rawConn = await this._connect(ma, options)
const maConn = toMultiaddrConnection(rawConn, { remoteAddr: ma, signal: options.signal })
log('new outbound connection %s', maConn.remoteAddr)
const conn = await options.upgrader.upgradeOutbound(maConn)
log('outbound connection %s upgraded', maConn.remoteAddr)
return conn
}

async _connect (ma: Multiaddr, options: WebRTCStarDialOptions) {
if (options.signal?.aborted === true) {
throw new AbortError()
}

const channelOptions = {
...(options.channelOptions ?? {})
}

// Use custom WebRTC implementation
if (this.wrtc != null) {
channelOptions.wrtc = this.wrtc
}

const cOpts = ma.toOptions()
const intentId = uint8ArrayToString(randomBytes(36), 'hex')

return await new Promise<WebRTCInitiator>((resolve, reject) => {
const sio = this.sigServers.get(cleanUrlSIO(ma))

if (sio?.socket == null) {
return reject(errcode(new Error('unknown signal server to use'), 'ERR_UNKNOWN_SIGNAL_SERVER'))
}

let connected: boolean = false

log('dialing %s:%s', cOpts.host, cOpts.port)
const channel = new WebRTCInitiator(channelOptions)

const onError = (evt: CustomEvent<Error>) => {
const err = evt.detail

if (!connected) {
const msg = `connection error ${cOpts.host}:${cOpts.port}: ${err.message}`
log.error(msg)
done(err)
}
}

const onReady = () => {
connected = true

log('connection opened %s:%s', cOpts.host, cOpts.port)
done()
}

const onAbort = () => {
log.error('connection aborted %s:%s', cOpts.host, cOpts.port)
channel.close().finally(() => {
done(new AbortError())
})
}

const done = (err?: Error) => {
channel.removeEventListener('ready', onReady)
options.signal?.removeEventListener('abort', onAbort)

if (err == null) {
resolve(channel)
} else {
reject(err)
}
}

channel.addEventListener('ready', onReady, {
once: true
})
channel.addEventListener('close', () => {
channel.removeEventListener('error', onError)
})
options.signal?.addEventListener('abort', onAbort)

channel.addEventListener('signal', (evt) => {
const signal = evt.detail

sio.socket.emit('ss-handshake', {
intentId: intentId,
srcMultiaddr: sio.signallingAddr.toString(),
dstMultiaddr: ma.toString(),
signal: signal
})
})

sio.socket.on('ws-handshake', (offer) => {
if (offer.intentId === intentId && offer.err != null) {
channel.close().finally(() => {
reject(errcode(new Error(offer.err), 'ERR_SIGNALLING_FAILED'))
})
}

if (offer.intentId !== intentId || offer.answer == null || channel.closed) {
return
}

channel.handleSignal(offer.signal)
})
})
}

/**
* Creates a WebrtcStar listener. The provided `handler` function will be called
* anytime a new incoming Connection has been successfully upgraded via
* `upgrader.upgradeInbound`.
*/
createListener (options: WebRTCStarListenerOptions): Listener {
if (!webrtcSupport && this.wrtc == null) {
throw errcode(new Error('no WebRTC support'), 'ERR_NO_WEBRTC_SUPPORT')
}

options.channelOptions = options.channelOptions ?? {}

if (this.wrtc != null) {
options.channelOptions.wrtc = this.wrtc
}

return createListener(options.upgrader, options.handler ?? noop, this.components.peerId, this, options)
}

/**
* Takes a list of `Multiaddr`s and returns only valid TCP addresses
*/
filter (multiaddrs: Multiaddr[]) {
multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]

return multiaddrs.filter((ma) => {
if (ma.protoCodes().includes(CODE_CIRCUIT)) {
return false
}

return mafmt.WebRTCStar.matches(ma)
})
}

peerDiscovered (maStr: string) {
log('peer discovered: %s', maStr)
maStr = cleanMultiaddr(maStr)

const ma = multiaddr(maStr)
const peerIdStr = ma.getPeerId()

if (peerIdStr == null) {
return
}

const peerId = peerIdFromString(peerIdStr)

this._discovery.dispatchEvent(new CustomEvent('peer', {
detail: {
id: peerId,
multiaddrs: [ma],
protocols: []
}
}))
}
}

export function webRTCStar (init: WebRTCStarInit = {}): (components: WebRTCStarComponents) => WebRTCStar {
return (components: WebRTCStarComponents) => new WebRTCStar(components, init)
}
2 changes: 1 addition & 1 deletion packages/webrtc-star-transport/src/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { PeerId } from '@libp2p/interface-peer-id'
import type { Multiaddr } from '@multiformats/multiaddr'
import type { MultiaddrConnection } from '@libp2p/interface-connection'
import type { Upgrader, ConnectionHandler, Listener, ListenerEvents } from '@libp2p/interface-transport'
import type { WebRTCStar, WebRTCStarListenerOptions, SignalServer, SignalServerServerEvents } from './index.js'
import type { WebRTCStar, WebRTCStarListenerOptions, SignalServer, SignalServerServerEvents } from './transport.js'
import type { WebRTCReceiverInit } from '@libp2p/webrtc-peer'
import type { WebRTCStarSocket, HandshakeSignal } from '@libp2p/webrtc-star-protocol'
import { EventEmitter, CustomEvent } from '@libp2p/interfaces/events'
Expand Down
Loading