UNPKG

@haelp/teto

Version:

A typescript-based controllable TETR.IO client.

1 lines 8.73 kB
{"version":3,"sources":["../../../src/utils/adapters/adapter-io.ts"],"sourcesContent":["import { EventEmitter } from \"..\";\nimport type { Engine, Mino } from \"../../engine\";\nimport { Adapter } from \"./core\";\nimport type * as Messages from \"./types/messages\";\n\nimport chalk from \"chalk\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"child_process\";\n\nexport interface AdapterIOConfig {\n /** The name of the adapter. Used when logging to the terminal. */\n name: string;\n /** Whether to log all messages and non-json output to the terminal */\n verbose: boolean;\n /** The path to the binary executable. */\n path: string;\n /**\n * The environment variables to set for the child process.\n * For example, when using rust, you might set RUST_BACKTRACE=1\n */\n env: NodeJS.ProcessEnv;\n /** Any additional command-line arguments to pass tothe executable */\n args: string[];\n}\n\n/**\n * Communicates with a binary engine executable using Standard Input/Output.\n * Uses JSON messages.\n * @see {@link Messages.CustomMessageData}\n */\nexport class AdapterIO<\n T extends Messages.CustomMessageData\n> extends Adapter<T> {\n static defaultConfig: Omit<AdapterIOConfig, \"path\"> = {\n name: \"AdapterIO\",\n verbose: false,\n env: {},\n args: []\n };\n\n log(\n msg: string,\n {\n force = false,\n level = \"info\"\n }: { force: boolean; level: \"info\" | \"warning\" | \"error\" } = {\n force: false,\n level: \"info\"\n }\n ) {\n if (!this.cfg.verbose && !force) return;\n const func =\n level === \"info\"\n ? chalk.blue\n : level === \"warning\"\n ? chalk.yellow\n : chalk.red;\n console[level === \"error\" ? \"error\" : \"log\"](\n `${func(`[${this.cfg.name}]`)} ${msg}`\n );\n }\n\n cfg: AdapterIOConfig;\n\n events = new EventEmitter<Messages.Incoming.EventMap<T>>();\n\n dead = false;\n #dataBuffer = \"\";\n\n process!: ChildProcessWithoutNullStreams;\n\n constructor(\n config: Partial<AdapterIOConfig> & {\n path: string;\n }\n ) {\n super();\n\n if (!config.path) {\n throw new Error(\"AdapterIO requires a path to the binary executable.\");\n }\n\n this.cfg = {\n ...AdapterIO.defaultConfig,\n ...config\n };\n }\n\n #start() {\n this.process = spawn(this.cfg.path, this.cfg.args, {\n env: this.cfg.env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n\n this.process.stderr.on(\"data\", (data) => {\n this.log(\"Error: \" + data.toString(), { level: \"error\", force: true });\n });\n\n this.process.stdout.on(\"data\", (message) => this.#handle(message));\n }\n\n initialize(): Promise<Messages.Incoming.Info<T>> {\n return new Promise((resolve) => {\n this.events.once(\"info\", (info) => {\n this.log(\"READY\");\n resolve(info);\n });\n\n this.#start();\n });\n }\n\n send(message: Messages.Outgoing.all<T>) {\n if (this.dead) return;\n this.process.stdin.write(JSON.stringify(message) + \"\\n\");\n this.log(\"OUTGOING:\\n\" + JSON.stringify(message, null, 2));\n }\n\n #handle(message: string | Buffer) {\n const text = message.toString();\n this.#dataBuffer += text;\n\n let newlineIndex;\n while ((newlineIndex = this.#dataBuffer.indexOf(\"\\n\")) >= 0) {\n const line = this.#dataBuffer.slice(0, newlineIndex);\n this.#dataBuffer = this.#dataBuffer.slice(newlineIndex + 1);\n\n if (line === \"\") continue;\n\n try {\n const message = JSON.parse(line.trim());\n this.log(\"INCOMING:\\n\" + JSON.stringify(message, null, 2));\n this.events.emit(message.type, message);\n } catch {\n this.log(line);\n }\n }\n }\n\n config(engine: Engine, data?: T[\"config\"]): void {\n this.send({\n type: \"config\",\n ...this.configFromEngine(engine),\n data\n });\n }\n\n update(engine: Engine, data?: T[\"state\"]): void {\n this.send({\n type: \"state\",\n ...this.stateFromEngine(engine),\n data\n });\n }\n\n addPieces(pieces: Mino[], data?: T[\"pieces\"]): void {\n this.send({\n type: \"pieces\",\n pieces,\n data\n });\n }\n\n play(engine: Engine, data?: T[\"play\"]): Promise<Messages.Incoming.Move<T>> {\n this.send({\n type: \"play\",\n ...this.playFromEngine(engine),\n data\n });\n\n return new Promise((resolve) => {\n this.events.once(\"move\", (move) => {\n resolve(move);\n });\n });\n }\n\n stop() {\n this.process.kill(\"SIGINT\");\n this.events.removeAllListeners();\n this.process.removeAllListeners();\n this.process.stdout.removeAllListeners();\n this.process.stderr.removeAllListeners();\n this.process.stdin.removeAllListeners();\n this.process.unref();\n\n this.dead = true;\n }\n}\n"],"names":["EventEmitter","Adapter","chalk","spawn","AdapterIO","defaultConfig","name","verbose","env","args","log","msg","force","level","cfg","func","blue","yellow","red","console","events","dead","process","config","path","Error","stdio","stderr","on","data","toString","stdout","message","initialize","Promise","resolve","once","info","send","stdin","write","JSON","stringify","text","newlineIndex","indexOf","line","slice","parse","trim","emit","type","engine","configFromEngine","update","stateFromEngine","addPieces","pieces","play","playFromEngine","move","stop","kill","removeAllListeners","unref"],"mappings":"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"}