diff --git a/README.md b/README.md index 9ee4b25..c7ef811 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# kagebot – where the code is better than the name +# kagebot +Kinda dead. + This bot is a replacement for [my old one](https://git.kageru.moe/kageru/discord-selphybot) with a very simple premise: As much as possible should be configurable in a human-readable way. This will allow anyone to modify the config to host their own instance tailored to their own needs, @@ -14,4 +16,6 @@ The implementation has kind of deteriorated into a playground for me but it’s been running and moderating a 1000+ user server for over a year with relatively little maintenance. -[1]: While arrow is great, adding it to a project after the fact leads to a very weird combination of FP and non-FP constructs. Would not recommend in production. +[1]: While arrow is great, adding it to a project after the fact leads to a very weird combination of FP and non-FP constructs. +Would not recommend in production. This was also built in an early version of arrow that still had `Kind` and other concepts that were scrapped later, +but I don’t plan to update that ever. The bot can keep running as-is until it breaks. diff --git a/build.gradle.kts b/build.gradle.kts index a79dd15..e10aade 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,22 +4,22 @@ apply { plugin("kotlin-kapt") } plugins { - kotlin("jvm") version "1.4.10" - id("com.github.johnrengelman.shadow") version "5.2.0" apply true + kotlin("jvm") version "1.9.0" + id("com.github.johnrengelman.shadow") version "8.1.1" apply true application } val botMainClass = "moe.kageru.kagebot.KagebotKt" application { - mainClassName = botMainClass + mainClass.set(botMainClass) } tasks.withType { manifest { attributes( mapOf( - "Main-Class" to botMainClass - ) + "Main-Class" to botMainClass, + ), ) } } @@ -43,10 +43,10 @@ val arrowVersion = "0.11.0" dependencies { implementation("com.uchuhimo:konf-core:0.23.0") implementation("com.uchuhimo:konf-toml:0.23.0") - implementation("org.javacord:javacord:3.1.1") + implementation("org.javacord:javacord:3.8.0") implementation("org.mapdb:mapdb:3.0.8") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9") - implementation("org.jetbrains.kotlin:kotlin-reflect:1.4.10") + implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.0") implementation("com.fasterxml.jackson.core:jackson-annotations:2.11.3") implementation("io.arrow-kt:arrow-core:$arrowVersion") @@ -55,10 +55,10 @@ dependencies { testImplementation("io.kotlintest:kotlintest-runner-junit5:3.4.2") testImplementation("io.mockk:mockk:1.10.0") // these two are needed to access javacord internals (such as reading from sent embeds during tests) - testImplementation("org.javacord:javacord-core:3.1.1") + testImplementation("org.javacord:javacord-core:3.8.0") testImplementation("com.fasterxml.jackson.core:jackson-databind:2.11.3") } tasks.withType { - kotlinOptions.jvmTarget = "14" + kotlinOptions.jvmTarget = "20" } diff --git a/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt b/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt index a8f0b69..07352b9 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt @@ -42,12 +42,14 @@ object Kagebot { println("Caused by: ${e.cause}\n${e.cause?.stackTrace?.joinToString("\n")}") exitProcess(1) } - Runtime.getRuntime().addShutdownHook(Thread { - Log.info("Bot has been interrupted. Shutting down.") - Dao.setCommandCounter(Globals.commandCounter.get()) - Dao.close() - api.disconnect() - }) + Runtime.getRuntime().addShutdownHook( + Thread { + Log.info("Bot has been interrupted. Shutting down.") + Dao.setCommandCounter(Globals.commandCounter.get()) + Dao.close() + api.disconnect() + }, + ) Log.info("kagebot Mk II running") api.addMessageCreateListener { checked { it.process() } } Config.features.eventFeatures().forEach { it.register(api) } diff --git a/src/main/kotlin/moe/kageru/kagebot/Log.kt b/src/main/kotlin/moe/kageru/kagebot/Log.kt index 44cc192..4352bd3 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Log.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Log.kt @@ -13,7 +13,7 @@ object Log { addHandler( FileHandler("kagebot.log", true).apply { formatter = LogFormatter() - } + }, ) } } diff --git a/src/main/kotlin/moe/kageru/kagebot/Util.kt b/src/main/kotlin/moe/kageru/kagebot/Util.kt index 8de5424..b002e02 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Util.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Util.kt @@ -80,17 +80,6 @@ object Util { } catch (e: Exception) { Log.warn("An uncaught exception occurred.\n$e") Log.warn(e.stackTrace.joinToString("\n")) - MessageUtil.sendEmbed( - Globals.api.owner.get(), - EmbedBuilder() - .setColor(Color.RED) - .addField("Error", "kagebot has encountered an error") - .addField( - "$e", """``` - ${e.stackTrace.joinToString("\n\t")} - ```""".trimIndent().run { applyIf(length > 1800) { substring(1..1800) } } - ) - ) } } } diff --git a/src/main/kotlin/moe/kageru/kagebot/command/Command.kt b/src/main/kotlin/moe/kageru/kagebot/command/Command.kt index dca8eea..1a30516 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/Command.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/Command.kt @@ -21,7 +21,7 @@ class Command( private val actions: MessageActions?, embed: List?, feature: String?, - matchType: String? + matchType: String?, ) { val matchType: MatchType = matchType?.let { type -> MatchType.values().find { it.name.equals(type, ignoreCase = true) } @@ -56,5 +56,5 @@ class Command( enum class MatchType(val matches: (String, Command) -> Boolean) { PREFIX({ message, command -> message.startsWith(command.trigger, ignoreCase = true) }), CONTAINS({ message, command -> message.contains(command.trigger, ignoreCase = true) }), - REGEX({ message, command -> command.regex!!.matches(message) }); + REGEX({ message, command -> command.regex!!.matches(message) }), } diff --git a/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt b/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt index 9d3d9cd..c16b3c6 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt @@ -11,7 +11,7 @@ class MessageActions( private val delete: Boolean = false, private val redirect: MessageRedirect?, @JsonProperty("assign") - private val assignment: RoleAssignment? + private val assignment: RoleAssignment?, ) { fun run(message: MessageCreateEvent, command: Command) { diff --git a/src/main/kotlin/moe/kageru/kagebot/command/Permissions.kt b/src/main/kotlin/moe/kageru/kagebot/command/Permissions.kt index fadf61d..6ebb2c8 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/Permissions.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/Permissions.kt @@ -3,14 +3,12 @@ package moe.kageru.kagebot.command import arrow.core.Option import arrow.core.toOption import moe.kageru.kagebot.Util -import moe.kageru.kagebot.extensions.unwrap -import org.javacord.api.entity.permission.Role import org.javacord.api.event.message.MessageCreateEvent class Permissions( hasOneOf: List?, hasNoneOf: List?, - private val onlyDM: Boolean = false + private val onlyDM: Boolean = false, ) { private val hasOneOf: Option> = hasOneOf?.toSet().toOption() private val hasNoneOf: Option> = hasNoneOf?.toSet().toOption() diff --git a/src/main/kotlin/moe/kageru/kagebot/command/RoleAssignment.kt b/src/main/kotlin/moe/kageru/kagebot/command/RoleAssignment.kt index e002e5c..11ff2e0 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/RoleAssignment.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/RoleAssignment.kt @@ -12,6 +12,6 @@ class RoleAssignment(@JsonProperty("role") role: String) { fun assign(message: MessageCreateEvent) = message.getUser().fold( { Log.warn("Could not find user ${message.messageAuthor.name} for role assign") }, - { it.addRole(role, "Requested via command.") } + { it.addRole(role, "Requested via command.") }, ) } diff --git a/src/main/kotlin/moe/kageru/kagebot/features/DebugFeature.kt b/src/main/kotlin/moe/kageru/kagebot/features/DebugFeature.kt index 45dcd61..846820a 100644 --- a/src/main/kotlin/moe/kageru/kagebot/features/DebugFeature.kt +++ b/src/main/kotlin/moe/kageru/kagebot/features/DebugFeature.kt @@ -22,11 +22,15 @@ class DebugFeature : MessageFeature { val runtime = Runtime.getRuntime() return MessageUtil.listToEmbed( listOf( - "Bot:", getBotStats(), - "Memory:", getMemoryInfo(runtime, osBean), - "CPU:", getCpuInfo(osBean), - "System:", getOsInfo() - ) + "Bot:", + getBotStats(), + "Memory:", + getMemoryInfo(runtime, osBean), + "CPU:", + getCpuInfo(osBean), + "System:", + getOsInfo(), + ), ) } @@ -40,7 +44,7 @@ class DebugFeature : MessageFeature { uptime.toDaysPart(), uptime.toHoursPart(), uptime.toMinutesPart(), - uptime.toSecondsPart() + uptime.toSecondsPart(), ) } diff --git a/src/main/kotlin/moe/kageru/kagebot/features/Features.kt b/src/main/kotlin/moe/kageru/kagebot/features/Features.kt index a7f703b..ecb4f21 100644 --- a/src/main/kotlin/moe/kageru/kagebot/features/Features.kt +++ b/src/main/kotlin/moe/kageru/kagebot/features/Features.kt @@ -3,7 +3,7 @@ package moe.kageru.kagebot.features class Features( val welcome: WelcomeFeature? = null, val timeout: TimeoutFeature? = null, - vc: TempVCFeature = TempVCFeature(null) + vc: TempVCFeature = TempVCFeature(null), ) { private val debug = DebugFeature() private val help = HelpFeature() @@ -18,7 +18,7 @@ class Features( "getConfig" to getConfig, "setConfig" to setConfig, "timeout" to timeout, - "vc" to vc + "vc" to vc, ) fun findByString(feature: String) = featureMap[feature] diff --git a/src/main/kotlin/moe/kageru/kagebot/features/TempVCFeature.kt b/src/main/kotlin/moe/kageru/kagebot/features/TempVCFeature.kt index ae11728..1543866 100644 --- a/src/main/kotlin/moe/kageru/kagebot/features/TempVCFeature.kt +++ b/src/main/kotlin/moe/kageru/kagebot/features/TempVCFeature.kt @@ -19,17 +19,21 @@ class TempVCFeature(@JsonProperty("category") category: String? = null) : EventF private val category: ChannelCategory? = category?.let { Config.server.categoriesByName(it).first() } override fun handle(message: MessageCreateEvent): Unit = with(message) { - Either.cond(' ' in readableMessageContent, + Either.cond( + ' ' in readableMessageContent, { readableMessageContent.split(' ', limit = 2).last() }, - { "Invalid syntax, expected ` `" }) + { "Invalid syntax, expected ` `" }, + ) .flatMap { limit -> limit.toIntOrNull().rightIfNotNull { "Invalid syntax, expected a number as limit, got $limit" } }.filterOrElse({ it < 99 }, { "Error: can’t create a channel with that many users." }) - .fold({ err -> channel.sendMessage(err) }, + .fold( + { err -> channel.sendMessage(err) }, { limit -> createChannel(message, limit) channel.sendMessage("Done") - }) + }, + ) } override fun register(api: DiscordApi) { @@ -43,7 +47,7 @@ class TempVCFeature(@JsonProperty("category") category: String? = null) : EventF private fun deleteChannel(channel: ServerVoiceChannel) = channel.delete("Empty temporary channel").asOption().fold( { Log.warn("Attempted to delete temporary VC without the necessary permissions") }, - { Dao.removeTemporaryVC(channel.idAsString) } + { Dao.removeTemporaryVC(channel.idAsString) }, ) private fun createChannel(message: MessageCreateEvent, limit: Int): Unit = @@ -54,7 +58,8 @@ class TempVCFeature(@JsonProperty("category") category: String? = null) : EventF setCategory(category) }.create().asOption().fold( { Log.warn("Attempted to create temporary VC without the necessary permissions") }, - { channel -> Dao.addTemporaryVC(channel.idAsString) }) + { channel -> Dao.addTemporaryVC(channel.idAsString) }, + ) private fun generateChannelName(message: MessageCreateEvent): String = "${message.messageAuthor.name}’s volatile corner" diff --git a/src/main/kotlin/moe/kageru/kagebot/features/TimeoutFeature.kt b/src/main/kotlin/moe/kageru/kagebot/features/TimeoutFeature.kt index b64becf..704f0c8 100644 --- a/src/main/kotlin/moe/kageru/kagebot/features/TimeoutFeature.kt +++ b/src/main/kotlin/moe/kageru/kagebot/features/TimeoutFeature.kt @@ -30,7 +30,7 @@ class TimeoutFeature(@JsonProperty("role") role: String) : MessageFeature { Either.cond( args.size >= 3, { Tuple3(args[1], args[2], args.getOrNull(3)) }, - { "Error: expected “