Spaces:
Running
Running
{ | |
"version": 3, | |
"sources": ["../../../tools/modlog/converter.ts"], | |
"sourcesContent": ["\n/**\n * Converts modlogs between text and SQLite; also modernizes old-format modlogs\n * @author Annika\n * @author jetou\n */\n\nif (!global.Config) {\n\tlet hasSQLite = true;\n\ttry {\n\t\trequire.resolve('better-sqlite3');\n\t} catch {\n\t\tconsole.warn(`Warning: the modlog conversion script is running without a SQLite library.`);\n\t\thasSQLite = false;\n\t}\n\tglobal.Config = {\n\t\tnofswriting: false,\n\t\tusesqlitemodlog: hasSQLite,\n\t\tusesqlite: hasSQLite,\n\t} as any;\n}\n\nimport type * as DatabaseType from 'better-sqlite3';\nimport type {ModlogEntry} from '../../server/modlog';\nimport {FS} from '../../lib';\nimport {IPTools} from '../../server/ip-tools';\n\nconst Database = Config.usesqlite ? require('better-sqlite3') : null;\nconst {Modlog} = require('../../server/modlog');\n\ntype ModlogFormat = 'txt' | 'sqlite';\n\n/** The number of modlog entries to write to the database on each transaction */\nconst ENTRIES_TO_BUFFER = 7500;\nconst ALTS_REGEX = /\\(.*?'s (lock|mut|bann|blacklist)ed alts: (.*)\\)/;\nconst AUTOCONFIRMED_REGEX = /\\(.*?'s ac account: (.*)\\)/;\n\nconst IP_ONLY_ACTIONS = new Set([\n\t'SHAREDIP', 'UNSHAREDIP', 'UNLOCKIP', 'UNLOCKRANGE', 'RANGEBAN', 'RANGELOCK',\n]);\n\nexport function parseBrackets(line: string, openingBracket: '(' | '[', greedy?: boolean) {\n\tconst brackets = {\n\t\t'(': ')',\n\t\t'[': ']',\n\t};\n\tconst bracketOpenIndex = line.indexOf(openingBracket);\n\tconst bracketCloseIndex = greedy ? line.lastIndexOf(brackets[openingBracket]) : line.indexOf(brackets[openingBracket]);\n\tif (bracketCloseIndex < 0 || bracketOpenIndex < 0) return '';\n\treturn line.slice(bracketOpenIndex + 1, bracketCloseIndex);\n}\n\nfunction toID(text: any): ID {\n\treturn (text && typeof text === \"string\" ? text : \"\").toLowerCase().replace(/[^a-z0-9]+/g, \"\") as ID;\n}\n\nexport function modernizeLog(line: string, nextLine?: string): string | undefined {\n\t// first we save and remove the timestamp and the roomname\n\tconst prefix = line.match(/\\[.+?\\] \\(.+?\\) /i)?.[0];\n\tif (!prefix) return;\n\tif (ALTS_REGEX.test(line) || AUTOCONFIRMED_REGEX.test(line)) return;\n\tline = line.replace(prefix, '');\n\t// handle duplicate room bug\n\tif (line.startsWith('(')) line = line.replace(/\\([a-z0-9-]*\\) /, '');\n\n\tif (line.startsWith('(') && line.endsWith(')')) {\n\t\tline = line.slice(1, -1);\n\t}\n\tconst getAlts = () => {\n\t\tlet alts = '';\n\t\tnextLine?.replace(ALTS_REGEX, (_a, _b, rawAlts) => {\n\t\t\tif (rawAlts) alts = `alts: [${rawAlts.split(',').map(toID).join('], [')}] `;\n\t\t\treturn '';\n\t\t});\n\t\treturn alts;\n\t};\n\n\tconst getAutoconfirmed = () => {\n\t\tlet autoconfirmed = '';\n\t\tnextLine?.replace(AUTOCONFIRMED_REGEX, (_a, rawAutoconfirmed) => {\n\t\t\tif (rawAutoconfirmed) autoconfirmed = `ac: [${toID(rawAutoconfirmed)}] `;\n\t\t\treturn '';\n\t\t});\n\t\treturn autoconfirmed;\n\t};\n\n\t// Special cases\n\n\tif (line.startsWith('SCAV ')) {\n\t\tline = line.replace(/: (\\[room: .*?\\]) by (.*)/, (match, roominfo, rest) => `: by ${rest} ${roominfo}`);\n\t}\n\tline = line.replace(\n\t\t/(GIVEAWAY WIN|GTS FINISHED): ([A-Za-z0-9].*?)(won|has finished)/,\n\t\t(match, action, user) => `${action}: [${toID(user)}]:`\n\t);\n\n\tif (line.includes(':')) {\n\t\tconst possibleModernAction = line.slice(0, line.indexOf(':')).trim();\n\t\tif (possibleModernAction === possibleModernAction.toUpperCase()) {\n\t\t\tif (possibleModernAction.includes('[')) {\n\t\t\t\t// for corrupted lines\n\t\t\t\tconst [drop, ...keep] = line.split('[');\n\t\t\t\tprocess.stderr.write(`Ignoring malformed line: ${drop}\\n`);\n\t\t\t\treturn modernizeLog(keep.join(''));\n\t\t\t}\n\t\t\tif (/\\(.+\\) by [a-z0-9]{1,19}$/.test(line) && !['OLD MODLOG', 'NOTE'].includes(possibleModernAction)) {\n\t\t\t\t// weird reason formatting\n\t\t\t\tconst reason = parseBrackets(line, '(', true);\n\t\t\t\treturn `${prefix}${line.replace(` (${reason})`, '')}: ${reason}`;\n\t\t\t}\n\t\t\t// Log is already modernized\n\t\t\treturn `${prefix}${line}`;\n\t\t}\n\t}\n\n\tif (/\\[(the|a)poll\\] was (started|ended) by/.test(line)) {\n\t\tconst actionTaker = toID(line.slice(line.indexOf(' by ') + ' by '.length));\n\t\tconst isEnding = line.includes('was ended by');\n\t\treturn `${prefix}POLL${isEnding ? ' END' : ''}: by ${actionTaker}`;\n\t}\n\tif (/User (.*?) won the game of (.*?) mode trivia/.test(line)) {\n\t\treturn `${prefix}TRIVIAGAME: by unknown: ${line}`;\n\t}\n\n\tconst modernizerTransformations: {[k: string]: (log: string) => string} = {\n\t\t'notes: ': (log) => {\n\t\t\tconst [actionTaker, ...rest] = line.split(' notes: ');\n\t\t\treturn `NOTE: by ${toID(actionTaker)}: ${rest.join('')}`;\n\t\t},\n\n\t\t' declared': (log) => {\n\t\t\tlet newAction = 'DECLARE';\n\t\t\tlet oldAction = ' declared';\n\t\t\tif (log.includes(' globally declared')) {\n\t\t\t\toldAction = ' globally declared';\n\t\t\t\tnewAction = 'GLOBALDECLARE';\n\t\t\t}\n\t\t\tif (log.includes('(chat level)')) {\n\t\t\t\toldAction += ' (chat level)';\n\t\t\t\tnewAction = `CHATDECLARE`;\n\t\t\t}\n\n\t\t\tconst actionTakerName = toID(log.slice(0, log.lastIndexOf(oldAction)));\n\n\t\t\tlog = log.slice(actionTakerName.length);\n\t\t\tlog = log.slice(oldAction.length);\n\t\t\tlog = log.replace(/^\\s?:/, '').trim();\n\t\t\treturn `${newAction}: by ${actionTakerName}: ${log}`;\n\t\t},\n\n\t\t'changed the roomdesc to: ': (log) => {\n\t\t\tconst actionTaker = parseBrackets(log, '[');\n\t\t\tlog = log.slice(actionTaker.length + 3);\n\t\t\tlog = log.slice('changed the roomdesc to: '.length + 1, -2);\n\t\t\treturn `ROOMDESC: by ${actionTaker}: to \"${log}\"`;\n\t\t},\n\n\t\t'roomevent titled \"': (log) => {\n\t\t\tlet action;\n\t\t\tif (log.includes(' added a roomevent titled \"')) {\n\t\t\t\taction = 'added a';\n\t\t\t} else if (log.includes(' removed a roomevent titled \"')) {\n\t\t\t\taction = 'removed a';\n\t\t\t} else {\n\t\t\t\taction = 'edited the';\n\t\t\t}\n\t\t\tconst actionTakerName = log.slice(0, log.lastIndexOf(` ${action} roomevent titled \"`));\n\t\t\tlog = log.slice(actionTakerName.length + 1);\n\t\t\tconst eventName = log.slice(` ${action} roomevent titled `.length, -2);\n\t\t\treturn `ROOMEVENT: by ${toID(actionTakerName)}: ${action.split(' ')[0]} \"${eventName}\"`;\n\t\t},\n\n\t\t'set modchat to ': (log) => {\n\t\t\tconst actionTaker = parseBrackets(log, '[');\n\t\t\tlog = log.slice(actionTaker.length + 3);\n\t\t\tlog = log.slice('set modchat to '.length);\n\t\t\treturn `MODCHAT: by ${actionTaker}: to ${log}`;\n\t\t},\n\t\t'set modjoin to ': (log) => {\n\t\t\tconst actionTakerName = log.slice(0, log.lastIndexOf(' set'));\n\t\t\tlog = log.slice(actionTakerName.length + 1);\n\t\t\tlog = log.slice('set modjoin to '.length);\n\t\t\tconst rank = log.startsWith('sync') ? 'sync' : log.replace('.', '');\n\t\t\treturn `MODJOIN${rank === 'sync' ? ' SYNC' : ''}: by ${toID(actionTakerName)}${rank !== 'sync' ? `: ${rank}` : ``}`;\n\t\t},\n\t\t'turned off modjoin': (log) => {\n\t\t\tconst actionTakerName = log.slice(0, log.lastIndexOf(' turned off modjoin'));\n\t\t\treturn `MODJOIN: by ${toID(actionTakerName)}: OFF`;\n\t\t},\n\n\t\t'changed the roomintro': (log) => {\n\t\t\tconst isDeletion = /deleted the (staff|room)intro/.test(log);\n\t\t\tconst isRoomintro = log.includes('roomintro');\n\t\t\tconst actionTaker = toID(log.slice(0, log.indexOf(isDeletion ? 'deleted' : 'changed')));\n\t\t\treturn `${isDeletion ? 'DELETE' : ''}${isRoomintro ? 'ROOM' : 'STAFF'}INTRO: by ${actionTaker}`;\n\t\t},\n\t\t'deleted the roomintro': (log) => modernizerTransformations['changed the roomintro'](log),\n\t\t'changed the staffintro': (log) => modernizerTransformations['changed the roomintro'](log),\n\t\t'deleted the staffintro': (log) => modernizerTransformations['changed the roomintro'](log),\n\n\t\t'created a tournament in': (log) => {\n\t\t\tconst actionTaker = parseBrackets(log, '[');\n\t\t\tlog = log.slice(actionTaker.length + 3);\n\t\t\tlog = log.slice(24, -8);\n\t\t\treturn `TOUR CREATE: by ${actionTaker}: ${log}`;\n\t\t},\n\t\t'was disqualified from the tournament by': (log) => {\n\t\t\tconst disqualified = parseBrackets(log, '[');\n\t\t\tlog = log.slice(disqualified.length + 3);\n\t\t\tlog = log.slice('was disqualified from the tournament by'.length);\n\t\t\treturn `TOUR DQ: [${toID(disqualified)}] by ${toID(log)}`;\n\t\t},\n\t\t'The tournament auto disqualify timeout was set to': (log) => {\n\t\t\tconst byIndex = log.indexOf(' by ');\n\t\t\tconst actionTaker = log.slice(byIndex + ' by '.length);\n\t\t\tconst length = log.slice('The tournament auto disqualify timeout was set to'.length, byIndex);\n\t\t\treturn `TOUR AUTODQ: by ${toID(actionTaker)}: ${length.trim()}`;\n\t\t},\n\n\t\t' was blacklisted from ': (log) => {\n\t\t\tconst isName = log.includes(' was nameblacklisted from ');\n\t\t\tconst banned = toID(log.slice(0, log.indexOf(` was ${isName ? 'name' : ''}blacklisted from `)));\n\t\t\tlog = log.slice(log.indexOf(' by ') + ' by '.length);\n\t\t\tlet reason, ip;\n\t\t\tif (/\\(.*\\)/.test(log)) {\n\t\t\t\treason = parseBrackets(log, '(');\n\t\t\t\tif (/\\[.*\\]/.test(log)) ip = parseBrackets(log, '[');\n\t\t\t\tlog = log.slice(0, log.indexOf('('));\n\t\t\t}\n\t\t\tconst actionTaker = toID(log);\n\t\t\treturn `${isName ? 'NAME' : ''}BLACKLIST: [${banned}] ${getAutoconfirmed()}${getAlts()}${ip ? `[${ip}] ` : ``}by ${actionTaker}${reason ? `: ${reason}` : ``}`;\n\t\t},\n\t\t' was nameblacklisted from ': (log) => modernizerTransformations[' was blacklisted from '](log),\n\t\t' was banned from room ': (log) => {\n\t\t\tconst banned = toID(log.slice(0, log.indexOf(' was banned from room ')));\n\t\t\tlog = log.slice(log.indexOf(' by ') + ' by '.length);\n\t\t\tlet reason, ip;\n\t\t\tif (/\\(.*\\)/.test(log)) {\n\t\t\t\treason = parseBrackets(log, '(');\n\t\t\t\tif (/\\[.*\\]/.test(log)) ip = parseBrackets(log, '[');\n\t\t\t\tlog = log.slice(0, log.indexOf('('));\n\t\t\t}\n\t\t\tconst actionTaker = toID(log);\n\t\t\treturn `ROOMBAN: [${banned}] ${getAutoconfirmed()}${getAlts()}${ip ? `[${ip}] ` : ``}by ${actionTaker}${reason ? `: ${reason}` : ``}`;\n\t\t},\n\t\t' was muted by ': (log) => {\n\t\t\tlet muted = '';\n\t\t\tlet isHour = false;\n\t\t\t[muted, log] = log.split(' was muted by ');\n\t\t\tmuted = toID(muted);\n\t\t\tlet reason, ip;\n\t\t\tif (/\\(.*\\)/.test(log)) {\n\t\t\t\treason = parseBrackets(log, '(');\n\t\t\t\tif (/\\[.*\\]/.test(log)) ip = parseBrackets(log, '[');\n\t\t\t\tlog = log.slice(0, log.indexOf('('));\n\t\t\t}\n\t\t\tlet actionTaker = toID(log);\n\t\t\tif (actionTaker.endsWith('for1hour')) {\n\t\t\t\tisHour = true;\n\t\t\t\tactionTaker = actionTaker.replace(/^(.*)(for1hour)$/, (match, staff) => staff) as ID;\n\t\t\t}\n\t\t\treturn `${isHour ? 'HOUR' : ''}MUTE: [${muted}] ${getAutoconfirmed()}${getAlts()}${ip ? `[${ip}] ` : ``}by ${actionTaker}${reason ? `: ${reason}` : ``}`;\n\t\t},\n\t\t' was locked from talking ': (log) => {\n\t\t\tconst isWeek = log.includes(' was locked from talking for a week ');\n\t\t\tconst locked = toID(log.slice(0, log.indexOf(' was locked from talking ')));\n\t\t\tlog = log.slice(log.indexOf(' by ') + ' by '.length);\n\t\t\tlet reason, ip;\n\t\t\tif (/\\(.*\\)/.test(log)) {\n\t\t\t\treason = parseBrackets(log, '(');\n\t\t\t\tif (/\\[.*\\]/.test(log)) ip = parseBrackets(log, '[');\n\t\t\t\tlog = log.slice(0, log.indexOf('('));\n\t\t\t}\n\t\t\tconst actionTaker = toID(log);\n\t\t\treturn `${isWeek ? 'WEEK' : ''}LOCK: [${locked}] ${getAutoconfirmed()}${getAlts()}${ip ? `[${ip}] ` : ``}by ${actionTaker}${reason ? `: ${reason}` : ``}`;\n\t\t},\n\t\t' was banned ': (log) => {\n\t\t\tif (log.includes(' was banned from room ')) return modernizerTransformations[' was banned from room '](log);\n\t\t\tconst banned = toID(log.slice(0, log.indexOf(' was banned ')));\n\t\t\tlog = log.slice(log.indexOf(' by ') + ' by '.length);\n\t\t\tlet reason, ip;\n\t\t\tif (/\\(.*\\)/.test(log)) {\n\t\t\t\treason = parseBrackets(log, '(');\n\t\t\t\tif (/\\[.*\\]/.test(log)) ip = parseBrackets(log, '[');\n\t\t\t\tlog = log.slice(0, log.indexOf('('));\n\t\t\t}\n\t\t\tconst actionTaker = toID(log);\n\t\t\treturn `BAN: [${banned}] ${getAutoconfirmed()}${getAlts()}${ip ? `[${ip}] ` : ``}by ${actionTaker}${reason ? `: ${reason}` : ``}`;\n\t\t},\n\n\t\t'was promoted to ': (log) => {\n\t\t\tconst isDemotion = log.includes('was demoted to ');\n\t\t\tconst userid = toID(log.split(' was ')[0]);\n\t\t\tif (!userid) {\n\t\t\t\tthrow new Error(`Ignoring malformed line: ${prefix}${log}`);\n\t\t\t}\n\t\t\tlog = log.slice(userid.length + 3);\n\t\t\tlog = log.slice(`was ${isDemotion ? 'demoted' : 'promoted'} to `.length);\n\t\t\tlet rank = log.slice(0, log.indexOf(' by')).replace(/ /, '').toUpperCase();\n\n\t\t\tlog = log.slice(`${rank} by `.length);\n\t\t\tif (!rank.startsWith('ROOM')) rank = `GLOBAL ${rank}`;\n\t\t\tconst actionTaker = parseBrackets(log, '[');\n\t\t\treturn `${rank}: [${userid}] by ${actionTaker}${isDemotion ? ': (demote)' : ''}`;\n\t\t},\n\t\t'was demoted to ': (log) => modernizerTransformations['was promoted to '](log),\n\t\t'was appointed Room Owner by ': (log) => {\n\t\t\tconst userid = parseBrackets(log, '[');\n\t\t\tlog = log.slice(userid.length + 3);\n\t\t\tlog = log.slice('was appointed Room Owner by '.length);\n\t\t\tconst actionTaker = parseBrackets(log, '[');\n\t\t\treturn `ROOMOWNER: [${userid}] by ${actionTaker}`;\n\t\t},\n\n\t\t' claimed this ticket': (log) => {\n\t\t\tconst actions: {[k: string]: string} = {\n\t\t\t\t' claimed this ticket': 'TICKETCLAIM',\n\t\t\t\t' closed this ticket': 'TICKETCLOSE',\n\t\t\t\t' deleted this ticket': 'TICKETDELETE',\n\t\t\t};\n\t\t\tfor (const oldAction in actions) {\n\t\t\t\tif (log.includes(oldAction)) {\n\t\t\t\t\tconst actionTaker = toID(log.slice(0, log.indexOf(oldAction)));\n\t\t\t\t\treturn `${actions[oldAction]}: by ${actionTaker}`;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn log;\n\t\t},\n\t\t'This ticket is now claimed by ': (log) => {\n\t\t\tconst claimer = toID(log.slice(log.indexOf(' by ') + ' by '.length));\n\t\t\treturn `TICKETCLAIM: by ${claimer}`;\n\t\t},\n\t\t' is no longer interested in this ticket': (log) => {\n\t\t\tconst abandoner = toID(log.slice(0, log.indexOf(' is no longer interested in this ticket')));\n\t\t\treturn `TICKETABANDON: by ${abandoner}`;\n\t\t},\n\t\t' opened a new ticket': (log) => {\n\t\t\tconst opener = toID(log.slice(0, log.indexOf(' opened a new ticket')));\n\t\t\tconst problem = log.slice(log.indexOf(' Issue: ') + ' Issue: '.length).trim();\n\t\t\treturn `TICKETOPEN: by ${opener}: ${problem}`;\n\t\t},\n\t\t' closed this ticket': (log) => modernizerTransformations[' claimed this ticket'](log),\n\t\t' deleted this ticket': (log) => modernizerTransformations[' claimed this ticket'](log),\n\t\t'This ticket is no longer claimed': () => 'TICKETUNCLAIM',\n\n\t\t' has been caught attempting a hunt with ': (log) => {\n\t\t\tconst index = log.indexOf(' has been caught attempting a hunt with ');\n\t\t\tconst user = toID(log.slice(0, index));\n\t\t\tlog = log.slice(index + ' has been caught attempting a hunt with '.length);\n\t\t\tlog = log.replace('. The user has also', '; has also').replace('.', '');\n\t\t\treturn `SCAV CHEATER: [${user}]: caught attempting a hunt with ${log}`;\n\t\t},\n\n\t\t'made this room hidden': (log) => {\n\t\t\tconst user = toID(log.slice(0, log.indexOf(' made this room hidden')));\n\t\t\treturn `HIDDENROOM: by ${user}`;\n\t\t},\n\n\t\t'The tournament auto start timer was set to ': (log) => {\n\t\t\tlog = log.slice('The tournament auto start timer was set to'.length);\n\t\t\tconst [length, setter] = log.split(' by ').map(toID);\n\t\t\treturn `TOUR AUTOSTART: by ${setter}: ${length}`;\n\t\t},\n\t\t'The tournament auto disqualify timer was set to ': (log) => {\n\t\t\tlog = log.slice('The tournament auto disqualify timer was set to'.length);\n\t\t\tconst [length, setter] = log.split(' by ').map(toID);\n\t\t\treturn `TOUR AUTODQ: by ${setter}: ${length}`;\n\t\t},\n\t\t\" set the tournament's banlist to \": (log) => {\n\t\t\tconst [setter, banlist] = log.split(` set the tournament's banlist to `);\n\t\t\treturn `TOUR BANLIST: by ${toID(setter)}: ${banlist.slice(0, -1)}`; // remove trailing . from banlist\n\t\t},\n\t\t\" set the tournament's custom rules to\": (log) => {\n\t\t\tconst [setter, rules] = log.split(` set the tournament's custom rules to `);\n\t\t\treturn `TOUR RULES: by ${toID(setter)}: ${rules.slice(0, -1)}`;\n\t\t},\n\t\t'[agameofhangman] was started by ': (log) => `HANGMAN: by ${toID(log.slice('[agameofhangman] was started by '.length))}`,\n\t\t'[agameofunowas] created by ': (log) => `UNO CREATE: by ${toID(log.slice('[agameofunowas] created by '.length))}`,\n\t\t'[thetournament] was set to autostart': (log) => {\n\t\t\tconst [, user] = log.split(' by ');\n\t\t\treturn `TOUR AUTOSTART: by ${toID(user)}: when playercap is reached`;\n\t\t},\n\t\t'[thetournament] was set to allow scouting': (log) => {\n\t\t\tconst [, user] = log.split(' by ');\n\t\t\treturn `TOUR SCOUT: by ${toID(user)}: allow`;\n\t\t},\n\t\t'[thetournament] was set to disallow scouting': (log) => {\n\t\t\tconst [, user] = log.split(' by ');\n\t\t\treturn `TOUR SCOUT: by ${toID(user)}: disallow`;\n\t\t},\n\t};\n\n\tfor (const oldAction in modernizerTransformations) {\n\t\tif (line.includes(oldAction)) {\n\t\t\ttry {\n\t\t\t\treturn prefix + modernizerTransformations[oldAction](line);\n\t\t\t} catch (err: any) {\n\t\t\t\tif (Config.nofswriting) throw err;\n\t\t\t\tprocess.stderr.write(`${err.message}\\n`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn `${prefix}${line}`;\n}\n\nexport function parseModlog(raw: string, nextLine?: string, isGlobal = false): ModlogEntry | undefined {\n\tlet line = modernizeLog(raw);\n\tif (!line) return;\n\n\tconst timestamp = parseBrackets(line, '[');\n\tline = line.slice(timestamp.length + 3);\n\tconst [roomID, ...bonus] = parseBrackets(line, '(').split(' ');\n\n\tconst log: ModlogEntry = {\n\t\taction: 'NULL',\n\t\troomID,\n\t\tvisualRoomID: '',\n\t\tuserid: null,\n\t\tautoconfirmedID: null,\n\t\talts: [],\n\t\tip: null,\n\t\tisGlobal,\n\t\tloggedBy: null,\n\t\tnote: '',\n\t\ttime: Math.floor(new Date(timestamp).getTime()) || 0,\n\t};\n\n\tif (bonus.length) log.visualRoomID = `${log.roomID} ${bonus.join(' ')}`;\n\tline = line.slice((log.visualRoomID || log.roomID).length + 3);\n\tconst actionColonIndex = line.indexOf(':');\n\tconst action = line.slice(0, actionColonIndex);\n\tif (action !== action.toUpperCase()) {\n\t\t// no action (probably an old-format log that slipped past the modernizer)\n\t\tlog.action = 'OLD MODLOG';\n\t\tlog.loggedBy = 'unknown' as ID;\n\t\tlog.note = line.trim();\n\t\treturn log;\n\t} else {\n\t\tlog.action = action;\n\t\tif (log.action === 'OLD MODLOG') {\n\t\t\tlog.loggedBy = 'unknown' as ID;\n\t\t\tlog.note = line.slice(line.indexOf('by unknown: ') + 'by unknown :'.length).trim();\n\t\t\treturn log;\n\t\t}\n\t\tline = line.slice(actionColonIndex + 2);\n\t}\n\n\tif (line[0] === '[') {\n\t\tif (!IP_ONLY_ACTIONS.has(log.action)) {\n\t\t\tconst userid = toID(parseBrackets(line, '['));\n\t\t\tlog.userid = userid;\n\t\t\tline = line.slice(userid.length + 3).trim();\n\t\t\tif (line.startsWith('ac:')) {\n\t\t\t\tline = line.slice(3).trim();\n\t\t\t\tconst ac = parseBrackets(line, '[');\n\t\t\t\tlog.autoconfirmedID = toID(ac);\n\t\t\t\tline = line.slice(ac.length + 3).trim();\n\t\t\t}\n\t\t\tif (line.startsWith('alts:')) {\n\t\t\t\tline = line.slice(5).trim();\n\t\t\t\tconst alts = new Set<ID>(); // we need to weed out duplicate alts\n\n\t\t\t\tlet alt = parseBrackets(line, '[');\n\t\t\t\tdo {\n\t\t\t\t\tif (alt.includes(', ')) {\n\t\t\t\t\t\t// old alt format\n\t\t\t\t\t\tfor (const trueAlt of alt.split(', ')) {\n\t\t\t\t\t\t\talts.add(toID(trueAlt));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tline = line.slice(line.indexOf(`[${alt}],`) + `[${alt}],`.length).trim();\n\t\t\t\t\t\tif (!line.startsWith('[')) line = `[${line}`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (IPTools.ipRegex.test(alt)) break;\n\t\t\t\t\t\talts.add(toID(alt));\n\t\t\t\t\t\tline = line.slice(line.indexOf(`[${alt}],`) + `[${alt}],`.length).trim();\n\t\t\t\t\t\tif (alt.includes('[') && !line.startsWith('[')) line = `[${line}`;\n\t\t\t\t\t}\n\t\t\t\t\talt = parseBrackets(line, '[');\n\t\t\t\t} while (alt);\n\t\t\t\tlog.alts = [...alts];\n\t\t\t}\n\t\t}\n\t\tif (line[0] === '[') {\n\t\t\tlog.ip = parseBrackets(line, '[');\n\t\t\tline = line.slice(log.ip.length + 3).trim();\n\t\t}\n\t}\n\n\tlet regex = /\\bby .*:/;\n\tlet actionTakerIndex = regex.exec(line)?.index;\n\tif (actionTakerIndex === undefined) {\n\t\tactionTakerIndex = line.indexOf('by ');\n\t\tregex = /\\bby .*/;\n\t}\n\tif (actionTakerIndex !== -1) {\n\t\tconst colonIndex = line.indexOf(': ');\n\t\tconst actionTaker = line.slice(actionTakerIndex + 3, colonIndex > actionTakerIndex ? colonIndex : undefined);\n\t\tif (toID(actionTaker).length < 19) {\n\t\t\tlog.loggedBy = toID(actionTaker) || null;\n\t\t\tif (colonIndex > actionTakerIndex) line = line.slice(colonIndex);\n\t\t\tline = line.replace(regex, ' ');\n\t\t}\n\t}\n\tif (line) log.note = line.replace(/^\\s?:\\s?/, '').trim();\n\treturn log;\n}\n\nexport function rawifyLog(log: ModlogEntry) {\n\tlet result = `[${new Date(log.time || Date.now()).toJSON()}] (${(log.visualRoomID || log.roomID || 'global').replace(/^global-/, '')}) ${log.action}`;\n\tif (log.userid) result += `: [${log.userid}]`;\n\tif (log.autoconfirmedID) result += ` ac: [${log.autoconfirmedID}]`;\n\tif (log.alts.length) result += ` alts: [${log.alts.join('], [')}]`;\n\tif (log.ip) {\n\t\tif (!log.userid) result += `:`;\n\t\tresult += ` [${log.ip}]`;\n\t}\n\tif (log.loggedBy) result += `${result.endsWith(']') ? '' : ':'} by ${log.loggedBy}`;\n\tif (log.note) result += `: ${log.note}`;\n\treturn result + `\\n`;\n}\n\nexport class ModlogConverterSQLite {\n\treadonly databaseFile: string;\n\treadonly textLogDir: string;\n\treadonly isTesting: {files: Map<string, string>, db: DatabaseType.Database} | null = null;\n\treadonly newestAllowedTimestamp?: number;\n\n\tconstructor(\n\t\tdatabaseFile: string, textLogDir: string,\n\t\tisTesting?: DatabaseType.Database, newestAllowedTimestamp?: number\n\t) {\n\t\tthis.databaseFile = databaseFile;\n\t\tthis.textLogDir = textLogDir;\n\t\tif (isTesting || Config.nofswriting) {\n\t\t\tthis.isTesting = {files: new Map<string, string>(), db: isTesting || new Database(':memory:')};\n\t\t}\n\t\tthis.newestAllowedTimestamp = newestAllowedTimestamp;\n\t}\n\n\tasync toTxt() {\n\t\tconst database = this.isTesting?.db || new Database(this.databaseFile, {fileMustExist: true});\n\t\tconst roomids = database.prepare('SELECT DISTINCT roomid FROM modlog').all();\n\t\tconst globalEntries = [];\n\t\tfor (const {roomid} of roomids) {\n\t\t\tif (!Config.nofswriting) console.log(`Reading ${roomid}...`);\n\t\t\tconst results = database.prepare(\n\t\t\t\t`SELECT *, (SELECT group_concat(userid, ',') FROM alts WHERE alts.modlog_id = modlog.modlog_id) as alts ` +\n\t\t\t\t`FROM modlog WHERE roomid = ? ORDER BY timestamp ASC`\n\t\t\t).all(roomid);\n\n\t\t\tconst trueRoomID = roomid.replace(/^global-/, '');\n\n\t\t\tlet entriesLogged = 0;\n\t\t\tlet entries: string[] = [];\n\n\t\t\tconst insertEntries = async () => {\n\t\t\t\tif (roomid === 'global') return;\n\t\t\t\tentriesLogged += entries.length;\n\t\t\t\tif (!Config.nofswriting && (entriesLogged % ENTRIES_TO_BUFFER === 0 || entriesLogged < ENTRIES_TO_BUFFER)) {\n\t\t\t\t\tprocess.stdout.clearLine(0);\n\t\t\t\t\tprocess.stdout.cursorTo(0);\n\t\t\t\t\tprocess.stdout.write(`Wrote ${entriesLogged} entries from '${trueRoomID}'`);\n\t\t\t\t}\n\t\t\t\tawait this.writeFile(`${this.textLogDir}/modlog_${trueRoomID}.txt`, entries.join(''));\n\t\t\t\tentries = [];\n\t\t\t};\n\n\t\t\tfor (const result of results) {\n\t\t\t\tif (this.newestAllowedTimestamp && result.timestamp > this.newestAllowedTimestamp) break;\n\t\t\t\tconst entry: ModlogEntry = {\n\t\t\t\t\taction: result.action,\n\t\t\t\t\troomID: result.roomid?.replace(/^global-/, ''),\n\t\t\t\t\tvisualRoomID: result.visual_roomid,\n\t\t\t\t\tuserid: result.userid,\n\t\t\t\t\tautoconfirmedID: result.autoconfirmed_userid,\n\t\t\t\t\talts: result.alts?.split(','),\n\t\t\t\t\tip: result.ip,\n\t\t\t\t\tisGlobal: result.roomid?.startsWith('global-') || result.roomid === 'global' || result.is_global,\n\t\t\t\t\tloggedBy: result.action_taker_userid,\n\t\t\t\t\tnote: result.note,\n\t\t\t\t\ttime: result.timestamp,\n\t\t\t\t};\n\n\t\t\t\tconst rawLog = rawifyLog(entry);\n\t\t\t\tentries.push(rawLog);\n\t\t\t\tif (entry.isGlobal) {\n\t\t\t\t\tglobalEntries.push(rawLog);\n\t\t\t\t}\n\t\t\t\tif (entries.length === ENTRIES_TO_BUFFER) await insertEntries();\n\t\t\t}\n\t\t\tawait insertEntries();\n\t\t\tif (entriesLogged) process.stdout.write('\\n');\n\t\t}\n\t\tif (!Config.nofswriting) console.log(`Writing the global modlog...`);\n\t\tawait this.writeFile(`${this.textLogDir}/modlog_global.txt`, globalEntries.join(''));\n\t}\n\n\tasync writeFile(path: string, text: string) {\n\t\tif (this.isTesting) {\n\t\t\tconst old = this.isTesting.files.get(path);\n\t\t\treturn this.isTesting.files.set(path, `${old || ''}${text}`);\n\t\t}\n\t\treturn FS(path).append(text);\n\t}\n}\n\nexport class ModlogConverterTxt {\n\treadonly databaseFile: string;\n\treadonly modlog: typeof Modlog;\n\treadonly newestAllowedTimestamp?: number;\n\n\treadonly textLogDir: string;\n\treadonly isTesting: {files: Map<string, string>, ml?: typeof Modlog} | null = null;\n\tconstructor(\n\t\tdatabaseFile: string,\n\t\ttextLogDir: string,\n\t\tisTesting?: Map<string, string>,\n\t\tnewestAllowedTimestamp?: number\n\t) {\n\t\tthis.databaseFile = databaseFile;\n\t\tthis.textLogDir = textLogDir;\n\t\tif (isTesting || Config.nofswriting) {\n\t\t\tthis.isTesting = {\n\t\t\t\tfiles: isTesting || new Map<string, string>(),\n\t\t\t};\n\t\t}\n\n\t\tthis.modlog = new Modlog(\n\t\t\tthis.isTesting ? ':memory:' : this.databaseFile,\n\t\t\t// wait 15 seconds for DB to no longer be busy - this is important since I'm trying to do\n\t\t\t// a no-downtime transfer of text -> SQLite\n\t\t\t{sqliteOptions: {timeout: 15000}},\n\t\t);\n\t\tthis.newestAllowedTimestamp = newestAllowedTimestamp;\n\t}\n\n\tasync toSQLite() {\n\t\tawait this.modlog.readyPromise;\n\t\tconst files = this.isTesting ? [...this.isTesting.files.keys()] : await FS(this.textLogDir).readdir();\n\t\t// Read global modlog first to avoid inserting duplicate data to database\n\t\tif (files.includes('modlog_global.txt')) {\n\t\t\tfiles.splice(files.indexOf('modlog_global.txt'), 1);\n\t\t\tfiles.unshift('modlog_global.txt');\n\t\t}\n\n\t\t// we don't want to insert global modlog entries twice, so we keep track of global ones\n\t\t// and don't reinsert them\n\t\t/** roomid:list of modlog entry strings */\n\t\tconst globalEntries: {[k: string]: string[]} = {};\n\n\t\tfor (const file of files) {\n\t\t\tif (file === 'README.md') continue;\n\t\t\tconst roomid = file.slice(7, -4);\n\t\t\tconst lines = this.isTesting ?\n\t\t\t\tthis.isTesting.files.get(file)?.split('\\n') || [] :\n\t\t\t\tFS(`${this.textLogDir}/${file}`).createReadStream().byLine();\n\n\t\t\tlet entriesLogged = 0;\n\t\t\tlet lastLine = undefined;\n\t\t\tlet entries: ModlogEntry[] = [];\n\t\t\tconst insertEntries = async () => {\n\t\t\t\tawait this.modlog.writeSQL(entries);\n\t\t\t\tentriesLogged += entries.length;\n\t\t\t\tif (!Config.nofswriting) {\n\t\t\t\t\tprocess.stdout.clearLine(0);\n\t\t\t\t\tprocess.stdout.cursorTo(0);\n\t\t\t\t\tprocess.stdout.write(`Inserted ${entriesLogged} entries from '${roomid}'`);\n\t\t\t\t}\n\t\t\t\tentries = [];\n\t\t\t};\n\n\t\t\tfor await (const line of lines) {\n\t\t\t\tconst entry = parseModlog(line, lastLine, roomid === 'global');\n\t\t\t\tlastLine = line;\n\t\t\t\tif (!entry) continue;\n\t\t\t\tif (this.newestAllowedTimestamp && entry.time > this.newestAllowedTimestamp) break;\n\t\t\t\tif (roomid !== 'global' && globalEntries[entry.roomID]?.includes(line)) {\n\t\t\t\t\t// this is a global modlog entry that has already been inserted\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (entry.isGlobal) {\n\t\t\t\t\tif (!globalEntries[entry.roomID]) globalEntries[entry.roomID] = [];\n\t\t\t\t\tglobalEntries[entry.roomID].push(line);\n\t\t\t\t}\n\t\t\t\tentries.push(entry);\n\t\t\t\tif (entries.length === ENTRIES_TO_BUFFER) await insertEntries();\n\t\t\t}\n\t\t\tdelete globalEntries[roomid];\n\t\t\tawait insertEntries();\n\t\t\tif (entriesLogged) process.stdout.write('\\n');\n\t\t}\n\t\treturn this.modlog.database;\n\t}\n}\n\nexport class ModlogConverterTest {\n\treadonly inputDir: string;\n\treadonly outputDir: string;\n\n\tconstructor(inputDir: string, outputDir: string) {\n\t\tthis.inputDir = inputDir;\n\t\tthis.outputDir = outputDir;\n\t}\n\n\tasync toTxt() {\n\t\tconst files = await FS(this.inputDir).readdir();\n\t\t// Read global modlog last to avoid inserting duplicate data to database\n\t\tif (files.includes('modlog_global.txt')) {\n\t\t\tfiles.splice(files.indexOf('modlog_global.txt'), 1);\n\t\t\tfiles.push('modlog_global.txt');\n\t\t}\n\n\t\tconst globalEntries = [];\n\n\t\tfor (const file of files) {\n\t\t\tif (file === 'README.md') continue;\n\t\t\tconst roomid = file.slice(7, -4);\n\n\t\t\tlet entriesLogged = 0;\n\t\t\tlet lastLine = undefined;\n\t\t\tlet entries: string[] = [];\n\n\t\t\tconst insertEntries = async () => {\n\t\t\t\tif (roomid === 'global') return;\n\t\t\t\tentriesLogged += entries.length;\n\t\t\t\tif (!Config.nofswriting && (entriesLogged % ENTRIES_TO_BUFFER === 0 || entriesLogged < ENTRIES_TO_BUFFER)) {\n\t\t\t\t\tprocess.stdout.clearLine(0);\n\t\t\t\t\tprocess.stdout.cursorTo(0);\n\t\t\t\t\tprocess.stdout.write(`Wrote ${entriesLogged} entries from '${roomid}'`);\n\t\t\t\t}\n\t\t\t\tawait FS(`${this.outputDir}/modlog_${roomid}.txt`).append(entries.join(''));\n\t\t\t\tentries = [];\n\t\t\t};\n\n\t\t\tconst readStream = FS(`${this.inputDir}/${file}`).createReadStream();\n\t\t\tfor await (const line of readStream.byLine()) {\n\t\t\t\tconst entry = parseModlog(line, lastLine, roomid === 'global');\n\t\t\t\tlastLine = line;\n\t\t\t\tif (!entry) continue;\n\t\t\t\tconst rawLog = rawifyLog(entry);\n\t\t\t\tif (roomid !== 'global') entries.push(rawLog);\n\t\t\t\tif (entry.isGlobal) {\n\t\t\t\t\tglobalEntries.push(rawLog);\n\t\t\t\t}\n\t\t\t\tif (entries.length === ENTRIES_TO_BUFFER) await insertEntries();\n\t\t\t}\n\t\t\tawait insertEntries();\n\t\t\tif (entriesLogged) process.stdout.write('\\n');\n\t\t}\n\n\t\tif (!Config.nofswriting) console.log(`Writing the global modlog...`);\n\t\tawait FS(`${this.outputDir}/modlog_global.txt`).append(globalEntries.join(''));\n\t}\n}\n\nexport const ModlogConverter = {\n\tasync convert(\n\t\tfrom: ModlogFormat, to: ModlogFormat, databasePath: string,\n\t\ttextLogDirectoryPath: string, outputLogPath?: string, newestAllowedTimestamp?: number,\n\t) {\n\t\tif (from === 'txt' && to === 'txt' && outputLogPath) {\n\t\t\tconst converter = new ModlogConverterTest(textLogDirectoryPath, outputLogPath);\n\t\t\tawait converter.toTxt();\n\t\t\tconsole.log(\"\\nDone!\");\n\t\t\tprocess.exit();\n\t\t} else if (from === 'sqlite' && to === 'txt') {\n\t\t\tconst converter = new ModlogConverterSQLite(databasePath, textLogDirectoryPath, undefined, newestAllowedTimestamp);\n\t\t\tawait converter.toTxt();\n\t\t\tconsole.log(\"\\nDone!\");\n\t\t\tprocess.exit();\n\t\t} else if (from === 'txt' && to === 'sqlite') {\n\t\t\tconst converter = new ModlogConverterTxt(databasePath, textLogDirectoryPath, undefined, newestAllowedTimestamp);\n\t\t\tawait converter.toSQLite();\n\t\t\tconsole.log(\"\\nDone!\");\n\t\t\tprocess.exit();\n\t\t}\n\t},\n};\n"], | |
"mappings": "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", | |
"names": [] | |
} | |