UNPKG

tcp2

Version:

A Wrapper of Node.JS' net API

199 lines (157 loc) 6.23 kB
const net = require("net"); const Events = require("@evodev/eventemitter"); const cuid = require("cuid"); const v8 = require("v8"); const Socket = require(`${__dirname}/socket.js`); const splitBytes = require(`${__dirname}/splitBytes.js`); const childProcess = require("child_process"); module.exports = class TCP2 extends Events { constructor(socket = true, server = true, settings = { maxBytes: 1024*1024 }) { super(); this.settings = settings; this.eventMessage = new Events; if (socket) { this.createSocket(); } if (server) { this.createServer(); } } disconnect() { if (!this.socketFork) throw new ReferenceError(`Socket is disabled`); this.socketFork.send(v8.serialize(['end'])); } createServer() { this.server = new net.Server; this.connections = {}; this.serverMessages = {}; this.server.on("error", e => this.emit(`server.error`, e)); this.server.on("listening", () => this.emit(`server.listening`)); this.server.on("connection", socket => { const id = cuid(); const connection = new Socket(socket, id, this.serverMessages); const messages = {}; this.connections[id] = connection; socket.on("close", () => { delete this.connections[id]; connection.emit(`disconnect`); }); socket.on("error", e => { if (!this.connections[id]) return; this.emit(`server.connection.error`, e); connection.emit(`error`, e); }); this.emit(`server.connection`, connection); socket.write(Buffer.from(`ID-${id}`)); socket.on("data", msg => { this.emit(`server.message_raw`, connection, msg); connection.emit(`message_raw`, msg); if (!Buffer.isBuffer(msg)) return; const string = msg.toString(); const msgs = string.split("\n"); for (let _msg_ of msgs) { const _ = _msg_.split("-"); try { const id = _[1]; //console.log(id, _, messages); switch (_[0]) { case "CREATE": { if (messages[id]) break; const event = Buffer.from(_[2].split(",")).toString(); messages[id] = { event, buffer: Buffer.alloc(0) }; break; } case "NOT ACCEPTED": { if (!this.serverMessages[id]) break; this.serverMessages[id].reject(_[2]); break; } case "RECEIVED": { if (!this.serverMessages[id]) break; this.serverMessages[id].resolve(id); break; } case "CONTENT": { if (!messages[id]) break; const buffer = Buffer.from(_[2].split(",")); messages[id].buffer = Buffer.concat([messages[id].buffer, buffer]); break; } case "END": { if (!messages[id]) break; const msg = v8.deserialize(messages[id].buffer); if (!Array.isArray(msg)) break; connection.eventMessage.emit(messages[id].event, { content: msg, id }); socket.write(Buffer.from(`RECEIVED-${id}`)); delete messages[id]; break; } } } catch {} } }); }); } createSocket() { this.socketFork = childProcess.fork(`${__dirname}/client.js`); this.socketID = null; this.socketMessages = {}; this.socketFork.send(v8.serialize(['settings', this.settings])); this.socketFork.on("exit", () => { this.createSocket(); this.emit(`socket.afterExit`); }); this.socketFork.on("message", msg => { const m = v8.deserialize(Buffer.from(msg.data)); //console.log(m); switch(m[0]) { case "socketMessages": { this.socketMessages[m[1]][m[2]](m[3] || m[1]); break; } case "id": { this.socketID = m[1]; } case "main": { this.emit(m[1], ...m.slice(2, Infinity)); break; } case "eventMessage": { this.eventMessage.emit(m[1], ...m.slice(2, Infinity)); break; } } }); } listen(ip = '127.0.0.1', port = 1337, callback) { if (!this.server) throw new ReferenceError(`Server is disabled`); return this.server.listen(port, ip, callback); } connect(ip = '127.0.0.1', port = 1337) { if (!this.socketFork) throw new ReferenceError(`Socket is disabled`); this.socketFork.send(v8.serialize(['connect', ip, port])); } send(event, ...messages) { if (!messages.length) throw new TypeError(`messages cannot be empty`); if (typeof event !== "string") throw new TypeError(`event can only be a string`); const msgID = cuid(); this.socketFork.send(v8.serialize(['send', event, messages, msgID])); return new Promise((resolve, reject) => { this.socketMessages[msgID] = { resolve, reject }; }); } onmessage(event, callback) { return this.eventMessage.on(event, callback); } sendToAll(event, ...messages) { const promises = []; for (let connection of Object.values(this.connections)) promises.push(connection.send(event, ...messages)); return promises; } };