@libp2p/websockets 9.0.13-98b43045c → 9.0.13-a0c8ceb99

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.
package/src/index.ts CHANGED
@@ -18,43 +18,9 @@
18
18
  * })
19
19
  * await node.start()
20
20
  *
21
- * const ma = multiaddr('/ip4/127.0.0.1/tcp/9090/ws')
21
+ * const ma = multiaddr('/dns4/example.com/tcp/9090/tls/ws')
22
22
  * await node.dial(ma)
23
23
  * ```
24
- *
25
- * ## Filters
26
- *
27
- * When run in a browser by default this module will only connect to secure web socket addresses.
28
- *
29
- * To change this you should pass a filter to the factory function.
30
- *
31
- * You can create your own address filters for this transports, or rely in the filters [provided](./src/filters.js).
32
- *
33
- * The available filters are:
34
- *
35
- * - `filters.all`
36
- * - Returns all TCP and DNS based addresses, both with `ws` or `wss`.
37
- * - `filters.dnsWss`
38
- * - Returns all DNS based addresses with `wss`.
39
- * - `filters.dnsWsOrWss`
40
- * - Returns all DNS based addresses, both with `ws` or `wss`.
41
- *
42
- * @example Allow dialing insecure WebSockets
43
- *
44
- * ```TypeScript
45
- * import { createLibp2p } from 'libp2p'
46
- * import { webSockets } from '@libp2p/websockets'
47
- * import * as filters from '@libp2p/websockets/filters'
48
- *
49
- * const node = await createLibp2p({
50
- * transports: [
51
- * webSockets({
52
- * // connect to all sockets, even insecure ones
53
- * filter: filters.all
54
- * })
55
- * ]
56
- * })
57
- * ```
58
24
  */
59
25
 
60
26
  import { transportSymbol, serviceCapabilities, ConnectionFailedError } from '@libp2p/interface'
@@ -63,25 +29,50 @@ import { connect, type WebSocketOptions } from 'it-ws/client'
63
29
  import pDefer from 'p-defer'
64
30
  import { CustomProgressEvent } from 'progress-events'
65
31
  import { raceSignal } from 'race-signal'
66
- import { isBrowser, isWebWorker } from 'wherearewe'
67
32
  import * as filters from './filters.js'
68
33
  import { createListener } from './listener.js'
69
34
  import { socketToMaConn } from './socket-to-conn.js'
70
- import type { Transport, MultiaddrFilter, CreateListenerOptions, DialTransportOptions, Listener, AbortOptions, ComponentLogger, Logger, Connection, OutboundConnectionUpgradeEvents, Metrics, CounterGroup } from '@libp2p/interface'
35
+ import type { Transport, MultiaddrFilter, CreateListenerOptions, DialTransportOptions, Listener, AbortOptions, ComponentLogger, Logger, Connection, OutboundConnectionUpgradeEvents, Metrics, CounterGroup, TypedEventTarget, Libp2pEvents } from '@libp2p/interface'
71
36
  import type { Multiaddr } from '@multiformats/multiaddr'
72
- import type { Server } from 'http'
73
37
  import type { DuplexWebSocket } from 'it-ws/duplex'
38
+ import type http from 'node:http'
39
+ import type https from 'node:https'
74
40
  import type { ProgressEvent } from 'progress-events'
75
41
  import type { ClientOptions } from 'ws'
76
42
 
77
43
  export interface WebSocketsInit extends AbortOptions, WebSocketOptions {
44
+ /**
45
+ * @deprecated Use a ConnectionGater instead
46
+ */
78
47
  filter?: MultiaddrFilter
48
+
49
+ /**
50
+ * Options used to create WebSockets
51
+ */
79
52
  websocket?: ClientOptions
80
- server?: Server
53
+
54
+ /**
55
+ * Options used to create the HTTP server
56
+ */
57
+ http?: http.ServerOptions
58
+
59
+ /**
60
+ * Options used to create the HTTPs server. `options.http` will be used if
61
+ * unspecified.
62
+ */
63
+ https?: https.ServerOptions
64
+
65
+ /**
66
+ * Inbound connections must complete their upgrade within this many ms
67
+ *
68
+ * @default 5000
69
+ */
70
+ inboundConnectionUpgradeTimeout?: number
81
71
  }
82
72
 
83
73
  export interface WebSocketsComponents {
84
74
  logger: ComponentLogger
75
+ events: TypedEventTarget<Libp2pEvents>
85
76
  metrics?: Metrics
86
77
  }
87
78
 
@@ -95,12 +86,12 @@ export type WebSocketsDialEvents =
95
86
 
96
87
  class WebSockets implements Transport<WebSocketsDialEvents> {
97
88
  private readonly log: Logger
98
- private readonly init?: WebSocketsInit
89
+ private readonly init: WebSocketsInit
99
90
  private readonly logger: ComponentLogger
100
91
  private readonly metrics?: WebSocketsMetrics
101
92
  private readonly components: WebSocketsComponents
102
93
 
103
- constructor (components: WebSocketsComponents, init?: WebSocketsInit) {
94
+ constructor (components: WebSocketsComponents, init: WebSocketsInit = {}) {
104
95
  this.log = components.logger.forComponent('libp2p:websockets')
105
96
  this.logger = components.logger
106
97
  this.components = components
@@ -180,13 +171,14 @@ class WebSockets implements Transport<WebSocketsDialEvents> {
180
171
  }
181
172
 
182
173
  /**
183
- * Creates a Websockets listener. The provided `handler` function will be called
174
+ * Creates a WebSockets listener. The provided `handler` function will be called
184
175
  * anytime a new incoming Connection has been successfully upgraded via
185
176
  * `upgrader.upgradeInbound`
186
177
  */
187
178
  createListener (options: CreateListenerOptions): Listener {
188
179
  return createListener({
189
180
  logger: this.logger,
181
+ events: this.components.events,
190
182
  metrics: this.components.metrics
191
183
  }, {
192
184
  ...this.init,
@@ -195,7 +187,7 @@ class WebSockets implements Transport<WebSocketsDialEvents> {
195
187
  }
196
188
 
197
189
  /**
198
- * Takes a list of `Multiaddr`s and returns only valid Websockets addresses.
190
+ * Takes a list of `Multiaddr`s and returns only valid WebSockets addresses.
199
191
  * By default, in a browser environment only DNS+WSS multiaddr is accepted,
200
192
  * while in a Node.js environment DNS+{WS, WSS} multiaddrs are accepted.
201
193
  */
@@ -206,11 +198,6 @@ class WebSockets implements Transport<WebSocketsDialEvents> {
206
198
  return this.init?.filter(multiaddrs)
207
199
  }
208
200
 
209
- // Browser
210
- if (isBrowser || isWebWorker) {
211
- return filters.wss(multiaddrs)
212
- }
213
-
214
201
  return filters.all(multiaddrs)
215
202
  }
216
203
 
package/src/listener.ts CHANGED
@@ -1,145 +1,345 @@
1
- import os from 'os'
2
- import { TypedEventEmitter } from '@libp2p/interface'
1
+ import http from 'node:http'
2
+ import https from 'node:https'
3
+ import net from 'node:net'
4
+ import os from 'node:os'
5
+ import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
3
6
  import { ipPortToMultiaddr as toMultiaddr } from '@libp2p/utils/ip-port-to-multiaddr'
4
- import { multiaddr, protocols } from '@multiformats/multiaddr'
5
- import { createServer } from 'it-ws/server'
7
+ import { multiaddr } from '@multiformats/multiaddr'
8
+ import { WebSockets, WebSocketsSecure } from '@multiformats/multiaddr-matcher'
9
+ import duplex from 'it-ws/duplex'
10
+ import { pEvent } from 'p-event'
11
+ import * as ws from 'ws'
6
12
  import { socketToMaConn } from './socket-to-conn.js'
7
- import type { ComponentLogger, Logger, Listener, ListenerEvents, CreateListenerOptions, CounterGroup, MetricGroup, Metrics } from '@libp2p/interface'
13
+ import type { ComponentLogger, Logger, Listener, ListenerEvents, CreateListenerOptions, CounterGroup, MetricGroup, Metrics, TLSCertificate, TypedEventTarget, Libp2pEvents, Upgrader, MultiaddrConnection } from '@libp2p/interface'
8
14
  import type { Multiaddr } from '@multiformats/multiaddr'
9
- import type { Server } from 'http'
10
15
  import type { DuplexWebSocket } from 'it-ws/duplex'
11
- import type { WebSocketServer } from 'it-ws/server'
16
+ import type { EventEmitter } from 'node:events'
17
+ import type { Server } from 'node:http'
18
+ import type { Duplex } from 'node:stream'
19
+ import type tls from 'node:tls'
12
20
 
13
21
  export interface WebSocketListenerComponents {
14
22
  logger: ComponentLogger
23
+ events: TypedEventTarget<Libp2pEvents>
15
24
  metrics?: Metrics
16
25
  }
17
26
 
18
27
  export interface WebSocketListenerInit extends CreateListenerOptions {
19
28
  server?: Server
29
+ inboundConnectionUpgradeTimeout?: number
30
+ cert?: string
31
+ key?: string
32
+ http?: http.ServerOptions
33
+ https?: http.ServerOptions
20
34
  }
21
35
 
22
36
  export interface WebSocketListenerMetrics {
23
- status: MetricGroup
24
- errors: CounterGroup
25
- events: CounterGroup
37
+ status?: MetricGroup
38
+ errors?: CounterGroup
39
+ events?: CounterGroup
26
40
  }
27
41
 
28
- class WebSocketListener extends TypedEventEmitter<ListenerEvents> implements Listener {
29
- private readonly connections: Set<DuplexWebSocket>
30
- private listeningMultiaddr?: Multiaddr
31
- private readonly server: WebSocketServer
42
+ export class WebSocketListener extends TypedEventEmitter<ListenerEvents> implements Listener {
32
43
  private readonly log: Logger
33
- private metrics?: WebSocketListenerMetrics
34
- private addr: string
44
+ private readonly logger: ComponentLogger
45
+ private readonly server: net.Server
46
+ private readonly wsServer: ws.WebSocketServer
47
+ private readonly metrics: WebSocketListenerMetrics
48
+ private readonly sockets: Set<net.Socket>
49
+ private readonly upgrader: Upgrader
50
+ private readonly inboundConnectionUpgradeTimeout: number
51
+ private readonly httpOptions?: http.ServerOptions
52
+ private readonly httpsOptions?: https.ServerOptions
53
+ private http?: http.Server
54
+ private https?: https.Server
55
+ private addr?: string
56
+ private listeningMultiaddr?: Multiaddr
35
57
 
36
58
  constructor (components: WebSocketListenerComponents, init: WebSocketListenerInit) {
37
59
  super()
38
60
 
39
61
  this.log = components.logger.forComponent('libp2p:websockets:listener')
40
- const metrics = components.metrics
41
- // Keep track of open connections to destroy when the listener is closed
42
- this.connections = new Set<DuplexWebSocket>()
62
+ this.logger = components.logger
63
+ this.upgrader = init.upgrader
64
+ this.httpOptions = init.http
65
+ this.httpsOptions = init.https ?? init.http
66
+ this.inboundConnectionUpgradeTimeout = init.inboundConnectionUpgradeTimeout ?? 5000
67
+ this.sockets = new Set()
43
68
 
44
- const self = this // eslint-disable-line @typescript-eslint/no-this-alias
69
+ this.wsServer = new ws.WebSocketServer({
70
+ noServer: true
71
+ })
72
+ this.wsServer.addListener('connection', this.onWsServerConnection.bind(this))
45
73
 
46
- this.addr = 'unknown'
74
+ components.metrics?.registerMetricGroup('libp2p_websockets_inbound_connections_total', {
75
+ label: 'address',
76
+ help: 'Current active connections in WebSocket listener',
77
+ calculate: () => {
78
+ if (this.addr == null) {
79
+ return {}
80
+ }
47
81
 
48
- this.server = createServer({
49
- ...init,
50
- onConnection: (stream: DuplexWebSocket) => {
51
- const maConn = socketToMaConn(stream, toMultiaddr(stream.remoteAddress ?? '', stream.remotePort ?? 0), {
52
- logger: components.logger,
53
- metrics: this.metrics?.events,
54
- metricPrefix: `${this.addr} `
55
- })
56
- this.log('new inbound connection %s', maConn.remoteAddr)
82
+ return {
83
+ [this.addr]: this.sockets.size
84
+ }
85
+ }
86
+ })
57
87
 
58
- this.connections.add(stream)
88
+ this.metrics = {
89
+ status: components.metrics?.registerMetricGroup('libp2p_websockets_listener_status_info', {
90
+ label: 'address',
91
+ help: 'Current status of the WebSocket listener socket'
92
+ }),
93
+ errors: components.metrics?.registerMetricGroup('libp2p_websockets_listener_errors_total', {
94
+ label: 'address',
95
+ help: 'Total count of WebSocket listener errors by type'
96
+ }),
97
+ events: components.metrics?.registerMetricGroup('libp2p_websockets_listener_events_total', {
98
+ label: 'address',
99
+ help: 'Total count of WebSocket listener events by type'
100
+ })
101
+ }
59
102
 
60
- stream.socket.on('close', function () {
61
- self.connections.delete(stream)
103
+ this.server = net.createServer({
104
+ pauseOnConnect: true
105
+ }, (socket) => {
106
+ this.onSocketConnection(socket)
107
+ .catch(err => {
108
+ this.log.error('error handling socket - %e', err)
109
+ socket.destroy()
62
110
  })
111
+ })
63
112
 
64
- init.upgrader.upgradeInbound(maConn)
65
- .catch(async err => {
66
- this.log.error('inbound connection failed to upgrade', err)
67
- this.metrics?.errors.increment({ [`${this.addr} inbound_upgrade`]: true })
113
+ components.events.addEventListener('certificate:provision', this.onCertificateProvision.bind(this))
114
+ components.events.addEventListener('certificate:renew', this.onCertificateRenew.bind(this))
115
+ }
68
116
 
69
- try {
70
- maConn.abort(err)
71
- } catch (err) {
72
- this.log.error('inbound connection failed to close after upgrade failed - %e', err)
73
- this.metrics?.errors.increment({ [`${this.addr} inbound_closing_failed`]: true })
74
- }
75
- })
76
- }
77
- })
117
+ async onSocketConnection (socket: net.Socket): Promise<void> {
118
+ this.metrics.events?.increment({ [`${this.addr} connection`]: true })
78
119
 
79
- this.server.on('listening', () => {
80
- if (metrics != null) {
81
- const { host, port } = this.listeningMultiaddr?.toOptions() ?? {}
82
- this.addr = `${host}:${port}`
83
-
84
- metrics.registerMetricGroup('libp2p_websockets_inbound_connections_total', {
85
- label: 'address',
86
- help: 'Current active connections in WebSocket listener',
87
- calculate: () => {
88
- return {
89
- [this.addr]: this.connections.size
90
- }
91
- }
92
- })
120
+ let buffer = socket.read(1)
93
121
 
94
- this.metrics = {
95
- status: metrics?.registerMetricGroup('libp2p_websockets_listener_status_info', {
96
- label: 'address',
97
- help: 'Current status of the WebSocket listener socket'
98
- }),
99
- errors: metrics?.registerMetricGroup('libp2p_websockets_listener_errors_total', {
100
- label: 'address',
101
- help: 'Total count of WebSocket listener errors by type'
102
- }),
103
- events: metrics?.registerMetricGroup('libp2p_websockets_listener_events_total', {
104
- label: 'address',
105
- help: 'Total count of WebSocket listener events by type'
106
- })
107
- }
108
- }
109
- this.dispatchEvent(new CustomEvent('listening'))
122
+ if (buffer == null) {
123
+ await pEvent(socket, 'readable')
124
+ buffer = socket.read(1)
125
+ }
126
+
127
+ // determine if this is an HTTP(s) request
128
+ const byte = buffer[0]
129
+ let server: EventEmitter | undefined = this.http
130
+
131
+ // https://github.com/mscdex/httpolyglot/blob/1c6c4af65f4cf95a32c918d0fdcc532e0c095740/lib/index.js#L92
132
+ if (byte < 32 || byte >= 127) {
133
+ server = this.https
134
+ }
135
+
136
+ if (server == null) {
137
+ this.log.error('no appropriate listener configured for byte %d', byte)
138
+ socket.destroy()
139
+ return
140
+ }
141
+
142
+ // store the socket so we can close it when the listener closes
143
+ this.sockets.add(socket)
144
+
145
+ socket.on('close', () => {
146
+ this.metrics.events?.increment({ [`${this.addr} close`]: true })
147
+ this.sockets.delete(socket)
110
148
  })
111
- this.server.on('error', (err: Error) => {
112
- this.metrics?.errors.increment({ [`${this.addr} listen_error`]: true })
113
- this.dispatchEvent(new CustomEvent('error', {
114
- detail: err
115
- }))
149
+
150
+ socket.on('error', (err) => {
151
+ this.log.error('socket error - %e', err)
152
+ this.metrics.events?.increment({ [`${this.addr} error`]: true })
153
+ socket.destroy()
116
154
  })
117
- this.server.on('close', () => {
118
- this.dispatchEvent(new CustomEvent('close'))
155
+
156
+ socket.once('timeout', () => {
157
+ this.metrics.events?.increment({ [`${this.addr} timeout`]: true })
119
158
  })
159
+
160
+ socket.once('end', () => {
161
+ this.metrics.events?.increment({ [`${this.addr} end`]: true })
162
+ })
163
+
164
+ // re-queue first data chunk
165
+ socket.unshift(buffer)
166
+
167
+ // hand the socket off to the appropriate server
168
+ server.emit('connection', socket)
120
169
  }
121
170
 
122
- async close (): Promise<void> {
123
- await Promise.all(
124
- Array.from(this.connections).map(async maConn => { await maConn.close() })
125
- )
171
+ onWsServerConnection (socket: ws.WebSocket, req: http.IncomingMessage): void {
172
+ let addr: string | ws.AddressInfo | null
173
+
174
+ try {
175
+ addr = this.server.address()
126
176
 
127
- if (this.server.address() == null) {
128
- // not listening, close will throw an error
177
+ if (typeof addr === 'string') {
178
+ throw new Error('Cannot listen on unix sockets')
179
+ }
180
+
181
+ if (addr == null) {
182
+ throw new Error('Server was closing or not running')
183
+ }
184
+ } catch (err: any) {
185
+ this.log.error('error obtaining remote socket address - %e', err)
186
+ req.destroy(err)
187
+ socket.close()
188
+ return
189
+ }
190
+
191
+ const stream: DuplexWebSocket = {
192
+ ...duplex(socket, {
193
+ remoteAddress: req.socket.remoteAddress ?? '0.0.0.0',
194
+ remotePort: req.socket.remotePort ?? 0
195
+ }),
196
+ localAddress: addr.address,
197
+ localPort: addr.port
198
+ }
199
+
200
+ let maConn: MultiaddrConnection
201
+
202
+ try {
203
+ maConn = socketToMaConn(stream, toMultiaddr(stream.remoteAddress ?? '', stream.remotePort ?? 0), {
204
+ logger: this.logger,
205
+ metrics: this.metrics?.events,
206
+ metricPrefix: `${this.addr} `
207
+ })
208
+ } catch (err: any) {
209
+ this.log.error('inbound connection failed', err)
210
+ this.metrics.errors?.increment({ [`${this.addr} inbound_to_connection`]: true })
211
+ socket.close()
129
212
  return
130
213
  }
131
214
 
132
- await this.server.close()
215
+ this.log('new inbound connection %s', maConn.remoteAddr)
216
+ const signal = AbortSignal.timeout(this.inboundConnectionUpgradeTimeout)
217
+ setMaxListeners(Infinity, signal)
218
+
219
+ this.upgrader.upgradeInbound(maConn, {
220
+ signal
221
+ })
222
+ .catch(async err => {
223
+ this.log.error('inbound connection failed to upgrade - %e', err)
224
+ this.metrics.errors?.increment({ [`${this.addr} inbound_upgrade`]: true })
225
+
226
+ await maConn.close()
227
+ .catch(err => {
228
+ this.log.error('inbound connection failed to close after upgrade failed', err)
229
+ this.metrics.errors?.increment({ [`${this.addr} inbound_closing_failed`]: true })
230
+ })
231
+ })
232
+ }
233
+
234
+ onUpgrade (req: http.IncomingMessage, socket: Duplex, head: Buffer): void {
235
+ this.wsServer.handleUpgrade(req, socket, head, this.onWsServerConnection.bind(this))
236
+ }
237
+
238
+ onTLSClientError (err: Error, socket: tls.TLSSocket): void {
239
+ this.log.error('TLS client error - %e', err)
240
+ socket.destroy()
133
241
  }
134
242
 
135
243
  async listen (ma: Multiaddr): Promise<void> {
244
+ if (WebSockets.exactMatch(ma)) {
245
+ this.http = http.createServer(this.httpOptions ?? {}, this.httpRequestHandler.bind(this))
246
+ this.http.addListener('upgrade', this.onUpgrade.bind(this))
247
+ } else if (WebSocketsSecure.exactMatch(ma)) {
248
+ this.https = https.createServer(this.httpsOptions ?? {}, this.httpRequestHandler.bind(this))
249
+ this.https.addListener('upgrade', this.onUpgrade.bind(this))
250
+ this.https.addListener('tlsClientError', this.onTLSClientError.bind(this))
251
+ }
252
+
136
253
  this.listeningMultiaddr = ma
254
+ const { host, port } = ma.toOptions()
255
+ this.addr = `${host}:${port}`
256
+
257
+ this.server.listen(port, host)
258
+
259
+ await new Promise<void>((resolve, reject) => {
260
+ const onListening = (): void => {
261
+ removeListeners()
262
+ resolve()
263
+ }
264
+ const onError = (err: Error): void => {
265
+ this.metrics.errors?.increment({ [`${this.addr} listen_error`]: true })
266
+ removeListeners()
267
+ reject(err)
268
+ }
269
+ const onDrop = (): void => {
270
+ this.metrics.events?.increment({ [`${this.addr} drop`]: true })
271
+ }
272
+ const removeListeners = (): void => {
273
+ this.server.removeListener('listening', onListening)
274
+ this.server.removeListener('error', onError)
275
+ this.server.removeListener('drop', onDrop)
276
+ }
277
+
278
+ this.server.addListener('listening', onListening)
279
+ this.server.addListener('error', onError)
280
+ this.server.addListener('drop', onDrop)
281
+ })
282
+
283
+ this.safeDispatchEvent('listening')
284
+ }
285
+
286
+ onCertificateProvision (event: CustomEvent<TLSCertificate>): void {
287
+ if (this.https != null) {
288
+ this.log('auto-tls certificate found but already listening on https')
289
+ return
290
+ }
291
+
292
+ this.log('auto-tls certificate found, starting https server')
293
+ this.https = https.createServer({
294
+ ...this.httpsOptions,
295
+ ...event.detail
296
+ }, this.httpRequestHandler.bind(this))
297
+ this.https.addListener('upgrade', this.onUpgrade.bind(this))
298
+ this.https.addListener('tlsClientError', this.onTLSClientError.bind(this))
299
+
300
+ this.safeDispatchEvent('listening')
301
+ }
302
+
303
+ onCertificateRenew (event: CustomEvent<TLSCertificate>): void {
304
+ // stop accepting new connections
305
+ this.https?.close()
306
+
307
+ this.log('auto-tls certificate renewed, restarting https server')
308
+ this.https = https.createServer({
309
+ ...this.httpsOptions,
310
+ ...event.detail
311
+ }, this.httpRequestHandler.bind(this))
312
+ this.https.addListener('upgrade', this.onUpgrade.bind(this))
313
+ this.https.addListener('tlsClientError', this.onTLSClientError.bind(this))
314
+ }
137
315
 
138
- await this.server.listen(ma.toOptions())
316
+ async close (): Promise<void> {
317
+ this.server.close()
318
+ this.http?.close()
319
+ this.https?.close()
320
+ this.wsServer.close()
321
+
322
+ // close all connections, must be done after closing the server to prevent
323
+ // race conditions where a new connection is accepted while we are closing
324
+ // the existing ones
325
+ this.http?.closeAllConnections()
326
+ this.https?.closeAllConnections()
327
+
328
+ ;[...this.sockets].forEach(socket => {
329
+ socket.destroy()
330
+ })
331
+
332
+ await Promise.all([
333
+ pEvent(this.server, 'close'),
334
+ this.http == null ? null : pEvent(this.http, 'close'),
335
+ this.https == null ? null : pEvent(this.https, 'close'),
336
+ pEvent(this.wsServer, 'close')
337
+ ])
338
+
339
+ this.safeDispatchEvent('close')
139
340
  }
140
341
 
141
342
  getAddrs (): Multiaddr[] {
142
- const multiaddrs = []
143
343
  const address = this.server.address()
144
344
 
145
345
  if (address == null) {
@@ -154,38 +354,69 @@ class WebSocketListener extends TypedEventEmitter<ListenerEvents> implements Lis
154
354
  throw new Error('Listener is not ready yet')
155
355
  }
156
356
 
157
- const ipfsId = this.listeningMultiaddr.getPeerId()
158
- const protos = this.listeningMultiaddr.protos()
159
-
160
- // Because TCP will only return the IPv6 version
161
- // we need to capture from the passed multiaddr
162
- if (protos.some(proto => proto.code === protocols('ip4').code)) {
163
- const wsProto = protos.some(proto => proto.code === protocols('ws').code) ? '/ws' : '/wss'
164
- let m = this.listeningMultiaddr.decapsulate('tcp')
165
- m = m.encapsulate(`/tcp/${address.port}${wsProto}`)
166
- if (ipfsId != null) {
167
- m = m.encapsulate(`/p2p/${ipfsId}`)
168
- }
357
+ const options = this.listeningMultiaddr.toOptions()
358
+ const multiaddrs: Multiaddr[] = []
169
359
 
170
- if (m.toString().includes('0.0.0.0')) {
171
- const netInterfaces = os.networkInterfaces()
172
- Object.values(netInterfaces).forEach(niInfos => {
360
+ if (options.family === 4) {
361
+ if (options.host === '0.0.0.0') {
362
+ Object.values(os.networkInterfaces()).forEach(niInfos => {
173
363
  if (niInfos == null) {
174
364
  return
175
365
  }
176
366
 
177
367
  niInfos.forEach(ni => {
178
368
  if (ni.family === 'IPv4') {
179
- multiaddrs.push(multiaddr(m.toString().replace('0.0.0.0', ni.address)))
369
+ multiaddrs.push(multiaddr(`/ip${options.family}/${ni.address}/${options.transport}/${address.port}`))
180
370
  }
181
371
  })
182
372
  })
183
373
  } else {
184
- multiaddrs.push(m)
374
+ multiaddrs.push(multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${address.port}`))
185
375
  }
