From f24ba763ac15a6d30a300f254d038157610f833b Mon Sep 17 00:00:00 2001 From: nikky Date: Sun, 24 Jun 2018 13:58:38 +0200 Subject: [PATCH] implemented jankson loading for commands and permissions --- .../bridge/command/CustomCommand.kt | 1 + .../kotlin/matterlink/config/CommandConfig.kt | 135 +++++++++++------- .../matterlink/config/PermissionConfig.kt | 67 ++++++--- 3 files changed, 132 insertions(+), 71 deletions(-) diff --git a/core/src/main/kotlin/matterlink/bridge/command/CustomCommand.kt b/core/src/main/kotlin/matterlink/bridge/command/CustomCommand.kt index 47d5d58..7614692 100644 --- a/core/src/main/kotlin/matterlink/bridge/command/CustomCommand.kt +++ b/core/src/main/kotlin/matterlink/bridge/command/CustomCommand.kt @@ -88,6 +88,7 @@ data class CustomCommand( } companion object { + val DEFAULT = CustomCommand() fun getReplacements(user: String, userId: String, server: String, args: String): Map String> = mapOf( "{uptime}" to instance::getUptimeAsString, diff --git a/core/src/main/kotlin/matterlink/config/CommandConfig.kt b/core/src/main/kotlin/matterlink/config/CommandConfig.kt index 414272f..06b0949 100644 --- a/core/src/main/kotlin/matterlink/config/CommandConfig.kt +++ b/core/src/main/kotlin/matterlink/config/CommandConfig.kt @@ -1,60 +1,64 @@ package matterlink.config -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.JsonSyntaxException -import com.google.gson.reflect.TypeToken -import matterlink.RegexDeSerializer +import blue.endless.jankson.Jankson +import blue.endless.jankson.JsonObject +import blue.endless.jankson.JsonPrimitive +import blue.endless.jankson.impl.Marshaller +import blue.endless.jankson.impl.SyntaxError import matterlink.bridge.command.CommandType import matterlink.bridge.command.CustomCommand import matterlink.instance -import matterlink.stackTraceString import java.io.File -import java.util.regex.PatternSyntaxException +import java.io.FileNotFoundException typealias CommandMap = MutableMap +typealias DefaultCommands = Map> object CommandConfig { - private val gson: Gson = GsonBuilder() - .registerTypeAdapter(Regex::class.java, RegexDeSerializer) - .setPrettyPrinting() - .create() private val configFile: File = cfg.cfgDirectory.resolve("commands.json") - private val default = hashMapOf( - "tps" to CustomCommand( + private val default: DefaultCommands = mapOf( + "tps" to ("""Your run off the mill tps commands, change it to /sampler tps or /cofh tps if you like + |make sure to disable defaultCommand if you want your edits to have any effect + """.trimMargin() + to CustomCommand( type = CommandType.EXECUTE, execute = "forge tps", help = "Print server tps", timeout = 200, defaultCommand = true - ), - "list" to CustomCommand( + )), + "list" to ("lists all the players, this is just a straight pass-through" + to CustomCommand( type = CommandType.EXECUTE, execute = "list", help = "List online players", defaultCommand = true - ), - "seed" to CustomCommand( + )), + "seed" to ("another straight pass-through" + to CustomCommand( type = CommandType.EXECUTE, execute = "seed", help = "Print server world seed", defaultCommand = true - ), - "uptime" to CustomCommand( + )), + "uptime" to ("this is a reponse command, it uses the uptime function, time since the mod was first loaded" + to CustomCommand( type = CommandType.RESPONSE, response = "{uptime}", help = "Print server uptime", defaultCommand = true - ), - "whoami" to CustomCommand( + )), + "whoami" to ("this shows you some of the other response macros" + to CustomCommand( type = CommandType.RESPONSE, response = "server: `{server}` userid: `{userid}` user: `{user}`", help = "Print debug user data", timeout = 200, defaultCommand = true - ), - "exec" to CustomCommand( + )), + "exec" to ("this uses arguments in a passed-through command, you could restrict the arguments with a regex" + to CustomCommand( type = CommandType.EXECUTE, execute = "{args}", argumentsRegex = ".*".toRegex(), @@ -62,40 +66,73 @@ object CommandConfig { help = "Execute any command as OP, be careful with this one", execOp = true, defaultCommand = true - ) + )) ) - var commands: CommandMap = default - private set + val commands: CommandMap = hashMapOf() fun readConfig(): Boolean { - if (!configFile.exists() || configFile.readText().isBlank()) { - configFile.createNewFile() - configFile.writeText(gson.toJson(default)) - commands = default - return true - } + val jankson = Jankson + .builder() + .registerTypeAdapter(CustomCommand::class.java) { jsonObj -> + with(CustomCommand.DEFAULT) { + CustomCommand( + type = jsonObj.get(String::class.java, "type")?.let { CommandType.valueOf(it) } + ?: type, + execute = jsonObj.get(String::class.java, "execute") ?: execute, + response = jsonObj.get(String::class.java, "response") ?: response, + permLevel = jsonObj.get(Double::class.java, "permLevel") ?: permLevel, + help = jsonObj.get(String::class.java, "help") ?: help, + timeout = jsonObj.get(Int::class.java, "timeout") ?: timeout, + defaultCommand = jsonObj.get(Boolean::class.java, "defaultCommand") ?: defaultCommand, + execOp = jsonObj.get(Boolean::class.java, "execOp") ?: execOp, + argumentsRegex = jsonObj.get(String::class.java, "argumentsRegex")?.toRegex() + ?: argumentsRegex + ) + } - try { - commands = gson.fromJson(configFile.readText(), object : TypeToken() {}.type) - commands.filterValues { it.defaultCommand ?: false }.forEach { commands.remove(it.key) } - default.forEach { k, v -> - if (!commands.containsKey(k)) { - commands[k] = v } - } - configFile.writeText(gson.toJson(commands)) - } catch (e: JsonSyntaxException) { - instance.fatal(e.stackTraceString) - instance.fatal("failed to parse $configFile, using last good values as fallback") + .build() - return false - } catch (e: PatternSyntaxException) { - instance.fatal(e.stackTraceString) - instance.fatal("failed to parse regex in $configFile, using last good values as fallback") - - return false + Marshaller.getFallback().registerSerializer(Regex::class.java) { + JsonPrimitive(it.pattern) } + Marshaller.getFallback().registerSerializer(CommandType::class.java) { + JsonPrimitive(it.name) + } + + val jsonObject = try { + jankson.load(configFile) + } catch (e: SyntaxError) { + instance.error("error parsing config: ${e.completeMessage}") + JsonObject() + } catch (e: FileNotFoundException) { + configFile.createNewFile() + JsonObject() + } + // clear commands + commands.clear() + jsonObject.forEach { key, element -> + instance.trace("loading command '$key'") + val command = jankson.fromJson(element.toJson(), CustomCommand::class.java) + commands[key] = command + } + + //apply defaults + default.forEach { k, (comment, defCommand) -> + val command = commands[k] + if (command == null || command.defaultCommand == true) { + commands[k] = defCommand + val element = Marshaller.getFallback().serialize(defCommand) + jsonObject.putDefault(k, element, comment) + } + } + + instance.debug("loaded jsonObj: $jsonObject") + instance.debug("loaded commandMap: $commands") + + configFile.writeText(jsonObject.toJson(true, true)) + return true } diff --git a/core/src/main/kotlin/matterlink/config/PermissionConfig.kt b/core/src/main/kotlin/matterlink/config/PermissionConfig.kt index 407f893..73f4c2b 100644 --- a/core/src/main/kotlin/matterlink/config/PermissionConfig.kt +++ b/core/src/main/kotlin/matterlink/config/PermissionConfig.kt @@ -1,46 +1,69 @@ package matterlink.config -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.JsonSyntaxException -import com.google.gson.reflect.TypeToken +import blue.endless.jankson.Jankson +import blue.endless.jankson.JsonObject +import blue.endless.jankson.impl.Marshaller +import blue.endless.jankson.impl.SyntaxError import matterlink.instance -import matterlink.stackTraceString import java.io.File +import java.io.FileNotFoundException -typealias PermissionMap = Map> +typealias PermissionMap = MutableMap> object PermissionConfig { - private val gson: Gson = GsonBuilder().setPrettyPrinting().create() + private val jankson = Jankson + .builder() + .build() + private val configFile: File = cfg.cfgDirectory.resolve("permissions.json") private val default = mapOf( "irc.esper" to mapOf( - "~nikky@nikky.moe" to 0.0, - "user@example." to 0.0 + "~nikky@nikky.moe" to (0.0 to "IRC users are identified by their username and hostmask"), + "user@example.com" to (0.0 to "") ), "discord.game" to mapOf( - "112228624366575616" to 0.0 + "112228624366575616" to (0.0 to "thats a discord user id") ) ) - var perms: PermissionMap = default + var perms: PermissionMap = mutableMapOf() + private var jsonObject: JsonObject = JsonObject() fun loadPermFile(): Boolean { - if (!configFile.exists() || configFile.readText().isBlank()) { + jsonObject = try { + jankson.load(configFile) + } catch (e: SyntaxError) { + instance.error("error parsing config: ${e.completeMessage}") + JsonObject() + } catch (e: FileNotFoundException) { configFile.createNewFile() - configFile.writeText(gson.toJson(default)) - return true + JsonObject() } - try { - perms =gson.fromJson(configFile.readText(), object : TypeToken() {}.type) - } catch (e: JsonSyntaxException) { - instance.fatal(e.stackTraceString) - instance.fatal("failed to parse $configFile using last good values as fallback") - - return true + default.forEach { platform, userMap -> + val jsonUserMap = jsonObject.getOrDefault(platform, JsonObject()) as JsonObject + userMap.forEach { user, (powerlevel, comment) -> + instance.trace("loading platform: $platform user: $user powwerlevel: $powerlevel") + val element = Marshaller.getFallback().serialize(powerlevel) + jsonUserMap.putDefault(user, element, comment.takeUnless { it.isBlank() }) + } + jsonObject[platform] = jsonUserMap } - return false + + jsonObject.forEach { platform, jsonUserMap -> + val userMap = perms[platform] ?: mutableMapOf() + if (jsonUserMap is JsonObject) { + jsonUserMap.forEach { user, powerlevel -> + instance.info("$platform $user $powerlevel") + userMap[user] = jsonUserMap.get(Double::class.java, user) ?: 0.0 + } + } + perms[platform] = userMap + } + + configFile.writeText(jsonObject.toJson(true, true)) + + return true } } \ No newline at end of file