import randomName from 'chinese-random-name'; import fs from 'fs'; import path from 'path'; import WebSocket from 'ws'; import { Config, Error, HandlerConfig, Log, Protocol, ProtocolError, ProtocolInit, ProtocolLogs } from './type'; export enum LogLevel { Log = 1, Warn = 2, Error = 3 } export interface Handler { onServerStart(): void; onServerStop(): void; onClientConnected(id: string): void; onClientDisconnect(id: string): void; onClientLogMessage(id: string, logs: Log[]): void; onClientErrorMessage(id: string, error: Error): void; } export class Server { private readonly logHandler: Handler[]; private readonly port: number = null; private webSocketServer: WebSocket.Server = null; constructor() { const config: Config = JSON.parse(fs.readFileSync(path.join(__dirname, 'config', 'config.json')).toString()); this.port = config.port; this.logHandler = []; for (const handlerConfig of config.handlers) { const handlerModule: any = require(`./handler/${handlerConfig.name}/${handlerConfig.name}`); const handlerClass = handlerModule[handlerConfig.name] || handlerModule['default']; this.logHandler.push(new handlerClass(handlerConfig)); } } public start(): void { if (this.webSocketServer) { return; } this.logHandler.forEach(handler => handler.onServerStart()); this.webSocketServer = new WebSocket.Server({ port: this.port, host: '0.0.0.0' }); this.webSocketServer.on('connection', (ws: WebSocket) => this.handleClient(ws)); } public stop(): void { this.logHandler.forEach(handler => handler.onServerStop()); this.webSocketServer && this.webSocketServer.close(); this.webSocketServer = null; } private genClientID(): string { return randomName.generate(); } private handleClient(ws: WebSocket): Promise { const promise: Promise = new Promise((resolve: () => void) => { let clientID: string = null; let isClosed: boolean = false; const handlerMessage = (message: string | any): void => { if (!message) return; if (typeof message !== 'string') message = message.toString(); let data: Protocol = null; try { data = JSON.parse(message); } catch (error) { data = null }; if (!data) return; switch (data.type) { case 'init': let initData: ProtocolInit = null; try { initData = JSON.parse(data.data) } catch (error) { initData = null }; if (!initData) break; clientID = initData.id || this.genClientID(); this.logHandler.forEach(handler => handler.onClientConnected(clientID)); ws.send(clientID); break; case 'log': if (!clientID) break; let logData: ProtocolLogs = null; try { logData = JSON.parse(data.data); } catch (error) { logData = null }; if (!logData || !logData.logs) break; this.logHandler.forEach(handler => handler.onClientLogMessage(clientID, logData.logs)); break; case 'error': if (!clientID) break; let errorData: ProtocolError = null; try { errorData = JSON.parse(data.data); } catch (error) { errorData = null }; if (!errorData || !errorData.error) break; this.logHandler.forEach(handler => handler.onClientErrorMessage(clientID, errorData.error)); break; } } const onClose = (): void => { if (isClosed) return; isClosed = true; clientID && this.logHandler.forEach(handler => handler.onClientDisconnect(clientID)); resolve() } ws.on('message', (message: string) => handlerMessage(message)); ws.on('close', () => onClose()); ws.on('error', () => onClose()); }); return promise; } } new Server().start();