376
+ } else if (options.family === 6) {
377
+ if (options.host === '::') {
378
+ Object.values(os.networkInterfaces()).forEach(niInfos => {
379
+ if (niInfos == null) {
380
+ return
381
+ }
382
+
383
+ niInfos.forEach(ni => {
384
+ if (ni.family === 'IPv6') {
385
+ multiaddrs.push(multiaddr(`/ip${options.family}/${ni.address}/${options.transport}/${address.port}`))
386
+ }
387
+ })
388
+ })
389
+ } else {
390
+ multiaddrs.push(multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${address.port}`))
391
+ }
392
+ }
393
+
394
+ const insecureMultiaddrs: Multiaddr[] = []
395
+
396
+ if (this.http != null) {
397
+ multiaddrs.forEach(ma => {
398
+ insecureMultiaddrs.push(ma.encapsulate('/ws'))
399
+ })
400
+ }
401
+
402
+ const secureMultiaddrs: Multiaddr[] = []
403
+
404
+ if (this.https != null) {
405
+ multiaddrs.forEach(ma => {
406
+ secureMultiaddrs.push(ma.encapsulate('/tls/ws'))
407
+ })
186
408
  }
187
409
 
188
- return multiaddrs
410
+ return [
411
+ ...insecureMultiaddrs,
412
+ ...secureMultiaddrs
413
+ ]
414
+ }
415
+
416
+ private httpRequestHandler (req: http.IncomingMessage, res: http.ServerResponse): void {
417
+ res.writeHead(400)
418
+ res.write('Only WebSocket connections are supported')
419
+ res.end()
189
420
  }
190
421
  }
191
422
 
package/LICENSE DELETED
@@ -1,4 +0,0 @@
1
- This project is dual licensed under MIT and Apache-2.0.
2
-
3
- MIT: https://www.opensource.org/licenses/mit
4
- Apache-2.0: https://www.apache.org/licenses/license-2.0