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