You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
2.6 KiB
113 lines
2.6 KiB
5 years ago
|
var through = require('through2')
|
||
|
var duplexify = require('duplexify')
|
||
|
var WS = require('ws')
|
||
|
|
||
|
module.exports = WebSocketStream
|
||
|
|
||
|
function WebSocketStream(target, protocols, options) {
|
||
|
var stream, socket
|
||
|
|
||
|
var isBrowser = process.title === 'browser'
|
||
|
var isNative = !!global.WebSocket
|
||
|
var socketWrite = isBrowser ? socketWriteBrowser : socketWriteNode
|
||
|
var proxy = through.obj(socketWrite, socketEnd)
|
||
|
|
||
|
if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) {
|
||
|
// accept the "options" Object as the 2nd argument
|
||
|
options = protocols
|
||
|
protocols = null
|
||
|
}
|
||
|
|
||
|
if (!options) options = {}
|
||
|
|
||
|
// browser only: sets the maximum socket buffer size before throttling
|
||
|
var bufferSize = options.browserBufferSize || 1024 * 512
|
||
|
|
||
|
// browser only: how long to wait when throttling
|
||
|
var bufferTimeout = options.browserBufferTimeout || 1000
|
||
|
|
||
|
// use existing WebSocket object that was passed in
|
||
|
if (typeof target === 'object') {
|
||
|
socket = target
|
||
|
// otherwise make a new one
|
||
|
} else {
|
||
|
// special constructor treatment for native websockets in browsers, see
|
||
|
// https://github.com/maxogden/websocket-stream/issues/82
|
||
|
if (isNative && isBrowser) {
|
||
|
socket = new WS(target, protocols)
|
||
|
} else {
|
||
|
socket = new WS(target, protocols, options)
|
||
|
}
|
||
|
|
||
|
socket.binaryType = 'arraybuffer'
|
||
|
}
|
||
|
|
||
|
// was already open when passed in
|
||
|
if (socket.readyState === 1) {
|
||
|
stream = proxy
|
||
|
} else {
|
||
|
stream = duplexify.obj()
|
||
|
socket.addEventListener("open", onready)
|
||
|
}
|
||
|
|
||
|
stream.socket = socket
|
||
|
|
||
|
socket.addEventListener("close", onclose)
|
||
|
socket.addEventListener("error", onerror)
|
||
|
socket.addEventListener("message", onmessage)
|
||
|
|
||
|
proxy.on('close', destroy)
|
||
|
|
||
|
function socketWriteNode(chunk, enc, next) {
|
||
|
socket.send(chunk, next)
|
||
|
}
|
||
|
|
||
|
function socketWriteBrowser(chunk, enc, next) {
|
||
|
if (socket.bufferedAmount > bufferSize) {
|
||
|
setTimeout(socketWriteBrowser, bufferTimeout, chunk, enc, next)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
socket.send(chunk)
|
||
|
} catch(err) {
|
||
|
return next(err)
|
||
|
}
|
||
|
|
||
|
next()
|
||
|
}
|
||
|
|
||
|
function socketEnd(done) {
|
||
|
socket.close()
|
||
|
done()
|
||
|
}
|
||
|
|
||
|
function onready() {
|
||
|
stream.setReadable(proxy)
|
||
|
stream.setWritable(proxy)
|
||
|
stream.emit('connect')
|
||
|
}
|
||
|
|
||
|
function onclose() {
|
||
|
stream.end();
|
||
|
stream.destroy()
|
||
|
}
|
||
|
|
||
|
function onerror(err) {
|
||
|
stream.destroy(err)
|
||
|
}
|
||
|
|
||
|
function onmessage(event) {
|
||
|
var data = event.data
|
||
|
if (data instanceof ArrayBuffer) data = new Buffer(new Uint8Array(data))
|
||
|
else data = new Buffer(data)
|
||
|
proxy.push(data)
|
||
|
}
|
||
|
|
||
|
function destroy() {
|
||
|
socket.close()
|
||
|
}
|
||
|
|
||
|
return stream
|
||
|
}
|