{ "version": 3, "sources": ["../../lib/repl.ts"], "sourcesContent": ["/**\n * REPL\n *\n * Documented in logs/repl/README.md\n * https://github.com/smogon/pokemon-showdown/blob/master/logs/repl/README.md\n *\n * @author kota\n * @license MIT\n */\n\nimport * as fs from 'fs';\nimport * as net from 'net';\nimport * as path from 'path';\nimport * as repl from 'repl';\nimport { crashlogger } from './crashlogger';\nimport { FS } from './fs';\ndeclare const Config: any;\n\nexport const Repl = new class {\n\t/**\n\t * Contains the pathnames of all active REPL sockets.\n\t */\n\tsocketPathnames = new Set();\n\n\tlistenersSetup = false;\n\n\tsetupListeners(filename: string) {\n\t\tif (Repl.listenersSetup) return;\n\t\tRepl.listenersSetup = true;\n\t\t// Clean up REPL sockets and child processes on forced exit.\n\t\tprocess.once('exit', code => {\n\t\t\tfor (const s of Repl.socketPathnames) {\n\t\t\t\ttry {\n\t\t\t\t\tfs.unlinkSync(s);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tif (code === 129 || code === 130) {\n\t\t\t\tprocess.exitCode = 0;\n\t\t\t}\n\t\t});\n\t\tif (!process.listeners('SIGHUP').length) {\n\t\t\tprocess.once('SIGHUP', () => process.exit(128 + 1));\n\t\t}\n\t\tif (!process.listeners('SIGINT').length) {\n\t\t\tprocess.once('SIGINT', () => process.exit(128 + 2));\n\t\t}\n\t\t(global as any).heapdump = (targetPath?: string) => {\n\t\t\tif (!targetPath) targetPath = `${filename}-${new Date().toISOString()}`;\n\t\t\tlet handler;\n\t\t\ttry {\n\t\t\t\thandler = require('node-oom-heapdump')();\n\t\t\t} catch (e: any) {\n\t\t\t\tif (e.code !== 'MODULE_NOT_FOUND') throw e;\n\t\t\t\tthrow new Error(`node-oom-heapdump is not installed. Run \\`npm install --no-save node-oom-heapdump\\` and try again.`);\n\t\t\t}\n\t\t\treturn handler.createHeapSnapshot(targetPath);\n\t\t};\n\t}\n\n\t/**\n\t * Delete old sockets in the REPL directory (presumably from a crashed\n\t * previous launch of PS).\n\t *\n\t * Does everything synchronously, so that the directory is guaranteed\n\t * clean and ready for new REPL sockets by the time this function returns.\n\t */\n\tcleanup() {\n\t\tconst config = typeof Config !== 'undefined' ? Config : {};\n\t\tif (!config.repl) return;\n\n\t\t// Clean up old REPL sockets.\n\t\tconst directory = path.dirname(\n\t\t\tpath.resolve(FS.ROOT_PATH, config.replsocketprefix || 'logs/repl', 'app')\n\t\t);\n\t\tlet files;\n\t\ttry {\n\t\t\tfiles = fs.readdirSync(directory);\n\t\t} catch {}\n\t\tif (files) {\n\t\t\tfor (const file of files) {\n\t\t\t\tconst pathname = path.resolve(directory, file);\n\t\t\t\tconst stat = fs.statSync(pathname);\n\t\t\t\tif (!stat.isSocket()) continue;\n\n\t\t\t\tconst socket = net.connect(pathname, () => {\n\t\t\t\t\tsocket.end();\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t}).on('error', () => {\n\t\t\t\t\tfs.unlinkSync(pathname);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Starts a REPL server, using a UNIX socket for IPC. The eval function\n\t * parametre is passed in because there is no other way to access a file's\n\t * non-global context.\n\t */\n\tstart(filename: string, evalFunction: (input: string) => any) {\n\t\tconst config = typeof Config !== 'undefined' ? Config : {};\n\t\tif (!config.repl) return;\n\n\t\t// TODO: Windows does support the REPL when using named pipes. For now,\n\t\t// this only supports UNIX sockets.\n\n\t\tRepl.setupListeners(filename);\n\n\t\tconst server = net.createServer(socket => {\n\t\t\trepl.start({\n\t\t\t\tinput: socket,\n\t\t\t\toutput: socket,\n\t\t\t\teval(cmd, context, unusedFilename, callback) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn callback(null, evalFunction(cmd));\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\treturn callback(e, undefined);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}).on('exit', () => socket.end());\n\t\t\tsocket.on('error', () => socket.destroy());\n\t\t});\n\n\t\tconst pathname = path.resolve(FS.ROOT_PATH, Config.replsocketprefix || 'logs/repl', filename);\n\t\ttry {\n\t\t\tserver.listen(pathname, () => {\n\t\t\t\tfs.chmodSync(pathname, Config.replsocketmode || 0o600);\n\t\t\t\tRepl.socketPathnames.add(pathname);\n\t\t\t});\n\n\t\t\tserver.once('error', (err: NodeJS.ErrnoException) => {\n\t\t\t\tserver.close();\n\t\t\t\tif (err.code === \"EADDRINUSE\") {\n\t\t\t\t\tfs.unlink(pathname, _err => {\n\t\t\t\t\t\tif (_err && _err.code !== \"ENOENT\") {\n\t\t\t\t\t\t\tcrashlogger(_err, `REPL: ${filename}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else if (err.code === \"EACCES\") {\n\t\t\t\t\tif (process.platform !== 'win32') {\n\t\t\t\t\t\tconsole.error(`Could not start REPL server \"${filename}\": Your filesystem doesn't support Unix sockets (everything else will still work)`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcrashlogger(err, `REPL: ${filename}`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tserver.once('close', () => {\n\t\t\t\tRepl.socketPathnames.delete(pathname);\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tconsole.error(`Could not start REPL server \"${filename}\": ${err}`);\n\t\t}\n\t}\n};\n"], "mappings": "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", "names": [] }