UNPKG

mydog

Version:

a framework of typescript game server

964 lines (963 loc) 33.3 kB
#!/usr/bin/env node "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; }; Object.defineProperty(exports, "__esModule", { value: true }); const path = __importStar(require("path")); const fs = __importStar(require("fs")); const readline = __importStar(require("readline")); const child_process_1 = require("child_process"); const define = __importStar(require("./util/define")); const msgCoder = __importStar(require("./components/msgCoder")); const tcpClient_1 = require("./components/tcpClient"); let version = require('../package.json').version; let DEFAULT_MASTER_HOST = '127.0.0.1'; let DEFAULT_MASTER_PORT = 3005; let FILEREAD_ERROR = 'Fail to read the file, please check if the application is started legally.'; let waitInterval = null; //#region some class class clientProxy { constructor(host, port, token, cb) { this.reqId = 1; this.reqs = {}; this.needAbort = true; this.heartbeatTimeout = null; this.token = token; this.connect_cb = cb; this.socket = new tcpClient_1.TcpClient(port, host, define.some_config.SocketBufferMaxLen, true, this.connectCb.bind(this)); this.socket.on("data", (buf) => { let data = JSON.parse(buf.toString()); let reqId = data.reqId; let req = this.reqs[reqId]; if (!req) { return; } delete this.reqs[reqId]; clearTimeout(req.timeOut); req.cb(null, data.msg); }); this.socket.on("close", (err) => { clearTimeout(this.heartbeatTimeout); if (this.needAbort) { abort(err); } }); } connectCb() { // register let loginInfo = { T: 1 /* define.Cli_To_Master.register */, cliToken: this.token }; let loginInfo_buf = msgCoder.encodeInnerData(loginInfo); this.socket.send(loginInfo_buf); this.heartbeat(); clearWait(); this.connect_cb(this); } heartbeat() { let self = this; this.heartbeatTimeout = setTimeout(function () { let heartBeatMsg = { T: 2 /* define.Cli_To_Master.heartbeat */ }; let heartBeatMsg_buf = msgCoder.encodeInnerData(heartBeatMsg); self.socket.send(heartBeatMsg_buf); self.heartbeat(); }, define.some_config.Time.Monitor_Heart_Beat_Time * 1000); } request(msg, timeout, cb) { let reqId = this.reqId++; let data = { "T": 3 /* define.Cli_To_Master.cliMsg */, "reqId": reqId, "msg": msg }; let buf = msgCoder.encodeInnerData(data); this.socket.send(buf); let self = this; this.reqs[reqId] = { "cb": cb, "timeOut": setTimeout(function () { delete self.reqs[reqId]; cb("time out"); }, timeout * 1000) }; } close(needAbort = true) { this.needAbort = needAbort; this.socket.close(); } } class Commond { constructor() { this.baseName = ""; this.ver = ""; this.cmdArr = []; } setNameVersion(baseName, ver) { this.baseName = baseName; this.ver = ver; } addCommond(cmd) { for (let one of this.cmdArr) { if (one.name === cmd.name) { console.log(`\n Error: [Cmd already exists] cmd -> ${cmd.name}\n`); process.exit(); } } for (let i = 0; i < cmd.options.length; i++) { let one = cmd.options[i]; for (let j = i + 1; j < cmd.options.length; j++) { let two = cmd.options[j]; if (two.opt === one.opt) { console.log(`\n Error: [Option.opt already exists] cmd -> ${cmd.name}, opt -> ${one.opt}\n`); process.exit(); } if (two.name === one.name) { console.log(`\n Error: [Option.name already exists] cmd -> ${cmd.name}, name -> ${one.name}\n`); process.exit(); } } } this.cmdArr.push(cmd); } parse() { let argvArr = [...process.argv]; argvArr.splice(0, 2); if (!argvArr.length) { this.print_help(); return; } let cmdName = argvArr[0]; if (["-h", "-H", "--help"].includes(cmdName)) { this.print_help(); return; } if (["-v", "-V", "--version"].includes(cmdName)) { console.log(`\n Version: ${this.ver}\n`); return; } if (cmdName === "des") { this.print_des(argvArr[1]); return; } this.parseCmd(cmdName, argvArr); } parseCmd(cmdName, argvArr) { let cmd = null; for (let one of this.cmdArr) { if (one.name === cmdName) { cmd = one; break; } } if (!cmd) { console.log(`\n Error: [Cmd not exists] ${cmdName}\n`); return; } if (argvArr.includes("--help")) { this.print_des(cmdName); return; } let keyDic = {}; let otherArr = []; for (let i = 1; i < argvArr.length;) { let str = argvArr[i]; if (!str.startsWith("-")) { otherArr.push(str); i += 1; continue; } let option = null; for (let one of cmd.options) { if (one.opt === str) { option = one; break; } } if (!option) { console.log(`\n Error: [No such option] ${str}\n`); process.exit(); } if (option.type === "bool") { keyDic[option.name] = true; i += 1; continue; } if (option.type === "string") { let str2 = argvArr[i + 1]; if (!str2 || str2.startsWith("-")) { console.log(`\n Error: [Wrong option input] ${str} ${str2 || ""}\n`); process.exit(); } keyDic[option.name] = str2; i += 2; continue; } if (option.type === "number") { let str2 = argvArr[i + 1]; if (!str2 || str2.startsWith("-")) { console.log(`\n Error: [Wrong option input] ${str} ${str2 || ""}\n`); process.exit(); } let numVal = Number(str2); if (isNaN(numVal)) { console.log(`\n Error: [Wrong option input] ${str} ${str2 || ""}\n`); process.exit(); } keyDic[option.name] = numVal; i += 2; continue; } } for (let one of cmd.options) { if (keyDic[one.name] !== undefined) { continue; } if (one.type === "bool") { continue; } if (one.mustNeed) { console.log(`\n Error: [Need option] ${one.opt}\n`); process.exit(); } else if (one.default !== undefined) { keyDic[one.name] = one.default; } } cmd.cb(keyDic, otherArr); } print_help() { console.log(""); console.log(` Version: ${this.ver}`); console.log(" Usage:"); let defaultArr = []; defaultArr.push(["-v", "show the version"]); defaultArr.push(["-h", "list the commonds"]); defaultArr.push(["des [command]", "describe the command"]); this.printArr(defaultArr); console.log("\n Commands:"); let arr = []; for (let one of this.cmdArr) { arr.push([one.name + (one.options.length ? " [options]" : ""), one.des]); } this.printArr(arr); console.log(""); } print_des(cmdName) { let cmd = null; for (let one of this.cmdArr) { if (one.name === cmdName) { cmd = one; break; } } if (!cmd) { console.log(`\n Error: [Cmd not exists] cmd -> ${cmdName}\n`); return; } console.log(``); console.log(` Cmd: ${this.baseName} ${cmd.name}`); console.log(` Des: ${cmd.des}`); if (cmd.usage) { console.log(` Usage: ${cmd.usage}`); } console.log(` Options:`); let arr = []; for (let one of cmd.options) { let tmpDes = one.des; if (!one.mustNeed && one.type !== "bool" && one.default !== undefined) { if (one.type === "string") { tmpDes += ` (default: "${one.default}")`; } else { tmpDes += ` (default: ${one.default})`; } } arr.push([one.opt, one.type === "bool" ? "" : `${one.name} [${one.type}]`, tmpDes, one.mustNeed ? "√" : ""]); } this.printArr(arr); console.log(""); } printArr(arr) { let widthArr = []; let maxWidthArr = []; for (let i = 0; i < arr.length; i++) { let one = arr[i]; let tmpArr = []; for (let j = 0; j < one.length; j++) { let len = this.getDisplayLength(one[j]); tmpArr.push(len); if (len >= (maxWidthArr[j] || 0)) { maxWidthArr[j] = len; } } widthArr.push(tmpArr); } for (let i = 0; i < maxWidthArr.length; i++) { maxWidthArr[i] += 5; } for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr[i].length; j++) { arr[i][j] += " ".repeat(maxWidthArr[j] - widthArr[i][j]); } console.log(" ", arr[i].join("")); } } getDisplayLength(str) { let realLength = 0, len = str.length, charCode = -1; for (var i = 0; i < len; i++) { charCode = str.charCodeAt(i); if (charCode >= 0 && charCode <= 128) { realLength += 1; } else { realLength += 2; } } return realLength; } } //#endregion //#region add commond let commond = new Commond(); commond.setNameVersion("mydog", version); commond.addCommond({ "name": "init", "des": "create a new application", "options": [], "usage": "", "cb": () => { cli_init(); } }); commond.addCommond({ "name": "start", "des": "start the application", "options": [ { "opt": "-e", "name": "env", "des": "the used environment", "mustNeed": false, "type": "string", "default": "development" }, { "opt": "-d", "name": "daemon", "des": "enable the daemon start", "mustNeed": false, "type": "bool" }, ], "usage": "mydog start -e env [serverId-1 ...]", "cb": (opts, argv) => { opts.serverIds = argv; cli_start(opts); } }); commond.addCommond({ "name": "list", "des": "list the servers", "options": [ { "opt": "-h", "name": "host", "des": "master server host", "mustNeed": false, "type": "string", "default": DEFAULT_MASTER_HOST }, { "opt": "-p", "name": "port", "des": "master server port", "mustNeed": false, "type": "number", "default": DEFAULT_MASTER_PORT }, { "opt": "-t", "name": "token", "des": "cli token", "mustNeed": false, "type": "string", "default": define.some_config.Cli_Token }, { "opt": "-i", "name": "interval", "des": "request interval", "mustNeed": false, "type": "number", "default": 5 }, ], "usage": "", "cb": (opts) => { cli_list(opts); } }); commond.addCommond({ "name": "stop", "des": "stop the servers", "options": [ { "opt": "-h", "name": "host", "des": "master server host", "mustNeed": false, "type": "string", "default": DEFAULT_MASTER_HOST }, { "opt": "-p", "name": "port", "des": "master server port", "mustNeed": false, "type": "number", "default": DEFAULT_MASTER_PORT }, { "opt": "-t", "name": "token", "des": "cli token", "mustNeed": false, "type": "string", "default": define.some_config.Cli_Token }, ], "usage": "", "cb": (opts) => { cli_stop(opts); } }); commond.addCommond({ "name": "remove", "des": "remove some servers", "options": [ { "opt": "-h", "name": "host", "des": "master server host", "mustNeed": false, "type": "string", "default": DEFAULT_MASTER_HOST }, { "opt": "-p", "name": "port", "des": "master server port", "mustNeed": false, "type": "number", "default": DEFAULT_MASTER_PORT }, { "opt": "-t", "name": "token", "des": "cli token", "mustNeed": false, "type": "string", "default": define.some_config.Cli_Token }, ], "usage": "mydog remove serverId-1 [serverId-2 ...]", "cb": (opts, argv) => { opts.serverIds = argv; cli_remove(opts); } }); commond.addCommond({ "name": "removeT", "des": "remove some serverTypes", "options": [ { "opt": "-h", "name": "host", "des": "master server host", "mustNeed": false, "type": "string", "default": DEFAULT_MASTER_HOST }, { "opt": "-p", "name": "port", "des": "master server port", "mustNeed": false, "type": "number", "default": DEFAULT_MASTER_PORT }, { "opt": "-t", "name": "token", "des": "cli token", "mustNeed": false, "type": "string", "default": define.some_config.Cli_Token }, ], "usage": "mydog removeT serverType-1 [serverType-2 ...]", "cb": (opts, argv) => { opts.serverTypes = argv; cli_removeT(opts); } }); commond.addCommond({ "name": "cmd", "des": "build cmd file", "options": [], "usage": "mydog cmd [ts cs ...]", "cb": (opts, argv) => { cli_cmd(argv); } }); commond.addCommond({ "name": "send", "des": "send msg to mydog", "options": [ { "opt": "-h", "name": "host", "des": "master server host", "mustNeed": false, "type": "string", "default": DEFAULT_MASTER_HOST }, { "opt": "-p", "name": "port", "des": "master server port", "mustNeed": false, "type": "number", "default": DEFAULT_MASTER_PORT }, { "opt": "-t", "name": "token", "des": "cli token", "mustNeed": false, "type": "string", "default": define.some_config.Cli_Token }, { "opt": "-id", "name": "serverId", "des": "serverId will get msg", "mustNeed": false, "type": "string" }, { "opt": "-svrT", "name": "serverType", "des": "serverType will get msg", "mustNeed": false, "type": "string" }, ], "usage": "mydog send [-id id1,id2] [-svrT svrT1,svrT2] [argv0 argv1...]", "cb": (opts, argv) => { cli_send(opts, argv); } }); commond.parse(); //#endregion //#region some func function cli_init() { let pathStr = process.cwd(); emptyDirectory(pathStr, function (empty) { if (empty) { createApplicationAt(pathStr); } else { confirm('Destination is not empty, continue? (y/n) [no] ', function (force) { if (force) { createApplicationAt(pathStr); } else { abort('[ canceled ]'); } }); } }); function createApplicationAt(ph) { copy(path.join(__dirname, '../template'), ph); function copy(origin, target) { if (!fs.existsSync(origin)) { abort(origin + 'does not exist.'); } if (!fs.existsSync(target)) { fs.mkdirSync(target); console.log(' create : ' + target); } fs.readdir(origin, function (err, datalist) { if (err) { abort(FILEREAD_ERROR); } for (let i = 0; i < datalist.length; i++) { let oCurrent = path.resolve(origin, datalist[i]); let tCurrent = path.resolve(target, datalist[i]); if (fs.statSync(oCurrent).isFile()) { fs.writeFileSync(tCurrent, fs.readFileSync(oCurrent, ''), ''); console.log(' create : ' + tCurrent); } else if (fs.statSync(oCurrent).isDirectory()) { copy(oCurrent, tCurrent); } } }); } } function emptyDirectory(path, fn) { fs.readdir(path, function (err, files) { if (err && 'ENOENT' !== err.code) { abort(FILEREAD_ERROR); } fn(!files || !files.length); }); } } function cli_start(opts) { let absScript = path.resolve(process.cwd(), 'app.js'); if (!fs.existsSync(absScript)) { absScript = path.resolve(process.cwd(), '../dist/app.js'); if (!fs.existsSync(absScript)) { abort(" -> Not find the script: " + absScript); } } opts.env = opts.env || "development"; opts.daemon = !!opts.daemon; if (opts.serverIds.length === 0) { startSvr([absScript, 'env=' + opts.env, "daemon=" + opts.daemon]); } else { let serverIds = []; for (let id of opts.serverIds) { serverIds.push(...parseServerId(id)); } serverIds = Array.from(new Set(serverIds)); for (let id of serverIds) { startSvr([absScript, 'env=' + opts.env, "daemon=" + opts.daemon, "id=" + id]); } } if (opts.daemon) { console.log('The application is running in the background now.\n'); process.exit(0); } function startSvr(params) { let ls; if (opts.daemon) { ls = (0, child_process_1.spawn)(process.execPath, params, { detached: true, stdio: 'ignore' }); ls.unref(); } else { ls = (0, child_process_1.spawn)(process.execPath, params); ls.stdout.on('data', function (data) { console.log(data.toString()); }); ls.stderr.on('data', function (data) { console.log(data.toString()); }); } } } function cli_list(opts) { let interval = Math.ceil(opts.interval); if (interval < 1) { interval = 1; } connectToMaster(opts.host, opts.port, opts.token, function (client) { console.log(""); requestList(); let rowNum = 0; function requestList() { client.request({ "func": "list" }, 10, function (err, msg) { if (err) { return abort(err); } let titles = msg.infoArr.shift(); titles.splice(1, 1); let serverTypes = {}; for (let one of msg.serverTypeSort) { serverTypes[one] = []; } for (let one of msg.infoArr) { serverTypes[one[1]].push(one); one.splice(1, 1); } for (let x in serverTypes) { serverTypes[x].sort(comparer); } let id = 1; titles.unshift(""); let endArr = []; endArr.push(titles); serverTypes["master"][0].unshift(" " + id.toString()); id++; endArr.push(serverTypes["master"][0]); delete serverTypes["master"]; for (let x in serverTypes) { for (let one of serverTypes[x]) { one.unshift(" " + id.toString()); id++; endArr.push(one); } } clearScreen(rowNum); rowNum = endArr.length + 1; mydogListPrint(msg.name, msg.env, endArr); setTimeout(requestList, interval * 1000); }); } }); let comparer = function (a, b) { if (a[0] < b[0]) { return -1; } else { return 1; } }; function mydogListPrint(appName, env, infoArr) { let consoleMaxColumns = process.stdout.columns - 2; let nameEnv = " appName: " + appName + " env: " + env; console.log("\x1b[35m" + getRealStr(nameEnv) + "\x1b[0m"); let widthArr = []; let columnWidth = []; let titleLen = infoArr[0].length; for (let i = 0; i < titleLen; i++) { columnWidth.push(0); } for (let i = 0; i < infoArr.length; i++) { let one = infoArr[i]; if (one.length > titleLen) { one.splice(titleLen); } else if (one.length < titleLen) { for (let j = titleLen - one.length - 1; j >= 0; j--) { one.push(""); } } let tmpArr = []; for (let j = 0; j < titleLen; j++) { one[j] = one[j].toString(); let tmpLen = getDisplayLength(one[j]); tmpArr.push(tmpLen); if (tmpLen > columnWidth[j]) { columnWidth[j] = tmpLen; } } widthArr[i] = tmpArr; } for (let i = 0; i < titleLen; i++) { columnWidth[i] += 3; } for (let i = 0; i < infoArr.length; i++) { let one = infoArr[i]; let tmpWidthArr = widthArr[i]; for (let j = 0; j < titleLen; j++) { one[j] += " ".repeat(columnWidth[j] - tmpWidthArr[j]); } if (i === 0) { console.log("\x1b[31m" + getRealStr(one.join("")) + "\x1b[0m"); } else { console.log(getRealStr(one.join(""))); } } function getRealStr(str) { while (getDisplayLength(str) > consoleMaxColumns) { str = str.substring(0, str.length - 2); } return str; } function getDisplayLength(str) { let realLength = 0, len = str.length, charCode = -1; for (var i = 0; i < len; i++) { charCode = str.charCodeAt(i); if (charCode >= 0 && charCode <= 128) { realLength += 1; } else { realLength += 2; } } return realLength; } } } function cli_stop(opts) { confirm('stop the server ? (y/n) [no] ', (yes) => { if (!yes) { abort("[ canceled ]"); return; } connectToMaster(opts.host, opts.port, opts.token, function (client) { waitMsg("connect ok! waiting"); client.request({ "func": "stop" }, 3600, function (err) { clearWait(); if (err) { return abort(err); } abort("the application has stopped, please confirm!"); }); }); }); } function cli_remove(opts) { if (opts.serverIds.length === 0) { return abort("no server input, please use like `mydog remove serverId-1 [serverId-2 ...]` "); } let serverIds = []; for (let id of opts.serverIds) { serverIds.push(...parseServerId(id)); } serverIds = Array.from(new Set(serverIds)); confirm(`remove server: ${serverIds.join(" ")} ? (y/n) [no] `, (yes) => { if (!yes) { abort("[ canceled ]"); return; } connectToMaster(opts.host, opts.port, opts.token, function (client) { waitMsg("connect ok! waiting"); client.request({ "func": "remove", "args": serverIds }, 3600, function (err) { clearWait(); if (err) { return abort(err); } abort("the servers have been removed, please confirm!"); }); }); }); } function cli_removeT(opts) { if (opts.serverTypes.length === 0) { return abort("no serverType input, please use like `mydog removeT serverType-1 [serverType-2 ...]` "); } opts.serverTypes = Array.from(new Set(opts.serverTypes)); confirm(`remove serverType: ${opts.serverTypes.join(" ")} ? (y/n) [no] `, (yes) => { if (!yes) { abort("[ canceled ]"); return; } connectToMaster(opts.host, opts.port, opts.token, function (client) { waitMsg("connect ok! waiting"); client.request({ "func": "removeT", "args": opts.serverTypes }, 3600, function (err) { clearWait(); if (err) { return abort(err); } abort("the serverTypes have been removed, please confirm!"); }); }); }); } function cli_cmd(lans) { lans = Array.from(new Set(lans)); let routePath = "config/sys/route.ts"; let serverPath = "config/cmd.ts"; let nowPath = process.cwd(); let filepath = path.join(nowPath, routePath); if (!fs.existsSync(filepath)) { abort(" -> Not find the script: " + filepath); } let readStream = fs.createReadStream(filepath); let read_l = readline.createInterface({ "input": readStream }); let hasStart = false; let cmdObjArr = []; read_l.on("line", function (line) { line = line.trim(); if (line === "") { return; } if (!hasStart) { if (line.indexOf("export") === 0) hasStart = true; return; } if (line.indexOf("]") === 0) { serverCmd(); clientCmd(); read_l.close(); return; } if (line.indexOf('"') !== 0) { return; } line = line.substring(1); let index = line.indexOf('"'); if (index === -1) { return; } let cmd = line.substring(0, index); let note = ""; index = line.indexOf("//"); if (index !== -1) { note = line.substring(index + 2).trim(); } cmdObjArr.push({ "cmd": cmd, "note": note }); }); read_l.on("close", function () { console.log("build cmd ok!"); }); function serverCmd() { let endStr = `export const enum cmd {\n`; let index = 0; for (let one of cmdObjArr) { if (one.note) { endStr += `\t/**\n\t * ${one.note}\n\t */\n`; } let oneStr = one.cmd; if (one.cmd.indexOf('.') !== -1) { let tmpArr = one.cmd.split('.'); oneStr = tmpArr[0] + '_' + tmpArr[1] + '_' + tmpArr[2]; } endStr += `\t${oneStr} = ${index},\n`; index++; } endStr += '}'; let csFilename = path.join(nowPath, serverPath); fs.writeFileSync(csFilename, endStr); } function clientCmd() { let clipath = path.join(nowPath, "mydog_cli.js"); if (!fs.existsSync(clipath)) { return; } let file = require(path.join(nowPath, "mydog_cli.js")); if (file.mydog_cmd && typeof file.mydog_cmd === "function") { file.mydog_cmd(lans, cmdObjArr); } } } function cli_send(opts, argv) { if (argv.length === 0) { return abort("cannot send empty msg"); } for (let i = 0; i < argv.length; i++) { argv[i] = argv[i].replace(/ /g, ","); } let serverIds = []; let serverTypes = []; let endMsg = { "serverIds": [], "serverTypes": [], "argv": argv }; if (opts.serverId) { opts.serverId = opts.serverId.replace(/ /g, ","); for (let id of opts.serverId.split(",")) { serverIds.push(...parseServerId(id)); } serverIds = Array.from(new Set(serverIds)); endMsg["serverIds"] = serverIds; } if (opts.serverType) { opts.serverType = opts.serverType.replace(/ /g, ","); serverTypes = Array.from(new Set(opts.serverType.split(","))); endMsg["serverTypes"] = serverTypes; } let msg = `sendMsg: { "serverIds": ${JSON.stringify(serverIds)} "serverTypes": ${JSON.stringify(serverTypes)} "argv": ${JSON.stringify(argv)} } (y/n)[no] ? `; confirm(msg, (yes) => { if (!yes) { abort("[ canceled ]"); return; } connectToMaster(opts.host, opts.port, opts.token, function (client) { waitMsg("connect ok! waiting"); client.request({ "func": "send", "args": endMsg }, 600, function (err, data) { clearWait(); console.log(); client.close(false); if (err) { return abort(err); } if (data.err) { return abort(data.err); } let clipath = path.join(process.cwd(), "mydog_cli.js"); if (!fs.existsSync(clipath)) { console.log(data); return; } let file = require(path.join(process.cwd(), "mydog_cli.js")); if (file.mydog_send && typeof file.mydog_send === "function") { file.mydog_send(endMsg, data.timeoutIds, data.data); } else { console.log(data); } }); }); }); } //#endregion function abort(str = "") { console.error(str); process.exit(1); } function confirm(msg, fn) { prompt(msg, function (val) { val = val.trim().toLowerCase(); fn(val === "y" || val === "yes"); }); function prompt(msg, fn) { console.log(msg); process.stdin.setEncoding('ascii'); process.stdin.once('data', function (data) { process.stdin.destroy(); fn(data.toString()); }).resume(); } } function parseServerId(id) { if (!id.includes("~")) { return [id]; } let arr = id.split("~"); if (arr.length !== 2) { abort("cannot parse serverId: " + id); return []; } let numArr = []; for (let i = 0; i <= 9; i++) { numArr.push(i.toString()); } let startNumArr = []; let idStartArr = []; let getId = false; let charArr = arr[0].split(""); for (let i = charArr.length - 1; i >= 0; i--) { if (getId) { idStartArr.unshift(charArr[i]); continue; } if (numArr.includes(charArr[i])) { startNumArr.unshift(charArr[i]); } else { idStartArr.unshift(charArr[i]); getId = true; } } let idStartStr = idStartArr.join(""); if (startNumArr.length == 0) { abort("cannot parse serverId: " + id); return []; } let startNum = parseInt(startNumArr.join("")); let endNum = parseInt(arr[1]); if (isNaN(startNum) || isNaN(endNum) || startNum > endNum) { abort("cannot parse serverId: " + id); return []; } let endIds = []; for (let i = startNum; i <= endNum; i++) { endIds.push(idStartStr + i); } return endIds; } function clearWait() { clearInterval(waitInterval); } function waitMsg(msg) { clearWait(); let index = 0; console.log(msg); waitInterval = setInterval(() => { clearScreen(1); console.log(msg + " " + ".".repeat(index)); index++; index = index % 4; }, 300); } function clearScreen(rowNum) { readline.cursorTo(process.stdout, 0); readline.moveCursor(process.stdout, 0, -rowNum); readline.clearScreenDown(process.stdout); } function connectToMaster(host, port, token, cb) { waitMsg("connecting " + host + ":" + port); let client = new clientProxy(host, port, token, cb); }