node-jet
Version:
Jet Realtime Message Bus for the Web. Daemon and Peer implementation.
120 lines (119 loc) • 3.65 kB
JavaScript
/* istanbul ignore file */
import { Socket, connect } from 'net';
import { EventEmitter } from './index.js';
/**
* Class Message socket
*/
export class MessageSocket extends EventEmitter {
last = Buffer.alloc(0);
len = -1;
socket;
constructor(port, ip = '') {
super();
if (port instanceof Socket) {
this.socket = port;
}
else {
this.socket = connect(port, ip);
this.socket.on('connect', () => {
this.emit('open');
});
}
this.socket.on('data', (buf) => {
let bigBuf = Buffer.concat([this.last, buf]);
while (true) {
if (this.len < 0) {
if (bigBuf.length < 4) {
this.last = bigBuf;
return;
}
else {
this.len = bigBuf.readUInt32BE(0);
bigBuf = bigBuf.subarray(4);
}
}
if (this.len > 0) {
if (bigBuf.length < this.len) {
this.last = bigBuf;
return;
}
else {
this.emit('message', bigBuf.toString(undefined, 0, this.len));
bigBuf = bigBuf.subarray(this.len);
this.len = -1;
}
}
}
});
this.socket.setNoDelay(true);
this.socket.setKeepAlive(true);
this.socket.once('close', () => {
this.emit('close');
});
this.socket.once('error', (e) => {
this.emit('error', e);
});
}
/**
* Send.
*/
send(msg) {
const utf8Length = Buffer.byteLength(msg, 'utf8');
const buf = Buffer.alloc(4 + utf8Length);
buf.writeUInt32BE(utf8Length, 0);
buf.write(msg, 4);
process.nextTick(() => {
this.socket.write(buf);
this.emit('sent', msg);
});
}
/**
* Close.
*/
close() {
this.socket.end();
}
/**
* addEventListener method needed for MessageSocket to be used in the browser.
* It is a wrapper for plain EventEmitter events like ms.on('...', callback).
*
* npm module 'ws' also comes with this method.
* See https://github.com/websockets/ws/blob/master/lib/WebSocket.js#L410
* That way we can use node-jet with via browserify inside the browser.
*/
addEventListener(method, listener) {
const onMessage = (data) => {
listener.call(this, new MessageEvent('data', { data }));
};
const onClose = (code, message) => {
listener.call(this, new CloseEvent(code, message));
};
const onError = (event) => {
listener.call(this, event);
};
const onOpen = () => {
listener.call(this, new Event('open'));
};
if (typeof listener === 'function') {
let cb;
switch (method) {
case 'message':
cb = onMessage;
break;
case 'close':
cb = onClose;
break;
case 'error':
cb = onError;
break;
case 'open':
cb = onOpen;
break;
default:
cb = listener;
}
this.on(method, cb);
}
}
}
export default MessageSocket;