|
| 1 | +lia.log = lia.log or {} |
| 2 | +lia.log.types = lia.log.types or {} |
| 3 | +if SERVER then |
| 4 | + lia.log.isConverting = lia.log.isConverting or false |
| 5 | + local function createLogsTable() |
| 6 | + if lia.db.module == "sqlite" then |
| 7 | + lia.db.query([[CREATE TABLE IF NOT EXISTS lia_logs ( |
| 8 | + _id INTEGER PRIMARY KEY AUTOINCREMENT, |
| 9 | + _timestamp DATETIME, |
| 10 | + _gamemode VARCHAR, |
| 11 | + _category VARCHAR, |
| 12 | + _message TEXT, |
| 13 | + _charID INTEGER, |
| 14 | + _steamID VARCHAR |
| 15 | + );]]) |
| 16 | + else |
| 17 | + lia.db.query([[CREATE TABLE IF NOT EXISTS `lia_logs` ( |
| 18 | + `_id` INT(12) NOT NULL AUTO_INCREMENT, |
| 19 | + `_timestamp` DATETIME NOT NULL, |
| 20 | + `_gamemode` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', |
| 21 | + `_category` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci', |
| 22 | + `_message` TEXT NOT NULL COLLATE 'utf8mb4_general_ci', |
| 23 | + `_charID` INT(12) NULL, |
| 24 | + `_steamID` VARCHAR(20) NULL COLLATE 'utf8mb4_general_ci', |
| 25 | + PRIMARY KEY (`_id`) |
| 26 | + );]]) |
| 27 | + end |
| 28 | + end |
| 29 | + |
| 30 | + local function checkLegacyLogs() |
| 31 | + local baseDir = "lilia/logs" |
| 32 | + local found = false |
| 33 | + local files, dirs = file.Find(baseDir .. "/*", "DATA") |
| 34 | + for _, fileName in ipairs(files) do |
| 35 | + if fileName:sub(-4) == ".txt" then |
| 36 | + found = true |
| 37 | + break |
| 38 | + end |
| 39 | + end |
| 40 | + |
| 41 | + if not found then |
| 42 | + for _, gm in ipairs(dirs) do |
| 43 | + local f = file.Find(baseDir .. "/" .. gm .. "/*.txt", "DATA") |
| 44 | + if #f > 0 then |
| 45 | + found = true |
| 46 | + break |
| 47 | + end |
| 48 | + end |
| 49 | + end |
| 50 | + |
| 51 | + if not found then return end |
| 52 | + lia.db.count("logs"):next(function(n) if n == 0 then lia.log.convertToDatabase(true) end end) |
| 53 | + end |
| 54 | + |
| 55 | + function lia.log.loadTables() |
| 56 | + file.CreateDir("lilia/logs/" .. engine.ActiveGamemode()) |
| 57 | + lia.db.waitForTablesToLoad():next(function() |
| 58 | + createLogsTable() |
| 59 | + checkLegacyLogs() |
| 60 | + end) |
| 61 | + end |
| 62 | + |
| 63 | + function lia.log.addType(logType, func, category) |
| 64 | + lia.log.types[logType] = { |
| 65 | + func = func, |
| 66 | + category = category, |
| 67 | + } |
| 68 | + end |
| 69 | + |
| 70 | + function lia.log.getString(client, logType, ...) |
| 71 | + local logData = lia.log.types[logType] |
| 72 | + if not logData then return end |
| 73 | + if isfunction(logData.func) then |
| 74 | + local success, result = pcall(logData.func, client, ...) |
| 75 | + if success then return result, logData.category end |
| 76 | + end |
| 77 | + end |
| 78 | + |
| 79 | + function lia.log.add(client, logType, ...) |
| 80 | + local logString, category = lia.log.getString(client, logType, ...) |
| 81 | + if not isstring(category) then category = "Uncategorized" end |
| 82 | + if not isstring(logString) then return end |
| 83 | + hook.Run("OnServerLog", client, logType, logString, category) |
| 84 | + lia.printLog(category, logString) |
| 85 | + local logsDir = "lilia/logs/" .. engine.ActiveGamemode() |
| 86 | + if not file.Exists(logsDir, "DATA") then file.CreateDir(logsDir) end |
| 87 | + local filenameCategory = string.lower(string.gsub(category, "%s+", "_")) |
| 88 | + local logFilePath = logsDir .. "/" .. filenameCategory .. ".txt" |
| 89 | + local timestamp = os.date("%Y-%m-%d %H:%M:%S") |
| 90 | + file.Append(logFilePath, "[" .. timestamp .. "]\t" .. logString .. "\r\n") |
| 91 | + local charID |
| 92 | + local steamID |
| 93 | + if IsValid(client) then |
| 94 | + local char = client:getChar() |
| 95 | + charID = char and char:getID() or nil |
| 96 | + steamID = client:SteamID() |
| 97 | + end |
| 98 | + |
| 99 | + lia.db.insertTable({ |
| 100 | + _timestamp = timestamp, |
| 101 | + _gamemode = engine.ActiveGamemode(), |
| 102 | + _category = category, |
| 103 | + _message = logString, |
| 104 | + _charID = charID, |
| 105 | + _steamID = steamID |
| 106 | + }, nil, "logs") |
| 107 | + end |
| 108 | + |
| 109 | + function lia.log.convertToDatabase(changeMap) |
| 110 | + if lia.log.isConverting then return end |
| 111 | + lia.log.isConverting = true |
| 112 | + lia.bootstrap("Database", L("convertLogsToDatabase")) |
| 113 | + local baseDir = "lilia/logs" |
| 114 | + local entries = {} |
| 115 | + local filesToDelete = {} |
| 116 | + local files, dirs = file.Find(baseDir .. "/*", "DATA") |
| 117 | + local function processFile(path, gamemode, category) |
| 118 | + local data = file.Read(path, "DATA") |
| 119 | + if not data then return end |
| 120 | + for line in data:gmatch("[^\r\n]+") do |
| 121 | + local ts, msg = line:match("^%[([^%]]+)%]%s*(.+)") |
| 122 | + if ts and msg then |
| 123 | + local steamID = msg:match("%[(STEAM_[0-5]:[01]:%d+)%]") or msg:match("%[(%d+)%]") |
| 124 | + local charID = msg:match("CharID:%s*(%d+)") |
| 125 | + entries[#entries + 1] = { |
| 126 | + _timestamp = ts, |
| 127 | + _gamemode = gamemode, |
| 128 | + _category = category, |
| 129 | + _message = msg, |
| 130 | + _charID = charID, |
| 131 | + _steamID = steamID |
| 132 | + } |
| 133 | + end |
| 134 | + end |
| 135 | + end |
| 136 | + |
| 137 | + for _, fileName in ipairs(files) do |
| 138 | + if fileName:sub(-4) == ".txt" then |
| 139 | + local category = string.StripExtension(fileName) |
| 140 | + local path = baseDir .. "/" .. fileName |
| 141 | + processFile(path, engine.ActiveGamemode(), category) |
| 142 | + filesToDelete[#filesToDelete + 1] = path |
| 143 | + end |
| 144 | + end |
| 145 | + |
| 146 | + for _, gm in ipairs(dirs) do |
| 147 | + local gmPath = baseDir .. "/" .. gm |
| 148 | + local gmFiles = file.Find(gmPath .. "/*.txt", "DATA") |
| 149 | + for _, fileName in ipairs(gmFiles) do |
| 150 | + local category = string.StripExtension(fileName) |
| 151 | + local path = gmPath .. "/" .. fileName |
| 152 | + processFile(path, gm, category) |
| 153 | + filesToDelete[#filesToDelete + 1] = path |
| 154 | + end |
| 155 | + end |
| 156 | + |
| 157 | + local entryCount = #entries |
| 158 | + lia.db.waitForTablesToLoad():next(function() |
| 159 | + local function finalize() |
| 160 | + lia.log.isConverting = false |
| 161 | + lia.bootstrap("Database", L("convertLogsToDatabaseDone", entryCount)) |
| 162 | + for _, path in ipairs(filesToDelete) do |
| 163 | + file.Delete(path) |
| 164 | + end |
| 165 | + |
| 166 | + if changeMap then game.ConsoleCommand("changelevel " .. game.GetMap() .. "\n") end |
| 167 | + end |
| 168 | + |
| 169 | + if entryCount == 0 then |
| 170 | + finalize() |
| 171 | + return |
| 172 | + end |
| 173 | + |
| 174 | + lia.db.bulkInsert("logs", entries):next(finalize):catch(function(err) |
| 175 | + lia.printLog("Database", "Log conversion error: " .. tostring(err)) |
| 176 | + finalize() |
| 177 | + end) |
| 178 | + end) |
| 179 | + end |
| 180 | + |
| 181 | + local function countLegacyLogEntries() |
| 182 | + local baseDir = "lilia/logs" |
| 183 | + local total, ported = 0, 0 |
| 184 | + local files, dirs = file.Find(baseDir .. "/*", "DATA") |
| 185 | + local function scanFile(path) |
| 186 | + local data = file.Read(path, "DATA") |
| 187 | + if not data then return end |
| 188 | + for line in data:gmatch("[^\r\n]+") do |
| 189 | + total = total + 1 |
| 190 | + local ts, msg = line:match("^%[([^%]]+)%]%s*(.+)") |
| 191 | + if ts and msg then ported = ported + 1 end |
| 192 | + end |
| 193 | + end |
| 194 | + |
| 195 | + for _, fileName in ipairs(files) do |
| 196 | + if fileName:sub(-4) == ".txt" then scanFile(baseDir .. "/" .. fileName) end |
| 197 | + end |
| 198 | + |
| 199 | + for _, gm in ipairs(dirs) do |
| 200 | + local gmFiles = file.Find(baseDir .. "/" .. gm .. "/*.txt", "DATA") |
| 201 | + for _, fileName in ipairs(gmFiles) do |
| 202 | + scanFile(baseDir .. "/" .. gm .. "/" .. fileName) |
| 203 | + end |
| 204 | + end |
| 205 | + return ported, total |
| 206 | + end |
| 207 | + |
| 208 | + concommand.Add("lia_log_legacy_count", function(ply) |
| 209 | + if IsValid(ply) then return end |
| 210 | + local ported, total = countLegacyLogEntries() |
| 211 | + print("[Lilia] " .. L("liaLogLegacyCount", total, ported)) |
| 212 | + end) |
| 213 | +end |
0 commit comments