@libp2p/webrtc 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/index.min.js +19 -19
  2. package/dist/src/index.d.ts +5 -2
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +8 -3
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/muxer.d.ts +6 -10
  7. package/dist/src/muxer.d.ts.map +1 -1
  8. package/dist/src/muxer.js +44 -13
  9. package/dist/src/muxer.js.map +1 -1
  10. package/dist/src/peer_transport/handler.d.ts +14 -0
  11. package/dist/src/peer_transport/handler.d.ts.map +1 -0
  12. package/dist/src/peer_transport/handler.js +107 -0
  13. package/dist/src/peer_transport/handler.js.map +1 -0
  14. package/dist/src/peer_transport/listener.d.ts +19 -0
  15. package/dist/src/peer_transport/listener.d.ts.map +1 -0
  16. package/dist/src/peer_transport/listener.js +32 -0
  17. package/dist/src/peer_transport/listener.js.map +1 -0
  18. package/dist/src/peer_transport/pb/index.d.ts +20 -0
  19. package/dist/src/peer_transport/pb/index.d.ts.map +1 -0
  20. package/dist/src/peer_transport/pb/index.js +73 -0
  21. package/dist/src/peer_transport/pb/index.js.map +1 -0
  22. package/dist/src/peer_transport/transport.d.ts +37 -0
  23. package/dist/src/peer_transport/transport.d.ts.map +1 -0
  24. package/dist/src/peer_transport/transport.js +128 -0
  25. package/dist/src/peer_transport/transport.js.map +1 -0
  26. package/dist/src/peer_transport/util.d.ts +10 -0
  27. package/dist/src/peer_transport/util.d.ts.map +1 -0
  28. package/dist/src/peer_transport/util.js +54 -0
  29. package/dist/src/peer_transport/util.js.map +1 -0
  30. package/dist/src/stream.d.ts +1 -0
  31. package/dist/src/stream.d.ts.map +1 -1
  32. package/dist/src/stream.js +6 -2
  33. package/dist/src/stream.js.map +1 -1
  34. package/dist/src/transport.d.ts +3 -3
  35. package/dist/src/transport.d.ts.map +1 -1
  36. package/dist/src/transport.js +6 -5
  37. package/dist/src/transport.js.map +1 -1
  38. package/package.json +16 -5
  39. package/src/index.ts +11 -3
  40. package/src/muxer.ts +45 -15
  41. package/src/peer_transport/handler.ts +139 -0
  42. package/src/peer_transport/listener.ts +44 -0
  43. package/src/peer_transport/pb/index.proto +16 -0
  44. package/src/peer_transport/pb/index.ts +92 -0
  45. package/src/peer_transport/transport.ts +167 -0
  46. package/src/peer_transport/util.ts +62 -0
  47. package/src/stream.ts +7 -2
  48. package/src/transport.ts +9 -8
