drpc
Version:
Distributed RPC
151 lines (149 loc) • 4.71 kB
JavaScript
const net = require('net');
class TCP {
split(buffer) {
let tail = buffer.split('\r\n');
let head = tail.pop();
return {
head: head,
tail: tail
};
}
handshake(socket, message, server) {
try {
message = JSON.parse(message);
if (server) {
if (!(message.password && message.sname && message.password === this.password)) {
throw new Error();
}
if (message.sname === this.sname) {
// prevent self loop
throw new Error();
}
if (this.list[message.sname]) {
// prevent double connection
throw new Error();
}
socket.write(JSON.stringify({
sname: this.sname
}) + '\r\n');
} else {
if (!message.sname) {
throw new Error();
}
if (message.sname === this.sname) {
// prevent self loop
throw new Error();
}
if (this.list[message.sname]) {
// prevent double connection
throw new Error();
}
}
socket.sname = message.sname;
this.list[socket.sname] = socket;
this.drpc.emit('connect', socket.sname);
} catch (e) { }
}
close(socket) {
if (socket.sname) {
delete this.list[socket.sname];
this.drpc.emit('disconnect', socket.sname);
}
}
init(drpc, port, sname, password) {
this.drpc = drpc;
this.port = port;
this.sname = sname;
this.password = password;
this.list = {};
this.server = net.createServer((socket) => {
let buffer = '';
socket.on('data', (chunk) => {
buffer += chunk.toString();
let { head, tail } = this.split(buffer);
buffer = head;
for (let message of tail) {
if (socket.sname) {
this.drpc.emit('cast', socket.sname, message);
} else {
this.handshake.call(this, socket, message, true);
}
}
});
socket.on('close', () => {
this.close.call(this, socket);
});
setTimeout(() => {
if (!socket.sname) {
socket.destroy();
}
}, 5000);
});
this.server.on('listening', () => {
this.drpc.emit('start');
});
this.server.on('error', (error) => {
this.drpc.emit('error', error);
});
this.server.on('close', () => {
this.drpc.emit('stop');
});
}
start() {
this.server.listen(this.port, '127.0.0.1');
}
stop() {
for (let name of Object.keys(this.list)) {
this.list[name].destroy();
delete this.list[name];
}
this.server.close();
}
connect(host, port, password) {
let socket = net.createConnection(port, host, () => {
let buffer = '';
socket.on('data', (chunk) => {
buffer += chunk.toString();
let { head, tail } = this.split(buffer);
buffer = head;
for (let message of tail) {
if (socket.sname) {
this.drpc.emit('cast', socket.sname, message);
} else {
this.handshake.call(this, socket, message, false);
}
}
});
socket.on('close', () => {
this.close.call(this, socket);
});
socket.write(JSON.stringify({
password: this.password,
sname: this.sname
}) + '\r\n');
});
}
disconnect(sname) {
this.list[sname].destroy();
}
broadcast(message) {
for (let socket of Object.values(this.list)) {
socket.write(message + '\r\n');
}
}
multicast(snames, message) {
for (let sname of snames) {
let socket = this.list[sname];
if (socket) {
socket.write(message + '\r\n');
}
}
}
unicast(sname, message) {
let socket = this.list[sname];
if (socket) {
socket.write(message + '\r\n');
}
}
}
exports.TCP = TCP;