UNPKG

protoobject

Version:

A universal class for creating any JSON objects and simple manipulations with them.

317 lines 12.2 kB
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); }; import { createServer, createConnection } from "node:net"; import { EventEmitter } from "node:events"; import { ProtoObject } from "./proto-object.js"; import { StaticImplements } from "../decorators/static-implements.js"; /* eslint-disable no-unused-vars */ /** * Message types for TCP communication */ export var MessageType; (function (MessageType) { MessageType["REQUEST"] = "REQUEST"; MessageType["RESPONSE"] = "RESPONSE"; MessageType["NOTIFICATION"] = "NOTIFICATION"; MessageType["ERROR"] = "ERROR"; })(MessageType || (MessageType = {})); /* eslint-enable no-unused-vars */ /** * TCP Server for ProtoObject communication */ export class ProtoObjectTCPServer extends EventEmitter { /* eslint-disable no-unused-vars */ constructor(port = 3000) { super(); this.port = port; this.clients = new Map(); this.server = createServer(); this.setupServer(); } /* eslint-enable no-unused-vars */ setupServer() { this.server.on("connection", (socket) => { const clientId = `${socket.remoteAddress}:${socket.remotePort}`; this.clients.set(clientId, socket); console.log(`Client connected: ${clientId}`); this.emit("clientConnected", clientId, socket); socket.on("data", (buffer) => { try { const messages = this.parseMessages(buffer); messages.forEach((message) => { this.emit("message", clientId, message); }); } catch (error) { this.emit("error", error); } }); socket.on("close", () => { this.clients.delete(clientId); console.log(`Client disconnected: ${clientId}`); this.emit("clientDisconnected", clientId); }); socket.on("error", (error) => { this.emit("error", error); }); }); } parseMessages(buffer) { const messages = []; let offset = 0; while (offset < buffer.length) { // Read message length (4 bytes) if (offset + 4 > buffer.length) break; const messageLength = buffer.readUInt32BE(offset); offset += 4; // Read message data if (offset + messageLength > buffer.length) break; const messageData = buffer.subarray(offset, offset + messageLength); offset += messageLength; try { const message = JSON.parse(messageData.toString()); messages.push(message); } catch (error) { console.error("Error parsing message:", error); } } return messages; } start() { return new Promise((resolve, reject) => { this.server.listen(this.port, (error) => { if (error) { reject(error); } else { console.log(`TCP Server listening on port ${this.port}`); resolve(); } }); }); } stop() { return new Promise((resolve) => { this.server.close(() => { console.log("TCP Server stopped"); resolve(); }); }); } sendToClient(clientId, object, type = MessageType.NOTIFICATION) { const socket = this.clients.get(clientId); if (!socket) return false; const message = { id: this.generateId(), type, timestamp: Date.now(), data: object.toJSON(), }; return this.sendMessage(socket, message); } broadcast(object, type = MessageType.NOTIFICATION) { const message = { id: this.generateId(), type, timestamp: Date.now(), data: object.toJSON(), }; this.clients.forEach((socket) => { this.sendMessage(socket, message); }); } sendMessage(socket, message) { try { const messageData = Buffer.from(JSON.stringify(message)); const lengthBuffer = Buffer.allocUnsafe(4); lengthBuffer.writeUInt32BE(messageData.length, 0); socket.write(Buffer.concat([lengthBuffer, messageData])); return true; } catch (error) { console.error("Error sending message:", error); return false; } } generateId() { return Math.random().toString(36).substring(2) + Date.now().toString(36); } getConnectedClients() { return Array.from(this.clients.keys()); } } /** * TCP Client for ProtoObject communication */ export class ProtoObjectTCPClient extends EventEmitter { /* eslint-disable no-unused-vars */ constructor(host = "localhost", port = 3000) { super(); this.host = host; this.port = port; this.socket = null; this.messageBuffer = Buffer.alloc(0); } /* eslint-enable no-unused-vars */ connect() { return new Promise((resolve, reject) => { this.socket = createConnection(this.port, this.host); this.socket.on("connect", () => { console.log(`Connected to server ${this.host}:${this.port}`); this.emit("connected"); resolve(); }); this.socket.on("data", (buffer) => { this.messageBuffer = Buffer.concat([this.messageBuffer, buffer]); this.processMessages(); }); this.socket.on("close", () => { console.log("Disconnected from server"); this.emit("disconnected"); }); this.socket.on("error", (error) => { this.emit("error", error); reject(error); }); }); } processMessages() { let offset = 0; while (offset + 4 <= this.messageBuffer.length) { const messageLength = this.messageBuffer.readUInt32BE(offset); if (offset + 4 + messageLength > this.messageBuffer.length) { break; // Wait for more data } const messageData = this.messageBuffer.subarray(offset + 4, offset + 4 + messageLength); try { const message = JSON.parse(messageData.toString()); this.emit("message", message); } catch (error) { console.error("Error parsing message:", error); } offset += 4 + messageLength; } this.messageBuffer = this.messageBuffer.subarray(offset); } send(object, type = MessageType.REQUEST) { if (!this.socket) return false; const message = { id: this.generateId(), type, timestamp: Date.now(), data: object.toJSON(), }; try { const messageData = Buffer.from(JSON.stringify(message)); const lengthBuffer = Buffer.allocUnsafe(4); lengthBuffer.writeUInt32BE(messageData.length, 0); this.socket.write(Buffer.concat([lengthBuffer, messageData])); return true; } catch (error) { console.error("Error sending message:", error); return false; } } disconnect() { if (this.socket) { this.socket.end(); this.socket = null; } } generateId() { return Math.random().toString(36).substring(2) + Date.now().toString(36); } } /** * Base class for TCP-enabled ProtoObjects */ let ProtoObjectTCP = (() => { let _classDecorators = [StaticImplements()]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = ProtoObject; var ProtoObjectTCP = _classThis = class extends _classSuper { constructor(data) { super(data); } /** * Send this object through TCP client */ sendTCP(client, type = MessageType.REQUEST) { return client.send(this, type); } /** * Broadcast this object through TCP server */ broadcastTCP(server, type = MessageType.NOTIFICATION) { server.broadcast(this, type); } /** * Send this object to specific client through TCP server */ sendToClientTCP(server, clientId, type = MessageType.RESPONSE) { return server.sendToClient(clientId, this, type); } /** * Create object from TCP message */ static fromTCPMessage(message) { return this.fromJSON(message.data); } }; __setFunctionName(_classThis, "ProtoObjectTCP"); (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); ProtoObjectTCP = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); })(); return ProtoObjectTCP = _classThis; })(); export { ProtoObjectTCP }; //# sourceMappingURL=proto-object-tcp.js.map