pepejik

Untitled

Feb 21st, 2025
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 7.84 KB | None | 0 0
  1. package com.pepej.truncator.indexer
  2.  
  3. import com.pepej.truncator.database.IndexedEvents
  4. import com.pepej.truncator.telegram.QUESTS_CHAT_ID
  5. import com.pepej.truncator.telegram.TelegramBatchedMessageSender
  6. import com.pepej.truncator.utils.toInstant
  7. import com.pepej.truncator.utils.toReadableTimeDifference
  8. import kotlinx.datetime.LocalDate
  9. import kotlinx.datetime.LocalDateTime
  10. import kotlinx.datetime.LocalTime
  11. import kotlinx.datetime.atTime
  12. import org.jetbrains.exposed.sql.insert
  13. import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
  14. import org.slf4j.LoggerFactory
  15. import java.io.File
  16.  
  17. private val LOG_PREFIX_REGEX = Regex("^\\[\\d{2}:\\d{2}:\\d{2}]\\s*\\[[^]]*]:\\s+(.*)$")
  18. private val LINE_TIME_REGEX = Regex("^\\[(\\d{2}):(\\d{2}):(\\d{2})]")
  19. private val LOCAL_CHAT_REGEX = Regex("^\\[L]\\s+(?:[^:]+\\s+)*(\\S+):\\s+(.*)$")
  20. private val GLOBAL_CHAT_REGEX = Regex("^\\[G]\\s+(?:[^:]+\\s+)*(\\S+):\\s+(.*)$")
  21. private val QUEST_REGEX = Regex("^(?:[^:]+\\s+)*(\\S+)\\s+завершил квест:\\s+(.*)$")
  22.  
  23. private val log = LoggerFactory.getLogger("LogIndexer")
  24.  
  25. private fun String.stripLogPrefix() = LOG_PREFIX_REGEX.find(this)?.groups?.get(1)?.value ?: this
  26.  
  27. private fun String.parseLineTime(): LocalTime? {
  28.     val match = LINE_TIME_REGEX.find(this)
  29.     return if (match != null) {
  30.         try {
  31.             LocalTime(
  32.                 hour = match.groupValues[1].toInt(),
  33.                 minute = match.groupValues[2].toInt(),
  34.                 second = match.groupValues[3].toInt()
  35.             )
  36.         } catch (e: Exception) {
  37.             null
  38.         }
  39.     } else null
  40. }
  41.  
  42. data class IndexedEventData(
  43.     val eventType: String,  // login, logout, quest, command, chat_local, chat_global
  44.     val nick: String,
  45.     val dateTime: LocalDateTime,
  46.     val details: String?,
  47.     val serverId: Int
  48. )
  49.  
  50. private val WIPE_DATE = LocalDateTime(
  51.     year = 2024,
  52.     monthNumber = 12,
  53.     dayOfMonth = 24,
  54.     hour = 11,
  55.     minute = 0,
  56.     second = 0,
  57. )
  58.  
  59.  
  60. val challenges = mapOf(
  61.     "+Ной" to "Noy",
  62.     "Драконоборец" to "Dracon",
  63.     "Энергон" to "Energon",
  64.     "Материализм" to "Materializm",
  65.     "Oпытофилия" to "Experience",
  66.     "Термоядерка" to "Nuclear",
  67.     "+Антипацифист" to "Killer",
  68.     "Одержимость" to "Music",
  69.     "Пчелиный мегаполис" to "Alvearies",
  70.     "Во все хмельные" to "Coffee",
  71.     "+Профессор" to "Bees",
  72.     "Кислотный пир" to "Acid",
  73.     "На благо сервера" to "Server",
  74.     "Братство камней" to "Stones",
  75.     "ВнизКоллекционер" to "Collection",
  76.     "Почти бесконечность" to "Infinity",
  77.     "Шапито" to "Fish",
  78.     "Закон Мёрфи" to "Singular",
  79.     "+Флорист" to "Flowers",
  80.     "Макросхемы" to "Schemes",
  81.     "Амортенция" to "Potions",
  82.     "Библиотека" to "Library",
  83.     "Легенда" to "Legend",
  84.     "Палладин" to "Palladium",
  85.     "Месть мехов" to "Stamps",
  86.     "Память" to "Memory",
  87. )
  88.  
  89. fun String.removeNonBmpChars(): String {
  90.     val sb = StringBuilder()
  91.     codePoints().forEach { cp ->
  92.         if (cp <= 0xFFFF) {
  93.             sb.appendCodePoint(cp)
  94.         }
  95.     }
  96.     return sb.toString()
  97. }
  98.  
  99. fun String.removeAnsiCodes(): String {
  100.     val ansiRegex = Regex("\\u001B\\[[;\\d]*[ -/]*[@-~]")
  101.     return replace(ansiRegex, "")
  102. }
  103.  
  104. suspend fun indexLogFile(logFile: File, fileDate: LocalDate, srvId: Int) {
  105.     log.info("Начинаем индексировать лог-файл: ${logFile.name}, дата = $fileDate")
  106.     val events = mutableListOf<IndexedEventData>()
  107.     val lines = logFile.readLines()
  108.     for (line in lines) {
  109.         val clean = line.removeNonBmpChars().removeAnsiCodes().stripLogPrefix()
  110.         val time = line.parseLineTime() ?: LocalTime(0, 0, 0)
  111.         val dateTime = fileDate.atTime(time)
  112.         when {
  113.             clean.contains(" logged in with entity id ") -> {
  114.                 val regex = Regex("(\\S+)\\[/([\\d.]+):\\d+].*?logged in")
  115.                 regex.find(clean)?.let { match ->
  116.                     val nick = match.groupValues[1]
  117.                     val ip = match.groupValues[2]
  118.                     events.add(IndexedEventData("login", nick, dateTime, "IP: $ip", srvId))
  119.                 }
  120.             }
  121.  
  122.             clean.contains(" lost connection:") -> {
  123.                 val regex = Regex("^(\\S+) lost connection:")
  124.                 regex.find(clean)?.let { match ->
  125.                     val nick = match.groupValues[1]
  126.                     events.add(IndexedEventData("logout", nick, dateTime, null, srvId))
  127.                 }
  128.             }
  129.  
  130.             clean.contains("завершил квест:") -> {
  131.                 QUEST_REGEX.find(clean)?.let { match ->
  132.                     val nick = match.groupValues[1]
  133.                     val quest = match.groupValues[2].trim()
  134.                     val finalQuest = if (quest.startsWith("Испытания ->")) {
  135.                         val challenge = quest.replace("Испытания -> ", "")
  136.                         val challengeId = challenges[challenge]
  137.                         if (challengeId != null) {
  138.                             val elapsed = WIPE_DATE.toInstant().toReadableTimeDifference(dateTime.toInstant())
  139.                             val message = "$nick (${srvId.serverName}) завершил испытание $challenge! Это заняло $elapsed!"
  140.                             val finalMessage = if (challengeId == "Legend") {
  141.                                 "@sovetskyii !!! \n$message"
  142.                             } else {
  143.                                 message
  144.                             }
  145.                             TelegramBatchedMessageSender.addToBatchQueue(QUESTS_CHAT_ID, finalMessage, includeTimeStamp = false)
  146.                             challengeId
  147.                         } else {
  148.                             quest
  149.                         }
  150.                     } else {
  151.                         quest
  152.                     }
  153.                     events.add(IndexedEventData("quest", nick, dateTime, finalQuest, srvId))
  154.                 }
  155.             }
  156.  
  157.             clean.contains("issued server command:") -> {
  158.                 val regex = Regex("^(\\S+) issued server command:\\s+(/\\S+)(.*)")
  159.                 regex.find(clean)?.let { match ->
  160.                     val nick = match.groupValues[1]
  161.                     val command = (match.groupValues[2] + " " + match.groupValues[3]).trim()
  162.                     events.add(IndexedEventData("command", nick, dateTime, command, srvId))
  163.                 }
  164.             }
  165.  
  166.             LOCAL_CHAT_REGEX.matches(clean) -> {
  167.                 LOCAL_CHAT_REGEX.find(clean)?.let { match ->
  168.                     val nick = match.groupValues[1]
  169.                     val text = match.groupValues[2]
  170.                     events.add(IndexedEventData("chat_local", nick, dateTime, text, srvId))
  171.                 }
  172.             }
  173.  
  174.             GLOBAL_CHAT_REGEX.matches(clean) -> {
  175.                 GLOBAL_CHAT_REGEX.find(clean)?.let { match ->
  176.                     val nick = match.groupValues[1]
  177.                     val text = match.groupValues[2]
  178.                     events.add(IndexedEventData("chat_global", nick, dateTime, text, srvId))
  179.                 }
  180.             }
  181.         }
  182.     }
  183.     newSuspendedTransaction {
  184.         events.forEach { event ->
  185.             IndexedEvents.insert {
  186.                 it[eventType] = event.eventType
  187.                 it[nick] = event.nick
  188.                 it[eventTime] = event.dateTime
  189.                 it[details] = event.details
  190.                 it[serverId] = event.serverId
  191.             }
  192.         }
  193.     }
  194.     log.info("Индексирование завершено для сервера $srvId: ${events.size} событий")
  195. }
  196.  
Add Comment
Please, Sign In to add comment