@@ -0,0 +1,139 @@
1
+ import type { IncomingStreamData } from '@libp2p/interface-registrar'
2
+ import { pbStream } from 'it-pb-stream'
3
+ import pDefer, { type DeferredPromise } from 'p-defer'
4
+ import { TimeoutController } from 'timeout-abort-controller'
5
+ import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
6
+ import * as pb from './pb/index.js'
7
+ import { abortableDuplex } from 'abortable-iterator'
8
+ import { logger } from '@libp2p/logger'
9
+ import type { Stream } from '@libp2p/interface-connection'
10
+ import type { StreamMuxerFactory } from '@libp2p/interface-stream-muxer'
11
+ import { DataChannelMuxerFactory } from '../muxer.js'
12
+
13
+ const DEFAULT_TIMEOUT = 30 * 1000
14
+
15
+ const log = logger('libp2p:webrtc:peer')
16
+
17
+ export type IncomingStreamOpts = { rtcConfiguration?: RTCConfiguration } & IncomingStreamData
18
+
19
+ export async function handleIncomingStream ({ rtcConfiguration, stream: rawStream }: IncomingStreamOpts): Promise<[RTCPeerConnection, StreamMuxerFactory]> {
20
+ const timeoutController = new TimeoutController(DEFAULT_TIMEOUT)
21
+ const signal = timeoutController.signal
22
+ const stream = pbStream(abortableDuplex(rawStream, timeoutController.signal)).pb(pb.Message)
23
+ const pc = new RTCPeerConnection(rtcConfiguration)
24
+ const muxerFactory = new DataChannelMuxerFactory(pc)
25
+
26
+ const connectedPromise: DeferredPromise<void> = pDefer()
27
+ const answerSentPromise: DeferredPromise<void> = pDefer()
28
+
29
+ signal.onabort = () => { connectedPromise.reject() }
30
+ // candidate callbacks
31
+ pc.onicecandidate = ({ candidate }) => {
32
+ answerSentPromise.promise.then(
33
+ () => {
34
+ stream.write({
35
+ type: pb.Message.Type.ICE_CANDIDATE,
36
+ data: (candidate != null) ? JSON.stringify(candidate.toJSON()) : ''
37
+ })
38
+ },
39
+ (err) => {
40
+ log.error('cannot set candidate since sending answer failed', err)
41
+ }
42
+ )
43
+ }
44
+
45
+ resolveOnConnected(pc, connectedPromise)
46
+
47
+ // read an SDP offer
48
+ const pbOffer = await stream.read()
49
+ if (pbOffer.type !== pb.Message.Type.SDP_OFFER) {
50
+ throw new Error(`expected message type SDP_OFFER, received: ${pbOffer.type ?? 'undefined'} `)
51
+ }
52
+ const offer = new RTCSessionDescription({
53
+ type: 'offer',
54
+ sdp: pbOffer.data
55
+ })
56
+
57
+ await pc.setRemoteDescription(offer).catch(err => {
58
+ log.error('could not execute setRemoteDescription', err)
59
+ throw new Error('Failed to set remoteDescription')
60
+ })
61
+
62
+ // create and write an SDP answer
63
+ const answer = await pc.createAnswer().catch(err => {
64
+ log.error('could not execute createAnswer', err)
65
+ answerSentPromise.reject(err)
66
+ throw new Error('Failed to create answer')
67
+ })
68
+ // write the answer to the remote
69
+ stream.write({ type: pb.Message.Type.SDP_ANSWER, data: answer.sdp })
70
+
71
+ await pc.setLocalDescription(answer).catch(err => {
72
+ log.error('could not execute setLocalDescription', err)
73
+ answerSentPromise.reject(err)
74
+ throw new Error('Failed to set localDescription')
75
+ })
76
+
77
+ answerSentPromise.resolve()
78
+
79
+ // wait until candidates are connected
80
+ await readCandidatesUntilConnected(connectedPromise, pc, stream)
81
+ return [pc, muxerFactory]
82
+ }
83
+
84
+ export interface ConnectOptions {
85
+ stream: Stream
86
+ signal: AbortSignal
87
+ rtcConfiguration?: RTCConfiguration
88
+ }
89
+
90
+ export async function initiateConnection ({ rtcConfiguration, signal, stream: rawStream }: ConnectOptions): Promise<[RTCPeerConnection, StreamMuxerFactory]> {
91
+ const stream = pbStream(abortableDuplex(rawStream, signal)).pb(pb.Message)
92
+
93
+ // setup peer connection
94
+ const pc = new RTCPeerConnection(rtcConfiguration)
95
+ const muxerFactory = new DataChannelMuxerFactory(pc)
96
+
97
+ const connectedPromise: DeferredPromise<void> = pDefer()
98
+ resolveOnConnected(pc, connectedPromise)
99
+
100
+ // reject the connectedPromise if the signal aborts
101
+ signal.onabort = connectedPromise.reject
102
+ // we create the channel so that the peerconnection has a component for which
103
+ // to collect candidates. The label is not relevant to connection initiation
104
+ // but can be useful for debugging
105
+ const channel = pc.createDataChannel('init')
106
+ // setup callback to write ICE candidates to the remote
107
+ // peer
108
+ pc.onicecandidate = ({ candidate }) => {
109
+ stream.write({
110
+ type: pb.Message.Type.ICE_CANDIDATE,
111
+ data: (candidate != null) ? JSON.stringify(candidate.toJSON()) : ''
112
+ })
113
+ }
114
+ // create an offer
115
+ const offerSdp = await pc.createOffer()
116
+ // write the offer to the stream
117
+ stream.write({ type: pb.Message.Type.SDP_OFFER, data: offerSdp.sdp })
118
+ // set offer as local description
119
+ await pc.setLocalDescription(offerSdp).catch(err => {
120
+ log.error('could not execute setLocalDescription', err)
121
+ throw new Error('Failed to set localDescription')
122
+ })
123
+
124
+ // read answer
125
+ const answerMessage = await stream.read()
126
+ if (answerMessage.type !== pb.Message.Type.SDP_ANSWER) {
127
+ throw new Error('remote should send an SDP answer')
128
+ }
129
+
130
+ const answerSdp = new RTCSessionDescription({ type: 'answer', sdp: answerMessage.data })
131
+ await pc.setRemoteDescription(answerSdp).catch(err => {
132
+ log.error('could not execute setRemoteDescription', err)
133
+ throw new Error('Failed to set remoteDescription')
134
+ })
135
+
136
+ await readCandidatesUntilConnected(connectedPromise, pc, stream)
137
+ channel.close()
138
+ return [pc, muxerFactory]
139
+ }
@@ -0,0 +1,44 @@
1
+ import type { PeerId } from '@libp2p/interface-peer-id'
2
+ import type { ListenerEvents, TransportManager, Upgrader, Listener } from '@libp2p/interface-transport'
3
+ import { EventEmitter } from '@libp2p/interfaces/events'
4
+ import { multiaddr, Multiaddr } from '@multiformats/multiaddr'
5
+ import { inappropriateMultiaddr } from '../error.js'
6
+ import { TRANSPORT } from './transport.js'
7
+
8
+ export interface ListenerOptions {
9
+ peerId: PeerId
10
+ upgrader: Upgrader
11
+ transportManager: TransportManager
12
+ }
13
+
14
+ export class WebRTCPeerListener extends EventEmitter<ListenerEvents> implements Listener {
15
+ constructor (
16
+ private readonly opts: ListenerOptions
17
+ ) {
18
+ super()
19
+ }
20
+
21
+ private getBaseAddress (ma: Multiaddr): Multiaddr {
22
+ const addrs = ma.toString().split(TRANSPORT)
23
+ if (addrs.length < 2) {
24
+ throw inappropriateMultiaddr('base address not found')
25
+ }
26
+ return multiaddr(addrs[0])
27
+ }
28
+
29
+ private listeningAddrs: Multiaddr[] = []
30
+ async listen (ma: Multiaddr): Promise<void> {
31
+ const baseAddr = this.getBaseAddress(ma)
32
+ const tpt = this.opts.transportManager.transportForMultiaddr(baseAddr)
33
+ const listener = tpt?.createListener({ ...this.opts })
34
+ await listener?.listen(baseAddr)
35
+ const listeningAddr = ma.encapsulate(`/p2p/${this.opts.peerId.toString()}`)
36
+ this.listeningAddrs.push(listeningAddr)
37
+ listener?.addEventListener('close', () => {
38
+ this.listeningAddrs = this.listeningAddrs.filter(a => a !== listeningAddr)
39
+ })
40
+ }
41
+
42
+ getAddrs (): Multiaddr[] { return this.listeningAddrs }
43
+ async close (): Promise<void> { }
44
+ }
@@ -0,0 +1,16 @@
1
+ syntax = "proto3";
2
+
3
+ message Message {
4
+ // Specifies type in `data` field.
5
+ enum Type {
6
+ // String of `RTCSessionDescription.sdp`
7
+ SDP_OFFER = 0;
8
+ // String of `RTCSessionDescription.sdp`
9
+ SDP_ANSWER = 1;
10
+ // String of `RTCIceCandidate.toJSON()`
11
+ ICE_CANDIDATE = 2;
12
+ }
13
+
14
+ optional Type type = 1;
15
+ optional string data = 2;
16
+ }
@@ -0,0 +1,92 @@
1
+ /* eslint-disable import/export */
2
+ /* eslint-disable complexity */
3
+ /* eslint-disable @typescript-eslint/no-namespace */
4
+ /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
5
+ /* eslint-disable @typescript-eslint/no-empty-interface */
6
+
7
+ import { enumeration, encodeMessage, decodeMessage, message } from 'protons-runtime'
8
+ import type { Uint8ArrayList } from 'uint8arraylist'
9
+ import type { Codec } from 'protons-runtime'
10
+
11
+ export interface Message {
12
+ type?: Message.Type
13
+ data?: string
14
+ }
15
+
16
+ export namespace Message {
17
+ export enum Type {
18
+ SDP_OFFER = 'SDP_OFFER',
19
+ SDP_ANSWER = 'SDP_ANSWER',
20
+ ICE_CANDIDATE = 'ICE_CANDIDATE'
21
+ }
22
+
23
+ enum __TypeValues {
24
+ SDP_OFFER = 0,
25
+ SDP_ANSWER = 1,
26
+ ICE_CANDIDATE = 2
27
+ }
28
+
29
+ export namespace Type {
30
+ export const codec = (): Codec<Type> => {
31
+ return enumeration<Type>(__TypeValues)
32
+ }
33
+ }
34
+
35
+ let _codec: Codec<Message>
36
+
37
+ export const codec = (): Codec<Message> => {
38
+ if (_codec == null) {
39
+ _codec = message<Message>((obj, w, opts = {}) => {
40
+ if (opts.lengthDelimited !== false) {
41
+ w.fork()
42
+ }
43
+
44
+ if (obj.type != null) {
45
+ w.uint32(8)
46
+ Message.Type.codec().encode(obj.type, w)
47
+ }
48
+
49
+ if (obj.data != null) {
50
+ w.uint32(18)
51
+ w.string(obj.data)
52
+ }
53
+
54
+ if (opts.lengthDelimited !== false) {
55
+ w.ldelim()
56
+ }
57
+ }, (reader, length) => {
58
+ const obj: any = {}
59
+
60
+ const end = length == null ? reader.len : reader.pos + length
61
+
62
+ while (reader.pos < end) {
63
+ const tag = reader.uint32()
64
+
65
+ switch (tag >>> 3) {
66
+ case 1:
67
+ obj.type = Message.Type.codec().decode(reader)
68
+ break
69
+ case 2:
70
+ obj.data = reader.string()
71
+ break
72
+ default:
73
+ reader.skipType(tag & 7)
74
+ break
75
+ }
76
+ }
77
+
78
+ return obj
79
+ })
80
+ }
81
+
82
+ return _codec
83
+ }
84
+
85
+ export const encode = (obj: Message): Uint8Array => {
86
+ return encodeMessage(obj, Message.codec())
87
+ }
88
+
89
+ export const decode = (buf: Uint8Array | Uint8ArrayList): Message => {
90
+ return decodeMessage(buf, Message.codec())
91
+ }
92
+ }
@@ -0,0 +1,167 @@
1
+ import type { Connection } from '@libp2p/interface-connection'
2
+ import { CreateListenerOptions, DialOptions, Listener, symbol, Transport } from '@libp2p/interface-transport'
3
+ import type { TransportManager, Upgrader } from '@libp2p/interface-transport'
4
+ import { multiaddr, Multiaddr, protocols } from '@multiformats/multiaddr'
5
+ import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
6
+ import type { PeerId } from '@libp2p/interface-peer-id'
7
+ import { WebRTCMultiaddrConnection } from '../maconn.js'
8
+ import type { Startable } from '@libp2p/interfaces/startable'
9
+ import { WebRTCPeerListener } from './listener.js'
10
+ import type { PeerStore } from '@libp2p/interface-peer-store'
11
+ import { logger } from '@libp2p/logger'
12
+ import { initiateConnection, handleIncomingStream } from './handler.js'
13
+ import { CodeError } from '@libp2p/interfaces/errors'
14
+ import { codes } from '../error.js'
15
+
16
+ const log = logger('libp2p:webrtc:peer')
17
+
18
+ export const TRANSPORT = '/webrtc'
19
+ export const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1'
20
+ export const CODE = protocols('webrtc').code
21
+
22
+ export interface WebRTCTransportInit {
23
+ rtcConfiguration?: RTCConfiguration
24
+ }
25
+
26
+ export interface WebRTCTransportComponents {
27
+ peerId: PeerId
28
+ registrar: Registrar
29
+ upgrader: Upgrader
30
+ transportManager: TransportManager
31
+ peerStore: PeerStore
32
+ }
33
+
34
+ export class WebRTCTransport implements Transport, Startable {
35
+ private _started = false
36
+
37
+ constructor (
38
+ private readonly components: WebRTCTransportComponents,
39
+ private readonly init: WebRTCTransportInit
40
+ ) {
41
+ }
42
+
43
+ isStarted (): boolean {
44
+ return this._started
45
+ }
46
+
47
+ async start (): Promise<void> {
48
+ await this.components.registrar.handle(SIGNALING_PROTO_ID, (data) => {
49
+ this._onProtocol(data).catch(err => { log.error('failed to handle incoming connect from %p', data.connection.remotePeer, err) })
50
+ })
51
+ this._started = true
52
+ }
53
+
54
+ async stop (): Promise<void> {
55
+ await this.components.registrar.unhandle(SIGNALING_PROTO_ID)
56
+ this._started = false
57
+ }
58
+
59
+ createListener (options: CreateListenerOptions): Listener {
60
+ return new WebRTCPeerListener(this.components)
61
+ }
62
+
63
+ get [Symbol.toStringTag] (): string {
64
+ return '@libp2p/webrtc'
65
+ }
66
+
67
+ get [symbol] (): true {
68
+ return true
69
+ }
70
+
71
+ filter (multiaddrs: Multiaddr[]): Multiaddr[] {
72
+ return multiaddrs.filter((ma) => {
73
+ const codes = ma.protoCodes()
74
+ return codes.includes(CODE)
75
+ })
76
+ }
77
+
78
+ /*
79
+ * dial connects to a remote via the circuit relay or any other protocol
80
+ * and proceeds to upgrade to a webrtc connection.
81
+ * multiaddr of the form: <multiaddr>/webrtc/p2p/<destination-peer>
82
+ * For a circuit relay, this will be of the form
83
+ * <relay address>/p2p/<relay-peer>/p2p-circuit/webrtc/p2p/<destination-peer>
84
+ */
85
+ async dial (ma: Multiaddr, options: DialOptions): Promise<Connection> {
86
+ log.trace('dialing address: ', ma)
87
+ const addrs = ma.toString().split(`${TRANSPORT}/`)
88
+ if (addrs.length !== 2) {
89
+ throw new CodeError('invalid multiaddr', codes.ERR_INVALID_MULTIADDR)
90
+ }
91
+ // look for remote peerId
92
+ let remoteAddr = multiaddr(addrs[0])
93
+ const destination = multiaddr('/' + addrs[1])
94
+
95
+ const destinationIdString = destination.getPeerId()
96
+ if (destinationIdString == null) {
97
+ throw new CodeError('bad destination', codes.ERR_INVALID_MULTIADDR)
98
+ }
99
+
100
+ if (options.signal == null) {
101
+ const controller = new AbortController()
102
+ options.signal = controller.signal
103
+ }
104
+
105
+ const lastProtoInRemote = remoteAddr.protos().pop()
106
+ if (lastProtoInRemote === undefined) {
107
+ throw new CodeError('invalid multiaddr', codes.ERR_INVALID_MULTIADDR)
108
+ }
109
+ if (lastProtoInRemote.name !== 'p2p') {
110
+ remoteAddr = remoteAddr.encapsulate(`/p2p/${destinationIdString}`)
111
+ }
112
+
113
+ const connection = await this.components.transportManager.dial(remoteAddr)
114
+
115
+ const rawStream = await connection.newStream([SIGNALING_PROTO_ID], options)
116
+
117
+ try {
118
+ const [pc, muxerFactory] = await initiateConnection({
119
+ stream: rawStream,
120
+ rtcConfiguration: this.init.rtcConfiguration,
121
+ signal: options.signal
122
+ })
123
+ const result = await options.upgrader.upgradeOutbound(
124
+ new WebRTCMultiaddrConnection({
125
+ peerConnection: pc,
126
+ timeline: { open: (new Date()).getTime() },
127
+ remoteAddr: connection.remoteAddr
128
+ }),
129
+ {
130
+ skipProtection: true,
131
+ skipEncryption: true,
132
+ muxerFactory
133
+ }
134
+ )
135
+
136
+ // close the stream if SDP has been exchanged successfully
137
+ rawStream.close()
138
+ return result
139
+ } catch (err) {
140
+ // reset the stream in case of any error
141
+ rawStream.reset()
142
+ throw err
143
+ }
144
+ }
145
+
146
+ async _onProtocol ({ connection, stream }: IncomingStreamData): Promise<void> {
147
+ try {
148
+ const [pc, muxerFactory] = await handleIncomingStream({
149
+ rtcConfiguration: this.init.rtcConfiguration,
150
+ connection,
151
+ stream
152
+ })
153
+ await this.components.upgrader.upgradeInbound(new WebRTCMultiaddrConnection({
154
+ peerConnection: pc,
155
+ timeline: { open: (new Date()).getTime() },
156
+ remoteAddr: connection.remoteAddr
157
+ }), {
158
+ skipEncryption: true,
159
+ skipProtection: true,
160
+ muxerFactory
161
+ })
162
+ } catch (err) {
163
+ stream.reset()
164
+ throw err
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,62 @@
1
+ import { logger } from '@libp2p/logger'
2
+ import type { DeferredPromise } from 'p-defer'
3
+ import * as pb from './pb/index.js'
4
+ import { detect } from 'detect-browser'
5
+
6
+ const browser = detect()
7
+ const isFirefox = ((browser != null) && browser.name === 'firefox')
8
+
9
+ interface MessageStream {
10
+ read: () => Promise<pb.Message>
11
+ write: (d: pb.Message) => void | Promise<void>
12
+ }
13
+
14
+ const log = logger('libp2p:webrtc:peer:util')
15
+
16
+ export const readCandidatesUntilConnected = async (connectedPromise: DeferredPromise<void>, pc: RTCPeerConnection, stream: MessageStream): Promise<void> => {
17
+ while (true) {
18
+ const readResult = await Promise.race([connectedPromise.promise, stream.read()])
19
+ // check if readResult is a message
20
+ if (readResult instanceof Object) {
21
+ const message = readResult
22
+ if (message.type !== pb.Message.Type.ICE_CANDIDATE) {
23
+ throw new Error('expected only ice candidates')
24
+ }
25
+ // end of candidates has been signalled
26
+ if (message.data == null || message.data === '') {
27
+ log.trace('end-of-candidates received')
28
+ break
29
+ }
30
+
31
+ log.trace('received new ICE candidate: %s', message.data)
32
+ try {
33
+ await pc.addIceCandidate(new RTCIceCandidate(JSON.parse(message.data)))
34
+ } catch (err) {
35
+ log.error('bad candidate received: ', err)
36
+ throw new Error('bad candidate received')
37
+ }
38
+ } else {
39
+ // connected promise resolved
40
+ break
41
+ }
42
+ }
43
+ await connectedPromise.promise
44
+ }
45
+
46
+ export function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<void>): void {
47
+ pc[isFirefox ? 'oniceconnectionstatechange' : 'onconnectionstatechange'] = (_) => {
48
+ log.trace('receiver peerConnectionState state: ', pc.connectionState)
49
+ switch (isFirefox ? pc.iceConnectionState : pc.connectionState) {
50
+ case 'connected':
51
+ promise.resolve()
52
+ break
53
+ case 'failed':
54
+ case 'disconnected':
55
+ case 'closed':
56
+ promise.reject()
57
+ break
58
+ default:
59
+ break
60
+ }
61
+ }
62
+ }
package/src/stream.ts CHANGED
@@ -421,8 +421,6 @@ export class WebRTCStream implements Stream {
421
421
  * @see this.closeWrite
422
422
  */
423
423
  reset (): void {
424
- // TODO Why are you resetting the stat here?
425
- this.stat = defaultStat(this.stat.direction)
426
424
  const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag: pb.Message_Flag.RESET })
427
425
  if (currentState === nextState) {
428
426
  // No change, no op
@@ -454,4 +452,11 @@ export class WebRTCStream implements Stream {
454
452
  }
455
453
  }
456
454
  }
455
+
456
+ eq (stream: Stream): boolean {
457
+ if (stream instanceof WebRTCStream) {
458
+ return stream.channel.id === this.channel.id
459
+ }
460
+ return false
461
+ }
457
462
  }
