{ "version": 3, "sources": ["../../../server/loginserver.ts"], "sourcesContent": ["/**\r\n * Login server abstraction layer\r\n * Pokemon Showdown - http://pokemonshowdown.com/\r\n *\r\n * This file handles communicating with the login server.\r\n *\r\n * @license MIT\r\n */\r\n\r\nconst LOGIN_SERVER_TIMEOUT = 30000;\r\nconst LOGIN_SERVER_BATCH_TIME = 1000;\r\n\r\nimport {Net, FS} from '../lib';\r\n\r\n/**\r\n * A custom error type used when requests to the login server take too long.\r\n */\r\nclass TimeoutError extends Error {}\r\nTimeoutError.prototype.name = TimeoutError.name;\r\n\r\nfunction parseJSON(json: string) {\r\n\tif (json.startsWith(']')) json = json.substr(1);\r\n\tconst data: {error: string | null, json: any[] | null} = {error: null, json: null};\r\n\ttry {\r\n\t\tdata.json = JSON.parse(json);\r\n\t} catch (err: any) {\r\n\t\tdata.error = err.message;\r\n\t}\r\n\treturn data;\r\n}\r\n\r\ntype LoginServerResponse = [AnyObject, null] | [null, Error];\r\n\r\nclass LoginServerInstance {\r\n\treadonly uri: string;\r\n\trequestQueue: [AnyObject, (val: LoginServerResponse) => void][];\r\n\trequestTimer: NodeJS.Timer | null;\r\n\trequestLog: string;\r\n\tlastRequest: number;\r\n\topenRequests: number;\r\n\tdisabled: false;\r\n\r\n\tconstructor() {\r\n\t\tthis.uri = Config.loginserver;\r\n\t\tthis.requestQueue = [];\r\n\t\tthis.requestTimer = null;\r\n\t\tthis.requestLog = '';\r\n\t\tthis.lastRequest = 0;\r\n\t\tthis.openRequests = 0;\r\n\t\tthis.disabled = false;\r\n\t}\r\n\r\n\tasync instantRequest(action: string, data: AnyObject | null = null): Promise {\r\n\t\tif (this.openRequests > 5) {\r\n\t\t\treturn Promise.resolve(\r\n\t\t\t\t[null, new RangeError(\"Request overflow\")]\r\n\t\t\t);\r\n\t\t}\r\n\t\tthis.openRequests++;\r\n\r\n\t\ttry {\r\n\t\t\tconst request = Net(this.uri);\r\n\t\t\tconst buffer = await request.get({\r\n\t\t\t\tquery: {\r\n\t\t\t\t\t...data,\r\n\t\t\t\t\tact: action,\r\n\t\t\t\t\tserverid: Config.serverid,\r\n\t\t\t\t\tservertoken: Config.servertoken,\r\n\t\t\t\t\tnocache: new Date().getTime(),\r\n\t\t\t\t},\r\n\t\t\t});\r\n\t\t\tconst json = parseJSON(buffer);\r\n\t\t\tthis.openRequests--;\r\n\t\t\tif (json.error) {\r\n\t\t\t\treturn [null, new Error(json.error)];\r\n\t\t\t}\r\n\t\t\tthis.openRequests--;\r\n\t\t\treturn [json.json!, null];\r\n\t\t} catch (error: any) {\r\n\t\t\tthis.openRequests--;\r\n\t\t\treturn [null, error];\r\n\t\t}\r\n\t}\r\n\r\n\trequest(action: string, data: AnyObject | null = null): Promise {\r\n\t\tif (this.disabled) {\r\n\t\t\treturn Promise.resolve(\r\n\t\t\t\t[null, new Error(`Login server connection disabled.`)]\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\t// ladderupdate and mmr are the most common actions\r\n\t\t// prepreplay is also common\r\n\t\t// @ts-ignore\r\n\t\tif (this[action + 'Server']) {\r\n\t\t\t// @ts-ignore\r\n\t\t\treturn this[action + 'Server'].request(action, data);\r\n\t\t}\r\n\r\n\t\tconst actionData = data || {};\r\n\t\tactionData.act = action;\r\n\t\treturn new Promise(resolve => {\r\n\t\t\tthis.requestQueue.push([actionData, resolve]);\r\n\t\t\tthis.requestTimerPoke();\r\n\t\t});\r\n\t}\r\n\trequestTimerPoke() {\r\n\t\t// \"poke\" the request timer, i.e. make sure it knows it should make\r\n\t\t// a request soon\r\n\r\n\t\t// if we already have it going or the request queue is empty no need to do anything\r\n\t\tif (this.openRequests || this.requestTimer || !this.requestQueue.length) return;\r\n\r\n\t\tthis.requestTimer = setTimeout(() => void this.makeRequests(), LOGIN_SERVER_BATCH_TIME);\r\n\t}\r\n\tasync makeRequests() {\r\n\t\tthis.requestTimer = null;\r\n\t\tconst requests = this.requestQueue;\r\n\t\tthis.requestQueue = [];\r\n\r\n\t\tif (!requests.length) return;\r\n\r\n\t\tconst resolvers: ((val: LoginServerResponse) => void)[] = [];\r\n\t\tconst dataList = [];\r\n\t\tfor (const [data, resolve] of requests) {\r\n\t\t\tresolvers.push(resolve);\r\n\t\t\tdataList.push(data);\r\n\t\t}\r\n\r\n\t\tthis.requestStart(requests.length);\r\n\r\n\t\ttry {\r\n\t\t\tconst request = Net(`${this.uri}action.php`);\r\n\t\t\tlet buffer = await request.post({\r\n\t\t\t\tbody: {\r\n\t\t\t\t\tserverid: Config.serverid,\r\n\t\t\t\t\tservertoken: Config.servertoken,\r\n\t\t\t\t\tnocache: new Date().getTime(),\r\n\t\t\t\t\tjson: JSON.stringify(dataList),\r\n\t\t\t\t},\r\n\t\t\t\ttimeout: LOGIN_SERVER_TIMEOUT,\r\n\t\t\t});\r\n\t\t\t// console.log('RESPONSE: ' + buffer);\r\n\t\t\tconst data = parseJSON(buffer).json;\r\n\t\t\tif (buffer.startsWith(`[{\"actionsuccess\":true,`)) {\r\n\t\t\t\tbuffer = 'stream interrupt';\r\n\t\t\t}\r\n\t\t\tif (!data) {\r\n\t\t\t\tif (buffer.includes('<')) buffer = 'invalid response';\r\n\t\t\t\tthrow new Error(buffer);\r\n\t\t\t}\r\n\t\t\tfor (const [i, resolve] of resolvers.entries()) {\r\n\t\t\t\tresolve([data[i], null]);\r\n\t\t\t}\r\n\r\n\t\t\tthis.requestEnd();\r\n\t\t} catch (error: any) {\r\n\t\t\tfor (const resolve of resolvers) {\r\n\t\t\t\tresolve([null, error]);\r\n\t\t\t}\r\n\t\t\tthis.requestEnd(error);\r\n\t\t}\r\n\t}\r\n\trequestStart(size: number) {\r\n\t\tthis.lastRequest = Date.now();\r\n\t\tthis.requestLog += ' | ' + size + ' rqs: ';\r\n\t\tthis.openRequests++;\r\n\t}\r\n\trequestEnd(error?: Error) {\r\n\t\tthis.openRequests = 0;\r\n\t\tif (error && error instanceof TimeoutError) {\r\n\t\t\tthis.requestLog += 'TIMEOUT';\r\n\t\t} else {\r\n\t\t\tthis.requestLog += '' + ((Date.now() - this.lastRequest) / 1000) + 's';\r\n\t\t}\r\n\t\tthis.requestLog = this.requestLog.substr(-1000);\r\n\t\tthis.requestTimerPoke();\r\n\t}\r\n\tgetLog() {\r\n\t\tif (!this.lastRequest) return this.requestLog;\r\n\t\treturn `${this.requestLog} (${Chat.toDurationString(Date.now() - this.lastRequest)} since last request)`;\r\n\t}\r\n}\r\n\r\nexport const LoginServer = Object.assign(new LoginServerInstance(), {\r\n\tTimeoutError,\r\n\r\n\tladderupdateServer: new LoginServerInstance(),\r\n\tprepreplayServer: new LoginServerInstance(),\r\n});\r\n\r\nFS('./config/custom.css').onModify(() => {\r\n\tvoid LoginServer.request('invalidatecss');\r\n});\r\nif (!Config.nofswriting) {\r\n\tvoid LoginServer.request('invalidatecss');\r\n}\r\n"], "mappings": "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", "names": [] }