Spaces:
Running
Running
{ | |
"version": 3, | |
"sources": ["../../../server/chat-plugins/battlesearch.ts"], | |
"sourcesContent": ["/**\n * Battle search - handles searching battle logs.\n */\nimport { FS, Utils, ProcessManager, Repl } from '../../lib';\n\nimport { checkRipgrepAvailability, Config } from '../config-loader';\n\nimport * as path from 'path';\nimport * as child_process from 'child_process';\n\nconst BATTLESEARCH_PROCESS_TIMEOUT = 3 * 60 * 60 * 1000; // 3 hours\n\ninterface BattleOutcome {\n\tlost: string;\n\twon: string;\n\tturns: string;\n}\n\ninterface BattleSearchResults {\n\ttotalBattles: number;\n\t/** Total battle outcomes. Null when only searching for one userid. */\n\ttotalOutcomes: BattleOutcome[] | null;\n\ttotalWins: { [k: string]: number };\n\ttotalLosses: { [k: string]: number };\n\ttotalTies: number;\n\ttimesBattled: { [k: string]: number };\n}\n\nconst MAX_BATTLESEARCH_PROCESSES = 1;\nexport async function runBattleSearch(userids: ID[], month: string, tierid: ID, turnLimit?: number) {\n\tconst useRipgrep = await checkRipgrepAvailability();\n\tconst pathString = `${month}/${tierid}/`;\n\tconst results: { [k: string]: BattleSearchResults } = {};\n\tlet files = [];\n\ttry {\n\t\tfiles = await Monitor.logPath(pathString).readdir();\n\t} catch (err: any) {\n\t\tif (err.code === 'ENOENT') {\n\t\t\treturn results;\n\t\t}\n\t\tthrow err;\n\t}\n\tconst [userid] = userids;\n\tfiles = files.filter(item => item.startsWith(month)).map(item => Monitor.logPath(`${month}/${tierid}/${item}`).path);\n\n\tif (useRipgrep) {\n\t\t// Matches non-word (including _ which counts as a word) characters between letters/numbers\n\t\t// in a user's name so the userid can case-insensitively be matched to the name.\n\t\t// We want to be order-insensitive for the player IDs. This union is much cheaper than using PCRE.\n\t\tconst userUnion = userids.map(id => `${[...id].join('[^a-zA-Z0-9]*')}[^a-zA-Z0-9]*`).join('|');\n\t\tconst regexString = userids.map(id => `(.*?(\"p(1|2)\":\"(${userUnion})\"))`).join('');\n\t\tlet output;\n\t\ttry {\n\t\t\toutput = await ProcessManager.exec(['rg', '-i', regexString, '--no-line-number', '-tjson', ...files]);\n\t\t} catch {\n\t\t\treturn results;\n\t\t}\n\t\tfor (const line of output.stdout.split('\\n').reverse()) {\n\t\t\tconst [file, raw] = Utils.splitFirst(line, ':');\n\t\t\tif (!raw || !line) continue;\n\t\t\tconst data = JSON.parse(raw);\n\t\t\tconst day = file.split('/')[3];\n\t\t\tif (!results[day]) {\n\t\t\t\tresults[day] = {\n\t\t\t\t\ttotalBattles: 0,\n\t\t\t\t\ttotalWins: {},\n\t\t\t\t\ttotalOutcomes: userids.length > 1 ? [] : null,\n\t\t\t\t\ttotalLosses: {},\n\t\t\t\t\ttotalTies: 0,\n\t\t\t\t\ttimesBattled: {},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst p1id = toID(data.p1);\n\t\t\tconst p2id = toID(data.p2);\n\n\t\t\tif (userids.length > 1) {\n\t\t\t\t// looking for specific userids, only register ones where those users are players\n\t\t\t\tif (userids.filter(item => [p1id, p2id].includes(item)).length < userids.length) continue;\n\t\t\t} else {\n\t\t\t\tif (!(p1id === userid || p2id === userid)) continue;\n\t\t\t}\n\n\t\t\tif (turnLimit && data.turns > turnLimit) continue;\n\t\t\tif (!results[day]) {\n\t\t\t\tresults[day] = {\n\t\t\t\t\ttotalBattles: 0,\n\t\t\t\t\ttotalWins: {},\n\t\t\t\t\ttotalOutcomes: userids.length > 1 ? [] : null,\n\t\t\t\t\ttotalLosses: {},\n\t\t\t\t\ttotalTies: 0,\n\t\t\t\t\ttimesBattled: {},\n\t\t\t\t};\n\t\t\t}\n\t\t\tresults[day].totalBattles++;\n\t\t\tconst winnerid = toID(data.winner);\n\t\t\tconst loser = winnerid === p1id ? p2id : p1id;\n\t\t\tif (userids.includes(winnerid)) {\n\t\t\t\tif (!results[day].totalWins[winnerid]) results[day].totalWins[winnerid] = 0;\n\t\t\t\tresults[day].totalWins[winnerid]++;\n\t\t\t} else if (data.winner) {\n\t\t\t\tif (!results[day].totalLosses[loser]) results[day].totalLosses[loser] = 0;\n\t\t\t\tresults[day].totalLosses[loser]++;\n\t\t\t} else {\n\t\t\t\tresults[day].totalTies++;\n\t\t\t}\n\t\t\t// explicitly state 0 of stats if none\n\t\t\tfor (const id of userids) {\n\t\t\t\tif (!results[day].totalLosses[id]) results[day].totalLosses[id] = 0;\n\t\t\t\tif (!results[day].totalWins[id]) results[day].totalWins[id] = 0;\n\t\t\t}\n\n\t\t\tconst outcomes = results[day].totalOutcomes;\n\t\t\tif (outcomes) {\n\t\t\t\toutcomes.push({ won: winnerid, lost: loser, turns: data.turns });\n\t\t\t}\n\t\t\t// we only want foe data for single-userid searches\n\t\t\tconst foe = userids.length > 1 ? null : userid === toID(data.p1) ? toID(data.p2) : toID(data.p1);\n\t\t\tif (foe) {\n\t\t\t\tif (!results[day].timesBattled[foe]) results[day].timesBattled[foe] = 0;\n\t\t\t\tresults[day].timesBattled[foe]++;\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\tfor (const file of files) {\n\t\tconst subFiles = FS(`${file}`).readdirSync();\n\t\tconst day = file.split('/')[3];\n\t\tfor (const dayFile of subFiles) {\n\t\t\tconst json = FS(`${file}/${dayFile}`).readIfExistsSync();\n\t\t\tconst data = JSON.parse(json);\n\t\t\tconst p1id = toID(data.p1);\n\t\t\tconst p2id = toID(data.p2);\n\t\t\tif (userids.length > 1) {\n\t\t\t\t// looking for specific userids, only register ones where those users are players\n\t\t\t\tif (userids.filter(item => item === p1id || item === p2id).length < userids.length) continue;\n\t\t\t} else {\n\t\t\t\tif (!(p1id === userid || p2id === userid)) continue;\n\t\t\t}\n\t\t\tif (turnLimit && data.turns > turnLimit) continue;\n\t\t\tif (!results[day]) {\n\t\t\t\tresults[day] = {\n\t\t\t\t\ttotalBattles: 0,\n\t\t\t\t\ttotalWins: {},\n\t\t\t\t\ttotalOutcomes: [],\n\t\t\t\t\ttotalLosses: {},\n\t\t\t\t\ttotalTies: 0,\n\t\t\t\t\ttimesBattled: {},\n\t\t\t\t};\n\t\t\t}\n\t\t\tresults[day].totalBattles++;\n\t\t\tconst winnerid = toID(data.winner);\n\t\t\tconst loser = winnerid === p1id ? p2id : p1id;\n\t\t\tif (userids.includes(winnerid)) {\n\t\t\t\tif (!results[day].totalWins[winnerid]) results[day].totalWins[winnerid] = 0;\n\t\t\t\tresults[day].totalWins[winnerid]++;\n\t\t\t} else if (data.winner) {\n\t\t\t\tif (!results[day].totalLosses[loser]) results[day].totalLosses[loser] = 0;\n\t\t\t\tresults[day].totalLosses[loser]++;\n\t\t\t} else {\n\t\t\t\tresults[day].totalTies++;\n\t\t\t}\n\t\t\t// explicitly state 0 of stats if none\n\t\t\tfor (const id of userids) {\n\t\t\t\tif (!results[day].totalLosses[id]) results[day].totalLosses[id] = 0;\n\t\t\t\tif (!results[day].totalWins[id]) results[day].totalWins[id] = 0;\n\t\t\t}\n\n\t\t\tconst outcomes = results[day].totalOutcomes;\n\t\t\tif (outcomes) {\n\t\t\t\toutcomes.push({ won: winnerid, lost: loser, turns: data.turns });\n\t\t\t}\n\n\t\t\t// we don't want foe data if we're searching for 2 userids\n\t\t\tconst foe = userids.length > 1 ? null : userid === p1id ? p2id : p1id;\n\t\t\tif (foe) {\n\t\t\t\tif (!results[day].timesBattled[foe]) results[day].timesBattled[foe] = 0;\n\t\t\t\tresults[day].timesBattled[foe]++;\n\t\t\t}\n\t\t}\n\t}\n\treturn results;\n}\n\nfunction buildResults(\n\tdata: { [k: string]: BattleSearchResults }, userids: ID[],\n\tmonth: string, tierid: ID, turnLimit?: number\n) {\n\tlet buf = `>view-battlesearch-${userids.join('-')}--${turnLimit}--${month}--${tierid}--confirm\\n|init|html\\n|title|[Battle Search][${userids.join('-')}][${tierid}][${month}]\\n`;\n\tbuf += `|pagehtml|<div class=\"pad ladder\"><p>`;\n\tbuf += `${tierid} battles on ${month} where `;\n\tbuf += userids.length > 1 ? `the users ${userids.join(', ')} were players` : `the user ${userids[0]} was a player`;\n\tbuf += turnLimit ? ` and the battle lasted less than ${turnLimit} turn${Chat.plural(turnLimit)}` : '';\n\tbuf += `:</p><li style=\"display: inline; list-style: none\"><a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}--${tierid}\" target=\"replace\">`;\n\tbuf += `<button class=\"button\">Back</button></a></li><br />`;\n\tif (userids.length > 1) {\n\t\tconst outcomes: BattleOutcome[] = [];\n\t\tfor (const day in data) {\n\t\t\tconst curOutcomes = data[day].totalOutcomes;\n\t\t\tif (curOutcomes) outcomes.push(...curOutcomes);\n\t\t}\n\t\tbuf += `<table><tbody><tr><h3 style=\"margin: 5px auto\">Full summary</h3></tr>`;\n\t\tbuf += `<tr><th>Won</th><th>Lost</th><th>Turns</th></tr>`;\n\t\tfor (const battle of outcomes) {\n\t\t\tconst { won, lost, turns } = battle;\n\t\t\tbuf += `<tr><td>${won}</td><td>${lost}</td><td>${turns}</td></tr>`;\n\t\t}\n\t}\n\tbuf += `</tbody></table><br />`;\n\tfor (const day in data) {\n\t\tconst dayStats = data[day];\n\t\tbuf += `<p style=\"text-align:left\">`;\n\t\tconst { totalWins, totalLosses } = dayStats;\n\t\tbuf += `<table style=\"\"><tbody><tr><th colspan=\"2\"><h3 style=\"margin: 5px auto\">${day}</h3>`;\n\t\tbuf += `</th></tr><tr><th>Category</th><th>Number</th></tr>`;\n\t\tbuf += `<tr><td>Total Battles</td><td>${dayStats.totalBattles}</td></tr>`;\n\t\tfor (const id in totalWins) {\n\t\t\t// hide userids if we're only searching for 1\n\t\t\tbuf += `<tr><td>Total Wins${userids.length > 1 ? ` (${id}) ` : ''}</td><td>${totalWins[id]}</td></tr>`;\n\t\t}\n\t\tfor (const id in totalLosses) {\n\t\t\tbuf += `<tr><td>Total Losses${userids.length > 1 ? ` (${id}) ` : ''}</td><td>${totalLosses[id]}</td></tr>`;\n\t\t}\n\t\tif (userids.length < 2) {\n\t\t\tbuf += `<tr><th>Opponent</th><th>Times Battled</th></tr>`;\n\t\t\tconst [userid] = userids;\n\t\t\tfor (const foe in dayStats.timesBattled) {\n\t\t\t\tbuf += `<tr><td>`;\n\t\t\t\tbuf += `<a href=\"/view-battlesearch-${userid}-${foe}--${turnLimit}--${month}--${tierid}\" target=\"replace\">${foe}</a>`;\n\t\t\t\tbuf += `</td><td>${dayStats.timesBattled[foe]}</td></tr>`;\n\t\t\t}\n\t\t}\n\t\tbuf += `</p><br />`;\n\t}\n\tbuf += `</tbody></table></div>`;\n\treturn buf;\n}\n\nasync function rustBattleSearch(\n\tcontext: Chat.PageContext, targetUser: string, daysString: string, format: ID\n) {\n\tconst days = parseInt(daysString);\n\tif (days < 1 || days > 15) {\n\t\tthrow new Chat.ErrorMessage(`Days must be between 1 and 15. To search longer ranges, use psbattletools manually on sim3.`);\n\t}\n\tif (!targetUser) {\n\t\tthrow new Chat.ErrorMessage(`No user specified.`);\n\t}\n\tconst { connection, user } = context;\n\tconst currentDayOfMonth = (new Date()).getDate();\n\tif (days < 1 || days > 15) {\n\t\treturn context.errorReply(`Days must be between 1 and 15. To search longer ranges, use psbattletools manually on sim3.`);\n\t}\n\n\ttry {\n\t\tawait ProcessManager.exec(`psbattletools --version`, {\n\t\t\tenv: { PATH: `${process.env.PATH}:${process.env.HOME}/.cargo/bin` },\n\t\t});\n\t} catch {\n\t\treturn context.errorReply(\n\t\t\t`You must install <a href=\"https://crates.io/crates/psbattletools\">psbattletools</a> to use the alternate battlesearch.`\n\t\t);\n\t}\n\tif (user.lastCommand !== '/battlesearch' && [30, 31, 1].includes(currentDayOfMonth)) {\n\t\tconst buf = [`Warning: Usage stats may be running currently.`];\n\t\tbuf.push(`Battlesearch can interfere with usage stats processing due to high computational load.`);\n\t\tbuf.push(`Please exercise caution.`);\n\t\tbuf.push(`Type the command again to confirm.`);\n\t\tuser.lastCommand = '/battlesearch';\n\t\tthrow new Chat.ErrorMessage(buf.join('<br />'));\n\t}\n\tuser.lastCommand = '';\n\n\tconst directories = [];\n\tfor (let daysAgo = 0; daysAgo < days; daysAgo++) {\n\t\tconst date = new Date(Date.now() - 24 * 60 * 60 * 1000 * daysAgo);\n\t\tconst year = date.getFullYear();\n\t\tconst month = (date.getMonth() + 1).toString().padStart(2, '0');\n\t\tconst day = date.getDate().toString().padStart(2, '0');\n\n\t\tdirectories.push(\n\t\t\tMonitor.logPath(path.join(`${year}-${month}`, format, `${year}-${month}-${day}`)).path\n\t\t);\n\t}\n\n\t// TODO: implement flag?\n\tlet buf = `>view-battlesearch-${toID(targetUser)}\\n|init|html\\n|title|[Battlesearch] ${targetUser} in ${format}\\n`;\n\tbuf += `|pagehtml|<div class=\"pad\"><h2>Battlesearch for ${targetUser} in ${format} in the last ${days} days</h2>`;\n\tbuf += `<div style=\"white-space:pre-wrap;display:block;\"></div>`;\n\tbuf += `<p>Searching...</p>`;\n\tbuf += `</div>`;\n\tconnection.send(buf);\n\n\tconst search = child_process.spawn(\n\t\t'psbattletools',\n\t\t['--threads', '3', 'search', targetUser, ...directories],\n\t\t{ env: { PATH: `${process.env.PATH}:${process.env.HOME}/.cargo/bin` } }\n\t);\n\tsearch.stdout.on('data', data => {\n\t\tbuf = buf.replace('</div>', `${Chat.formatText(data.toString()).replace(/\\n/g, '<br />')}</div>`);\n\t\tconnection.send(buf);\n\t});\n\tsearch.on('close', () => {\n\t\tbuf = buf.replace('Searching...', 'Done!');\n\t\tconnection.send(buf);\n\t});\n}\n\nasync function fsBattleSearch(\n\tconnection: Connection, userids: string[], month: string,\n\ttierid: ID, turnLimit?: number\n) {\n\tuserids = userids.map(toID);\n\tconst user = connection.user;\n\tif (!user.can('forcewin')) return connection.popup(`/battlesearch - Access Denied`);\n\n\tconst response = await PM.query({ userids, turnLimit, month, tierid });\n\tconnection.send(buildResults(response, userids as ID[], month, tierid, turnLimit));\n}\n\nexport const pages: Chat.PageTable = {\n\tasync battlesearch(args, user, connection) {\n\t\tif (!user.named) return Rooms.RETRY_AFTER_LOGIN;\n\t\tthis.checkCan('forcewin');\n\t\tif (Config.nobattlesearch === true) {\n\t\t\treturn this.errorReply(`Battlesearch has been temporarily disabled due to load issues.`);\n\t\t}\n\t\tif (Config.nobattlesearch === 'psbattletools') {\n\t\t\treturn rustBattleSearch(this, args[0], args[1], toID(args[2]));\n\t\t}\n\t\tconst [ids, rawLimit, month, formatid, confirmation] = Utils.splitFirst(this.pageid.slice(18), '--', 5);\n\t\tlet turnLimit: number | undefined = parseInt(rawLimit);\n\t\tif (isNaN(turnLimit)) turnLimit = undefined;\n\t\tconst userids = ids.split('-');\n\t\tif (!ids || turnLimit && turnLimit < 1) {\n\t\t\treturn user.popup(`Some arguments are missing or invalid for battlesearch. Use /battlesearch to start over.`);\n\t\t}\n\t\tthis.title = `[Battle Search][${userids.join(', ')}]`;\n\t\tlet buf = `<div class=\"pad ladder\"><h2>Battle Search</h2><p>Userid${Chat.plural(userids)}: ${userids.join(', ')}</p><p>`;\n\t\tif (turnLimit) {\n\t\t\tbuf += `Maximum Turns: ${turnLimit}`;\n\t\t}\n\t\tbuf += `</p>`;\n\n\t\tconst months = Utils.sortBy(\n\t\t\t(await Monitor.logPath('/').readdir()).filter(f => f.length === 7 && f.includes('-')),\n\t\t\tname => ({ reverse: name })\n\t\t);\n\t\tif (!month) {\n\t\t\tbuf += `<p>Please select a month:</p><ul style=\"list-style: none; display: block; padding: 0\">`;\n\t\t\tfor (const i of months) {\n\t\t\t\tbuf += `<li style=\"display: inline; list-style: none\"><a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${i}\" target=\"replace\"><button class=\"button\">${i}</button></li>`;\n\t\t\t}\n\t\t\treturn `${buf}</ul></div>`;\n\t\t} else {\n\t\t\tif (!months.includes(month)) {\n\t\t\t\treturn `${buf}Invalid month selected. <a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}\" target=\"replace\"><button class=\"button\">Back to month selection</button></a></div>`;\n\t\t\t}\n\t\t\tbuf += `<p><a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}\" target=\"replace\"><button class=\"button\">Back</button></a> <button class=\"button disabled\">${month}</button></p>`;\n\t\t}\n\n\t\tconst tierid = toID(formatid);\n\t\tconst tiers = Utils.sortBy(await Monitor.logPath(`${month}/`).readdir(), tier => [\n\t\t\t// First sort by gen with the latest being first\n\t\t\ttier.startsWith('gen') ? -parseInt(tier.charAt(3)) : -6,\n\t\t\t// Then sort alphabetically\n\t\t\ttier,\n\t\t]).map(tier => {\n\t\t\t// Use the official tier name\n\t\t\tconst format = Dex.formats.get(tier);\n\t\t\tif (format?.exists) tier = format.name;\n\t\t\t// Otherwise format as best as possible\n\t\t\tif (tier.startsWith('gen')) {\n\t\t\t\treturn `[Gen ${tier.substring(3, 4)}] ${tier.substring(4)}`;\n\t\t\t}\n\t\t\treturn tier;\n\t\t});\n\t\tif (!tierid) {\n\t\t\tbuf += `<p>Please select the tier to search:</p><ul style=\"list-style: none; display: block; padding: 0\">`;\n\t\t\tfor (const tier of tiers) {\n\t\t\t\tbuf += `<li style=\"display: inline; list-style: none\">`;\n\t\t\t\tbuf += `<a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}--${toID(tier)}\" target=\"replace\">`;\n\t\t\t\tbuf += `<button class=\"button\">${tier}</button></a></li><br />`;\n\t\t\t}\n\t\t\treturn `${buf}</ul></div>`;\n\t\t} else {\n\t\t\tif (!tiers.map(toID).includes(tierid)) {\n\t\t\t\treturn `${buf}Invalid tier selected. <a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}\" target=\"replace\"><button class=\"button\">Back to tier selection</button></a></div>`;\n\t\t\t}\n\t\t\tthis.title += `[${tierid}]`;\n\t\t\tbuf += `<p><a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}\" target=\"replace\"><button class=\"button\">Back</button></a> <button class=\"button disabled\">${tierid}</button></p>`;\n\t\t}\n\n\t\tconst [userid] = userids;\n\t\tif (toID(confirmation) !== 'confirm') {\n\t\t\tbuf += `<p>Are you sure you want to run a battle search for for ${tierid} battles on ${month} `;\n\t\t\tbuf += `where the ${userids.length > 1 ? `user(s) ${userids.join(', ')} were players` : `the user ${userid} was a player`}`;\n\t\t\tif (turnLimit) buf += ` and the battle lasted less than ${turnLimit} turn${Chat.plural(turnLimit)}`;\n\t\t\tbuf += `?</p><p><a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}--${tierid}--confirm\" target=\"replace\"><button class=\"button notifying\">Yes, run the battle search</button></a> <a href=\"/view-battlesearch-${userids.join('-')}--${turnLimit}--${month}--${tierid}\" target=\"replace\"><button class=\"button\">No, go back</button></a></p>`;\n\t\t\treturn `${buf}</div>`;\n\t\t}\n\n\t\t// Run search\n\t\tvoid fsBattleSearch(connection, userids, month, tierid, turnLimit);\n\t\treturn (\n\t\t\t`<div class=\"pad ladder\"><h2>Battle Search</h2><p>` +\n\t\t\t`Searching for ${tierid} battles on ${month} where the ` +\n\t\t\t`${userids.length > 1 ? `user(s) ${userids.join(', ')} were players` : `the user ${userid} was a player`} ` +\n\t\t\t(turnLimit ? `and the battle lasted less than ${turnLimit} turn${Chat.plural(turnLimit)}.` : '') +\n\t\t\t`</p><p>Loading... (this will take a while)</p></div>`\n\t\t);\n\t},\n};\n\nexport const commands: Chat.ChatCommands = {\n\tbattlesearch(target, room, user, connection) {\n\t\tif (!target.trim()) return this.parse('/help battlesearch');\n\t\tthis.checkCan('forcewin');\n\n\t\tconst parts = target.split(',');\n\t\tlet turnLimit;\n\t\tconst ids = [];\n\t\tfor (const part of parts) {\n\t\t\tif (part.startsWith('limit=')) {\n\t\t\t\tconst n = parseInt(part.slice('limit='.length).trim());\n\t\t\t\tif (isNaN(n)) {\n\t\t\t\t\treturn this.errorReply(`Invalid limit: ${part.slice('limit='.length)}`);\n\t\t\t\t}\n\t\t\t\tturnLimit = n;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tids.push(part);\n\t\t}\n\t\t// Selection on month, tier, and date will be handled in the HTML room\n\t\treturn this.parse(`/join view-battlesearch-${ids.map(toID).join('-')}--${turnLimit || \"\"}`);\n\t},\n\tbattlesearchhelp() {\n\t\tif (Config.nobattlesearch === 'psbattletools') {\n\t\t\t// use the psbattletools battlesearch command instead\n\t\t\treturn this.parse('/help rustbattlesearch');\n\t\t}\n\n\t\tthis.runBroadcast();\n\t\treturn this.sendReply(\n\t\t\t'/battlesearch [args] - Searches rated battle history for the provided [args] and returns information on battles between the userids given.\\n' +\n\t\t\t`If a number is provided in the [args], it is assumed to be a turn limit, else they're assumed to be userids. Requires ~`\n\t\t);\n\t},\n\trustbattlesearchhelp: [\n\t\t`/battlesearch <user>, <format>, <days> - Searches for battles played by <user> in the past <days> days. Requires: ~`,\n\t],\n};\n\n/*********************************************************\n * Process manager\n *********************************************************/\n\nexport const PM = new ProcessManager.QueryProcessManager<AnyObject, AnyObject>(module, async data => {\n\tconst { userids, turnLimit, month, tierid } = data;\n\tconst start = Date.now();\n\ttry {\n\t\tconst result = await runBattleSearch(userids, month, tierid, turnLimit);\n\t\tconst elapsedTime = Date.now() - start;\n\t\tif (elapsedTime > 10 * 60 * 1000) {\n\t\t\tMonitor.slow(`[Slow battlesearch query] ${elapsedTime}ms: ${JSON.stringify(data)}`);\n\t\t}\n\t\treturn result;\n\t} catch (err) {\n\t\tMonitor.crashlog(err, 'A battle search query', {\n\t\t\tuserids,\n\t\t\tturnLimit,\n\t\t\tmonth,\n\t\t\ttierid,\n\t\t});\n\t}\n\treturn null;\n}, BATTLESEARCH_PROCESS_TIMEOUT, message => {\n\tif (message.startsWith('SLOW\\n')) {\n\t\tMonitor.slow(message.slice(5));\n\t}\n});\n\nif (!PM.isParentProcess) {\n\t// This is a child process!\n\tglobal.Config = require('../config-loader').Config;\n\tglobal.Monitor = {\n\t\tcrashlog(error: Error, source = 'A battle search process', details: AnyObject | null = null) {\n\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\n\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\n\t\t},\n\t\tslow(text: string) {\n\t\t\tprocess.send!(`CALLBACK\\nSLOW\\n${text}`);\n\t\t},\n\t};\n\tprocess.on('uncaughtException', err => {\n\t\tif (Config.crashguard) {\n\t\t\tMonitor.crashlog(err, 'A battle search child process');\n\t\t}\n\t});\n\tglobal.Dex = require('../../sim/dex').Dex;\n\tglobal.toID = Dex.toID;\n\t// eslint-disable-next-line no-eval\n\tRepl.start('battlesearch', cmd => eval(cmd));\n} else {\n\tPM.spawn(MAX_BATTLESEARCH_PROCESSES);\n}\n"], | |
"mappings": "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", | |
"names": ["buf"] | |
} | |