package/src/transport.ts CHANGED
@@ -15,6 +15,7 @@ import type { WebRTCDialOptions } from './options.js'
15
15
  import * as sdp from './sdp.js'
16
16
  import { WebRTCStream } from './stream.js'
17
17
  import { genUfrag } from './util.js'
18
+ import { protocols } from '@multiformats/multiaddr'
18
19
 
19
20
  const log = logger('libp2p:webrtc:transport')
20
21
 
@@ -28,30 +29,30 @@ const HANDSHAKE_TIMEOUT_MS = 10_000
28
29
  *
29
30
  * {@link https://github.com/multiformats/multiaddr/blob/master/protocols.csv}
30
31
  */
31
- export const WEBRTC_CODE: number = 280
32
+ export const WEBRTC_CODE: number = protocols('webrtc-direct').code
32
33
 
33
34
  /**
34
35
  * Created by converting the hexadecimal protocol code to an integer.
35
36
  *
36
37
  * {@link https://github.com/multiformats/multiaddr/blob/master/protocols.csv}
37
38
  */
38
- export const CERTHASH_CODE: number = 466
39
+ export const CERTHASH_CODE: number = protocols('certhash').code
39
40
 
40
41
  /**
41
42
  * The peer for this transport
42
43
  */
43
44
  // @TODO(ddimaria): seems like an unnessary abstraction, consider removing
44
- export interface WebRTCTransportComponents {
45
+ export interface WebRTCDirectTransportComponents {
45
46
  peerId: PeerId
46
47
  }
47
48
 
48
- export class WebRTCTransport implements Transport {
49
+ export class WebRTCDirectTransport implements Transport {
49
50
  /**
50
51
  * The peer for this transport
51
52
  */
52
- private readonly components: WebRTCTransportComponents
53
+ private readonly components: WebRTCDirectTransportComponents
53
54
 
54
- constructor (components: WebRTCTransportComponents) {
55
+ constructor (components: WebRTCDirectTransportComponents) {
55
56
  this.components = components
56
57
  }
57
58
 
@@ -82,7 +83,7 @@ export class WebRTCTransport implements Transport {
82
83
  * Implement toString() for WebRTCTransport
83
84
  */
84
85
  get [Symbol.toStringTag] (): string {
85
- return '@libp2p/webrtc'
86
+ return '@libp2p/webrtc-direct'
86
87
  }
87
88
 
88
89
  /**
@@ -238,5 +239,5 @@ export class WebRTCTransport implements Transport {
238
239
  */
239
240
  function validMa (ma: Multiaddr): boolean {
240
241
  const codes = ma.protoCodes()
241
- return codes.includes(WEBRTC_CODE) && codes.includes(CERTHASH_CODE) && ma.getPeerId() != null
242
+ return codes.includes(WEBRTC_CODE) && codes.includes(CERTHASH_CODE) && ma.getPeerId() != null && !codes.includes(protocols('p2p-circuit').code)
242
243
  }