forked from libp2p/js-libp2p
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Add scaffolding for WebRTC signalling plugin * Create a signalling stream when a peer connects to primary relay * Negotiate WebRTC connections between peers over signalling stream * Stop listener on disconnecting from primary relay node * Filter out circuit addresses * Forward signalling messages over a pubsub topic if required * Update todos * Fix lint errors * Update dependencies * Update package version
- Loading branch information
1 parent
f2d9a5d
commit f2111a1
Showing
15 changed files
with
895 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Time to wait for a connection to close gracefully before destroying it manually | ||
export const CLOSE_TIMEOUT = 2000 | ||
|
||
// Use a supported protocol id in multiaddr to listen through signalling stream | ||
// Need to use one of the supported protocol names (list: https://github.com/multiformats/multiaddr/blob/master/protocols.csv) for the multiaddr to be valid | ||
export const P2P_WEBRTC_STAR_ID = 'p2p-webrtc-star' | ||
|
||
// Pubsub topic over which signalling nodes forward the signalling messages if not connected to the destination | ||
export const WEBRTC_SIGNAL_TOPIC = 'webrtc-signal' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { logger } from '@libp2p/logger' | ||
import type { PeerId } from '@libp2p/interface-peer-id' | ||
import type { PeerStore, PeerProtocolsChangeData } from '@libp2p/interface-peer-store' | ||
import type { Connection } from '@libp2p/interface-connection' | ||
import type { ConnectionManager } from '@libp2p/interface-connection-manager' | ||
import type { TransportManager } from '@libp2p/interface-transport' | ||
|
||
import { WEBRTC_SIGNAL_CODEC } from './multicodec.js' | ||
import { P2P_WEBRTC_STAR_ID } from './constants.js' | ||
|
||
const log = logger('libp2p:webrtc-signal:auto-signal') | ||
|
||
export interface WebRTCSignalConfig { | ||
enabled: boolean | ||
isSignallingNode: boolean | ||
autoSignal: AutoSignalConfig | ||
} | ||
|
||
export interface AutoSignalConfig { | ||
enabled: boolean | ||
relayPeerId: string | ||
} | ||
|
||
export interface SignalComponents { | ||
peerStore: PeerStore | ||
connectionManager: ConnectionManager | ||
transportManager: TransportManager | ||
} | ||
|
||
export class AutoSignal { | ||
private readonly components: SignalComponents | ||
private readonly relayPeerId: string | ||
private isListening: boolean = false | ||
// TODO Done in circuit-relay implementation, required here? | ||
// private readonly onError: (error: Error, msg?: string) => void | ||
|
||
constructor (components: SignalComponents, init: AutoSignalConfig) { | ||
this.components = components | ||
this.relayPeerId = init.relayPeerId | ||
|
||
this._onProtocolChange = this._onProtocolChange.bind(this) | ||
this._onPeerConnected = this._onPeerConnected.bind(this) | ||
this._onPeerDisconnected = this._onPeerDisconnected.bind(this) | ||
|
||
this.components.peerStore.addEventListener('change:protocols', (evt) => { | ||
void this._onProtocolChange(evt).catch(err => { | ||
log.error(err) | ||
}) | ||
}) | ||
|
||
this.components.connectionManager.addEventListener('peer:connect', (evt) => { | ||
void this._onPeerConnected(evt).catch(err => { | ||
log.error(err) | ||
}) | ||
}) | ||
|
||
this.components.connectionManager.addEventListener('peer:disconnect', (evt) => this._onPeerDisconnected(evt)) | ||
} | ||
|
||
async _onProtocolChange (evt: CustomEvent<PeerProtocolsChangeData>) { | ||
const { | ||
peerId, | ||
protocols | ||
} = evt.detail | ||
|
||
await this._handleProtocols(peerId, protocols) | ||
} | ||
|
||
async _onPeerConnected (evt: CustomEvent<Connection>) { | ||
const connection = evt.detail | ||
const peerId = connection.remotePeer | ||
const protocols = await this.components.peerStore.protoBook.get(peerId) | ||
|
||
// Handle protocols on peer connection as change:protocols event is not triggered after reconnection between peers. | ||
await this._handleProtocols(peerId, protocols) | ||
} | ||
|
||
_onPeerDisconnected (evt: CustomEvent<Connection>) { | ||
const connection = evt.detail | ||
|
||
if (connection.remotePeer.toString() === this.relayPeerId.toString()) { | ||
this.isListening = false | ||
} | ||
} | ||
|
||
async _handleProtocols (peerId: PeerId, protocols: string[]) { | ||
// Ignore if we are already listening or it's not the primary relay node | ||
if (this.isListening || peerId.toString() !== this.relayPeerId) { | ||
return | ||
} | ||
|
||
// Check if it has the protocol | ||
const hasProtocol = protocols.find(protocol => protocol === WEBRTC_SIGNAL_CODEC) | ||
|
||
// Ignore if protocol is not supported | ||
if (hasProtocol == null) { | ||
return | ||
} | ||
|
||
// If required protocol is supported, start the listener | ||
const connections = this.components.connectionManager.getConnections(peerId) | ||
if (connections.length === 0) { | ||
return | ||
} | ||
|
||
const connection = connections[0] | ||
|
||
// TODO Done in circuit-relay implementation, required here? | ||
// await this.components.peerStore.metadataBook.setValue(peerId, HOP_METADATA_KEY, uint8ArrayFromString(HOP_METADATA_VALUE)) | ||
|
||
await this._addListener(connection) | ||
} | ||
|
||
/** | ||
* Attempt to listen on the given connection with relay node | ||
*/ | ||
async _addListener (connection: Connection): Promise<void> { | ||
try { | ||
const remoteAddr = connection.remoteAddr | ||
|
||
// Attempt to listen on relay | ||
const multiaddr = remoteAddr.encapsulate(`/${P2P_WEBRTC_STAR_ID}`) | ||
|
||
// Announce multiaddr will update on listen success by TransportManager event being triggered | ||
await this.components.transportManager.listen([multiaddr]) | ||
this.isListening = true | ||
} catch (err: any) { | ||
log.error('error listening on signalling address', err) | ||
this.isListening = false | ||
throw err | ||
} | ||
} | ||
} |
Oops, something went wrong.