UNPKG

mihawk

Version:

A tiny & simple mock server tool, support json,js,cjs,ts(typescript).

239 lines (238 loc) 12.6 kB
'use strict'; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const https_1 = __importDefault(require("https")); const http_1 = __importDefault(require("http")); const util_1 = require("util"); const color_cc_1 = __importDefault(require("color-cc")); const WS = __importStar(require("ws")); const consts_1 = require("../consts"); const parser_1 = require("../utils/parser"); const print_1 = require("../utils/print"); const date_1 = require("../utils/date"); const server_1 = require("../utils/server"); const net_1 = require("../utils/net"); const LOGFLAG_WS = `${color_cc_1.default.cyan('[WS]')}${color_cc_1.default.gray(':')}`; class WsCtrl { constructor(options) { this._clientIndex = 0; const { host, port, secure = false, server, stomp = false, resolve = _defaultResolveFunc, } = options; this._useStompMsg = !!stomp; this._host = host; this._port = port; this._secure = secure; this._wsSvr = null; this._baseServer = server; const _resolve = typeof resolve === 'function' ? resolve : _defaultResolveFunc; this._resolveFunc = function (socket, request, options) { try { const funcCtx = socket; _resolve.call(funcCtx, socket, request, options); } catch (error) { print_1.Printer.error(LOGFLAG_WS, 'Failed to exec socket logic resolveFunc:\n', error); } }; } _autoCreateClientId() { return `Client-${++this._clientIndex}__${(0, date_1.getTimeNowStr)()}`; } start(server, isRestart) { return __awaiter(this, void 0, void 0, function* () { if (this._wsSvr) { print_1.Printer.log(LOGFLAG_WS, 'WS server is already running.'); return; } const resolveFunc = this._resolveFunc; const stomp = this._useStompMsg; if (server && _isHttpOrHttpsServer(server)) { this._baseServer = server; } const { isSecure = this._secure, host = this._host, port = this._port } = _getBaseServerInfo(this._baseServer); const protocol = isSecure ? 'wss' : 'ws'; const hostFix = host === '0.0.0.0' ? '127.0.0.1' : host; this._wsSvr = new WS.WebSocketServer({ server: this._baseServer }); this._wsSvr.on('listening', function listening() { print_1.Printer.log(`🚀 ${color_cc_1.default.green(`${isRestart ? 'Restart' : 'Start'} mock-socket-server success!`)}`); !isRestart && print_1.Printer.log(`Mock Socket Server address:`); print_1.Printer.log(`${color_cc_1.default.gray('-')} ${color_cc_1.default.cyan(`${protocol}://${hostFix}:${port}`)}`); if ((0, net_1.supportLocalHost)(host)) { const addr2 = `${protocol}://${(0, net_1.getMyIp)()}:${port}`; print_1.Printer.log(`${color_cc_1.default.gray('-')} ${color_cc_1.default.cyan(addr2)}`); } console.log(); }); this._wsSvr.on('headers', function headers(headers, req) { headers.push(`X-Powered-By: ${consts_1.PKG_NAME}`); }); this._wsSvr.on('connection', (socket, request) => { const { remoteAddress, remotePort } = (request === null || request === void 0 ? void 0 : request.socket) || {}; const clientId = remoteAddress ? `${remoteAddress}:${remotePort || ++this._clientIndex}` : this._autoCreateClientId(); print_1.Printer.log(LOGFLAG_WS, 'Socket client connected!', color_cc_1.default.gray(`clientId=[${clientId}]`), color_cc_1.default.gray(`time=${(0, date_1.getTimeNowStr)()}`)); resolveFunc(socket, request, { clientId, stomp }); setTimeout(() => { const clientId4Log = color_cc_1.default.gray(`clientId=[${clientId}]`); const timeNow4Log = color_cc_1.default.gray(`time=${(0, date_1.getTimeNowStr)()}`); if (this._wsSvr) { try { socket === null || socket === void 0 ? void 0 : socket.emit('open', () => { print_1.Printer.log(LOGFLAG_WS, "Socket client opened! (socket.emit('open') success!)", clientId4Log, timeNow4Log); }); } catch (error) { print_1.Printer.error(LOGFLAG_WS, "Failed to exec socket.emit('open') ! ", clientId4Log, timeNow4Log, '\n', error); } } else { print_1.Printer.warn(LOGFLAG_WS, "Cancel to exec socket.emit('open'), because connection is closed.", clientId4Log, timeNow4Log); } }, 0); }); this._wsSvr.on('error', function error(err) { print_1.Printer.error(LOGFLAG_WS, 'WebSocket server error:', err); }); this._wsSvr.on('close', function close() { }); }); } _close(forceClose = false) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this._wsSvr) { print_1.Printer.log(LOGFLAG_WS, 'WebSocket server is not running.'); return; } const clients = (_a = this._wsSvr) === null || _a === void 0 ? void 0 : _a.clients; try { if (clients === null || clients === void 0 ? void 0 : clients.size) { if (forceClose) { clients === null || clients === void 0 ? void 0 : clients.forEach(client => client === null || client === void 0 ? void 0 : client.terminate()); } else { clients === null || clients === void 0 ? void 0 : clients.forEach(client => client === null || client === void 0 ? void 0 : client.close()); } } } catch (error) { print_1.Printer.error(LOGFLAG_WS, `Batch ${forceClose ? 'terminate' : 'close'} clients failed!\n`, error); } const closeAsync = (0, util_1.promisify)(this._wsSvr.close).bind(this._wsSvr); try { yield closeAsync(); this._wsSvr = null; } catch (error) { print_1.Printer.error(LOGFLAG_WS, `${forceClose ? 'Destory' : 'Close'} WebSocket server failed!\n`, error); } }); } close() { return __awaiter(this, void 0, void 0, function* () { return yield this._close(); }); } destory() { return __awaiter(this, void 0, void 0, function* () { return yield this._close(true); }); } } exports.default = WsCtrl; function _defaultResolveFunc(socket, request, options) { const { clientId: cid, stomp } = options || {}; const clientId = cid || request.socket.remoteAddress; const clientName = `[${clientId}]`; const logTail = color_cc_1.default.gray(`from ${clientName}`); const logName = color_cc_1.default.gray('socket:'); socket.send(JSON.stringify({ success: true, data: `WsServer: Connection established! Hello, client! ${clientName}` })); socket.on('message', (message, isBinary) => { const recived = typeof message === 'string' ? message : Buffer.isBuffer(message) ? message === null || message === void 0 ? void 0 : message.toString() : JSON.stringify(message); let recivedData = recived; if (stomp) { recivedData = (0, parser_1.parseStompMsg)(recived); print_1.Printer.log(LOGFLAG_WS, logName, 'Received stomp message', logTail); print_1.Printer.log(LOGFLAG_WS, logName, '<= stompData:', recivedData); } else { print_1.Printer.log(LOGFLAG_WS, logName, `Received message <= "${color_cc_1.default.green(recived)}"`, isBinary ? color_cc_1.default.gray('binary') : '', logTail); } const recivedDataStr = typeof recivedData === 'string' ? recivedData : JSON.stringify(recivedData); const msgData = { success: true, data: `WsServer: I've recived your message(${recivedDataStr})`, }; print_1.Printer.log(LOGFLAG_WS, logName, `Send response to ${color_cc_1.default.gray(clientName)} =>`, msgData); socket.send(JSON.stringify(msgData)); console.log('\n'); }); socket.on('open', () => { print_1.Printer.log(LOGFLAG_WS, logName, `Client ${color_cc_1.default.gray(clientId)} open.`, logTail); }); socket.on('upgrade', (request) => { const clientAddr = request.socket.remoteAddress; print_1.Printer.log(LOGFLAG_WS, logName, `Client ${clientAddr} upgraded.`, logTail); }); socket.on('ping', (data) => { print_1.Printer.log(LOGFLAG_WS, logName, `Received ping => ${(data === null || data === void 0 ? void 0 : data.toString()) || ''}`, logTail); socket.pong(`Pong: ${data === null || data === void 0 ? void 0 : data.toString()}`); }); socket.on('pong', (data) => { print_1.Printer.log(LOGFLAG_WS, logName, `Received pong => ${(data === null || data === void 0 ? void 0 : data.toString()) || ''}`, logTail); }); socket.on('error', (err) => { const errMsg = (err === null || err === void 0 ? void 0 : err.message) || (err === null || err === void 0 ? void 0 : err.toString()) || 'unknow error'; print_1.Printer.error(LOGFLAG_WS, logName, `CLient error: ${color_cc_1.default.red(errMsg)}`, logTail); print_1.Printer.error(LOGFLAG_WS, err, '\n'); }); socket.on('unexpected-response', (request, response) => { const exceptDetail = `${response.statusCode} ${response.statusMessage}`; print_1.Printer.error(LOGFLAG_WS, logName, `CLient unexpected-response: ${color_cc_1.default.red(exceptDetail)}`, logTail, '\n'); }); socket.on('close', (code, reason) => { const closeDetail = `code=${code},reason=${reason.toString() || 'none'}`; print_1.Printer.log(LOGFLAG_WS, logName, `Client close connection.(${color_cc_1.default.yellow(closeDetail)})`, logTail, '\n'); }); } function _getBaseServerInfo(server) { const isSecure = server instanceof https_1.default.Server; const protocol = isSecure ? 'https' : 'http'; const { port, address } = (0, server_1.getAddrInfoByServer)(server) || {}; return { isSecure, protocol, host: address, port }; } function _isHttpOrHttpsServer(server) { return server instanceof http_1.default.Server || server instanceof https_1.default.Server; }