'use strict' const EventEmitter = require('events') const os = require('os') const multiaddr = require('multiaddr') const { createServer } = require('it-ws') const debug = require('debug') const log = debug('libp2p:websockets:listener') log.error = debug('libp2p:websockets:listener:error') const toConnection = require('./socket-to-conn') module.exports = ({ handler, upgrader }, options = {}) => { const listener = new EventEmitter() const server = createServer(options, async (stream) => { let maConn, conn try { maConn = toConnection(stream) log('new inbound connection %s', maConn.remoteAddr) conn = await upgrader.upgradeInbound(maConn) } catch (err) { log.error('inbound connection failed to upgrade', err) return maConn && maConn.close() } log('inbound connection %s upgraded', maConn.remoteAddr) trackConn(server, maConn) if (handler) handler(conn) listener.emit('connection', conn) }) server .on('listening', () => listener.emit('listening')) .on('error', err => listener.emit('error', err)) .on('close', () => listener.emit('close')) // Keep track of open connections to destroy in case of timeout server.__connections = [] let listeningMultiaddr listener.close = () => { server.__connections.forEach(maConn => maConn.close()) return server.close() } listener.listen = (ma) => { listeningMultiaddr = ma return server.listen(ma.toOptions()) } listener.getAddrs = () => { const multiaddrs = [] const address = server.address() if (!address) { throw new Error('Listener is not ready yet') } const ipfsId = listeningMultiaddr.getPeerId() // Because TCP will only return the IPv6 version // we need to capture from the passed multiaddr if (listeningMultiaddr.toString().indexOf('ip4') !== -1) { let m = listeningMultiaddr.decapsulate('tcp') m = m.encapsulate('/tcp/' + address.port + '/ws') if (listeningMultiaddr.getPeerId()) { m = m.encapsulate('/p2p/' + ipfsId) } if (m.toString().indexOf('0.0.0.0') !== -1) { const netInterfaces = os.networkInterfaces() Object.keys(netInterfaces).forEach((niKey) => { netInterfaces[niKey].forEach((ni) => { if (ni.family === 'IPv4') { multiaddrs.push(new multiaddr.Multiaddr(m.toString().replace('0.0.0.0', ni.address))) } }) }) } else { multiaddrs.push(m) } } return multiaddrs } return listener } function trackConn (server, maConn) { server.__connections.push(maConn) }