153 lines
3.5 KiB
JavaScript
Raw Normal View History

2016-03-23 16:23:10 +01:00
'use strict'
2016-04-25 02:21:32 +01:00
const debug = require('debug')
const log = debug('libp2p:websockets')
const SW = require('simple-websocket')
const isNode = require('detect-node')
let SWS
if (isNode) {
SWS = require('simple-websocket-server')
} else {
SWS = {}
}
2016-03-14 21:19:42 +00:00
const mafmt = require('mafmt')
const contains = require('lodash.contains')
const Connection = require('interface-connection').Connection
const CLOSE_TIMEOUT = 2000
// const IPFS_CODE = 421
2016-02-26 13:18:05 +00:00
2016-03-14 20:25:00 +00:00
exports = module.exports = WebSockets
2016-02-26 13:18:05 +00:00
2016-03-14 20:25:00 +00:00
function WebSockets () {
if (!(this instanceof WebSockets)) {
return new WebSockets()
}
this.dial = function (ma, options, callback) {
if (typeof options === 'function') {
callback = options
2016-03-14 20:25:00 +00:00
options = {}
}
if (!callback) {
callback = function noop () {}
2016-03-14 20:25:00 +00:00
}
const maOpts = ma.toOptions()
const socket = new SW('ws://' + maOpts.host + ':' + maOpts.port)
const conn = new Connection(socket)
socket.on('timeout', () => {
conn.emit('timeout')
})
socket.on('error', (err) => {
callback(err)
conn.emit('error', err)
})
socket.on('connect', () => {
callback(null, conn)
conn.emit('connect')
})
conn.getObservedAddrs = (cb) => {
return cb(null, [ma])
}
2016-03-14 20:25:00 +00:00
return conn
}
this.createListener = (options, handler) => {
2016-03-14 20:25:00 +00:00
if (typeof options === 'function') {
handler = options
options = {}
}
const listener = SWS.createServer((socket) => {
const conn = new Connection(socket)
2016-02-26 13:18:05 +00:00
conn.getObservedAddrs = (cb) => {
// TODO research if we can reuse the address in anyway
return cb(null, [])
}
handler(conn)
})
let listeningMultiaddr
2016-03-14 20:25:00 +00:00
listener._listen = listener.listen
listener.listen = (ma, callback) => {
if (!callback) {
callback = function noop () {}
}
listeningMultiaddr = ma
if (contains(ma.protoNames(), 'ipfs')) {
ma = ma.decapsulate('ipfs')
}
2016-03-14 20:25:00 +00:00
listener._listen(ma.toOptions(), callback)
}
listener._close = listener.close
listener.close = (options, callback) => {
if (typeof options === 'function') {
callback = options
options = { timeout: CLOSE_TIMEOUT }
}
if (!callback) { callback = function noop () {} }
if (!options) { options = { timeout: CLOSE_TIMEOUT } }
let closed = false
listener.once('close', () => {
closed = true
})
listener._close(callback)
setTimeout(() => {
if (closed) {
return
2016-03-14 20:25:00 +00:00
}
log('unable to close graciously, destroying conns')
Object.keys(listener.__connections).forEach((key) => {
log('destroying %s', key)
listener.__connections[key].destroy()
})
}, options.timeout || CLOSE_TIMEOUT)
}
// Keep track of open connections to destroy in case of timeout
listener.__connections = {}
listener.on('connection', (socket) => {
const key = (~~(Math.random() * 1e9)).toString(36) + Date.now()
listener.__connections[key] = socket
socket.on('close', () => {
delete listener.__connections[key]
2016-03-14 20:25:00 +00:00
})
})
listener.getAddrs = (callback) => {
callback(null, [listeningMultiaddr])
2016-03-14 20:25:00 +00:00
}
2016-05-08 22:58:38 +02:00
return listener
2016-03-14 20:25:00 +00:00
}
this.filter = (multiaddrs) => {
if (!Array.isArray(multiaddrs)) {
multiaddrs = [multiaddrs]
}
2016-03-14 20:25:00 +00:00
return multiaddrs.filter((ma) => {
if (contains(ma.protoNames(), 'ipfs')) {
ma = ma.decapsulate('ipfs')
}
2016-03-14 21:19:42 +00:00
return mafmt.WebSockets.matches(ma)
2016-03-14 20:25:00 +00:00
})
}
}