WIP custom commands and permissions loading from json

This commit is contained in:
DaMachinator 2018-02-18 20:22:27 +01:00
parent 4d51894628
commit 968ff1aacc
28 changed files with 211 additions and 136 deletions

View File

@ -58,10 +58,9 @@ object EventHandler {
@JvmStatic
fun commandEvent(e: CommandEvent) {
val sender = when {
e.sender is EntityPlayer -> e.sender.name
e.sender is DedicatedServer -> cfg.relay.systemUser
e.sender is TileEntityCommandBlock -> "CommandBlock"
else -> return
else -> e.sender.name
}
val args = e.parameters.joinToString(" ")
val type = when {

View File

@ -1,17 +1,15 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.command.IMinecraftCommandSender
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.config.cfg
import matterlink.update.UpdateChecker
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.*
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger
import java.io.File
lateinit var logger: Logger

View File

@ -2,6 +2,7 @@ package matterlink.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import net.minecraft.command.CommandResultStats
import net.minecraft.command.ICommandSender
@ -18,7 +19,7 @@ import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
private var level: Int = 0
override fun execute(cmdString: String, level: Int): Boolean {
override fun execute(cmdString: String): Boolean {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
this,
cmdString
@ -38,7 +39,7 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
//TODO: Implement actual permissions checking
//we check user on our end
return true
}

View File

@ -4,5 +4,4 @@ const val MODID = "matterlink"
const val NAME = "MatterLink"
const val MODVERSION = "@MODVERSION@"
const val MCVERSION = "@MCVERSION@"
//const val DEPENDENCIES = "required-after:forgelin@[@FORGELIN-VERSION@,);required-after:forge@[@FORGE-VERSION@,);"
const val DEPENDENCIES = "required-after:forgelin@[@FORGELIN-VERSION@,);"

View File

@ -59,10 +59,9 @@ object EventHandler {
@JvmStatic
fun commandEvent(e: CommandEvent) {
val sender = when {
e.sender is EntityPlayer -> e.sender.name
e.sender is DedicatedServer -> cfg.relay.systemUser
e.sender is TileEntityCommandBlock -> "CommandBlock"
else -> return
else -> e.sender.name
}
val args = e.parameters.joinToString(" ")
val type = when {

View File

@ -1,17 +1,15 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.command.IMinecraftCommandSender
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.config.cfg
import matterlink.update.UpdateChecker
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.*
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger
import java.io.File
lateinit var logger: Logger

View File

@ -2,6 +2,7 @@ package matterlink.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import net.minecraft.command.CommandResultStats
import net.minecraft.command.ICommandSender
@ -16,9 +17,8 @@ import net.minecraftforge.fml.common.FMLCommonHandler
import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
private var level: Int = 0
override fun execute(cmdString: String, level: Int): Boolean {
override fun execute(cmdString: String): Boolean {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
this,
cmdString
@ -38,7 +38,7 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
//TODO: Implement actual permissions checking
//we now do permissions checking on our end
return true
}

View File

@ -51,10 +51,9 @@ object EventHandler {
@JvmStatic
fun commandEvent(e: CommandEvent) {
val sender = when {
e.sender is EntityPlayer -> e.sender.name
e.sender is DedicatedServer -> cfg.relay.systemUser
e.sender is TileEntityCommandBlock -> "CommandBlock"
else -> return
else -> e.sender.name
}
val args = e.parameters.joinToString(" ")
val type = when {

View File

@ -1,17 +1,15 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.command.IMinecraftCommandSender
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.config.cfg
import matterlink.update.UpdateChecker
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.*
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger
import java.io.File
lateinit var logger: Logger

View File

@ -2,6 +2,7 @@ package matterlink.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import net.minecraft.command.ICommandSender
import net.minecraft.server.MinecraftServer
@ -11,9 +12,8 @@ import net.minecraftforge.fml.common.FMLCommonHandler
import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
private var level: Int = 0
override fun execute(cmdString: String, level: Int): Boolean {
override fun execute(cmdString: String): Boolean {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
this,
cmdString
@ -29,7 +29,7 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
//TODO: Implement actual permissions checking
//permissions are checked on our end
return true
}

View File

@ -54,10 +54,9 @@ object EventHandler {
@SubscribeEvent
fun commandEvent(e: CommandEvent) {
val sender = when {
e.sender is EntityPlayer -> e.sender.commandSenderName
e.sender is DedicatedServer -> cfg.relay.systemUser
e.sender is TileEntityCommandBlock -> "CommandBlock"
else -> return
else -> e.sender.commandSenderName
}
val args = e.parameters.joinToString(" ")
val type = when {

View File

@ -4,7 +4,7 @@ import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.*
import matterlink.command.CommandMatterlink
import matterlink.command.IMinecraftCommandSender
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.config.cfg
import net.minecraft.server.MinecraftServer

View File

@ -2,9 +2,9 @@ package matterlink.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import net.minecraft.command.ICommandSender
import net.minecraft.entity.Entity
import net.minecraft.server.MinecraftServer
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChunkCoordinates
@ -15,7 +15,7 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
private var level: Int = 0
override fun execute(cmdString: String, level: Int): Boolean {
override fun execute(cmdString: String): Boolean {
return 0 < MinecraftServer.getServer().commandManager.executeCommand(
this,
cmdString
@ -35,7 +35,7 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun canCommandSenderUseCommand(permLevel: Int, commandName: String?): Boolean {
//TODO: Implement actual permissions checking
//we do permission
return true
}

View File

@ -4,5 +4,4 @@ const val MODID = "matterlink"
const val NAME = "MatterLink"
const val MODVERSION = "@MODVERSION@"
const val MCVERSION = "@MCVERSION@"
const val DEPENDENCIES = ""

View File

@ -2,7 +2,7 @@ package matterlink
import matterlink.bridge.MessageHandler
import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.command.IMinecraftCommandSender
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import matterlink.update.UpdateChecker
import java.io.File

View File

@ -20,7 +20,8 @@ object ServerChatHandler {
val message = when (nextMessage.event) {
"user_action" -> nextMessage.format(cfg.formatting.action)
"" -> {
if (BridgeCommandRegistry.handleCommand(nextMessage.text)) return
// try to handle command and do not handle as a chat message
if (BridgeCommandRegistry.handleCommand(nextMessage)) return
nextMessage.format(cfg.formatting.chat)
}
"join_leave" -> nextMessage.format(cfg.formatting.joinLeave)

View File

@ -1,5 +1,8 @@
package matterlink.bridge.command
import matterlink.bridge.ApiMessage
import matterlink.config.CommandConfig
import matterlink.config.PermissionConfig
import matterlink.config.cfg
import matterlink.instance
import java.util.*
@ -8,25 +11,28 @@ object BridgeCommandRegistry {
private val commandMap: HashMap<String, IBridgeCommand> = HashMap()
fun handleCommand(input: String): Boolean {
fun handleCommand(input: ApiMessage): Boolean {
if (!cfg.command.enable) return false
if (input[0] != cfg.command.prefix[0] || input.length < 2) return false
if (input.text[0] != cfg.command.prefix[0] || input.text.length < 2) return false
val cmd = input.substring(1).split(' ', ignoreCase = false, limit = 2)
val args = if (cmd.size == 2)
cmd[1]
else
""
val cmd = input.text.substring(1).split(' ', ignoreCase = false, limit = 2)
val args = if (cmd.size == 2) cmd[1] else ""
return if (commandMap.containsKey(cmd[0])) (commandMap[cmd[0]]!!.call(args)) else false
return if (commandMap.containsKey(cmd[0]))
(commandMap[cmd[0]]!!.execute(input.username, input.userid, input.account, args))
else false
}
fun register(cmd: IBridgeCommand): Boolean {
if (cmd.name.isBlank() || commandMap.containsKey(cmd.name)) {
instance.info("Failed to register command: '${cmd.name}'")
if (cmd.alias.isBlank() || commandMap.containsKey(cmd.alias)) {
instance.error("Failed to register command: '${cmd.alias}'")
return false
}
commandMap[cmd.name] = cmd
if(!cmd.validate()) {
instance.error("Failed to validate command: '${cmd.alias}'")
return false
}
commandMap[cmd.alias] = cmd
return true
}
@ -42,14 +48,16 @@ object BridgeCommandRegistry {
return if (help.isNotBlank()) help else "No help for '$cmd'"
}
val commandList: String
get() = commandMap.keys.joinToString(separator = ", ")
fun getCommandList (permLvl : Int) : String {
return commandMap.filter { (key, value) ->
value.permLevel <= permLvl
}.map {it.key}.joinToString(" ")
}
fun reloadCommands() {
commandMap.clear()
registerAll(HelpCommand,PlayerListCommand,UptimeCommand)
for ((key, value) in cfg.command.commandMapping) {
register(PassthroughCommand(key, value))
}
PermissionConfig.loadPermFile()
register(HelpCommand)
registerAll(*CommandConfig.readConfig())
}
}

View File

@ -0,0 +1,48 @@
package matterlink.bridge.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.instance
data class CustomCommand(
override val alias: String,
val type: CommandType = CommandType.RESPONSE,
val execute: String = "",
val response: String = "",
override val permLevel: Int = 0,
override val help: String = "",
val allowArgs : Boolean = true
) : IBridgeCommand {
override fun execute(user: String, userId: String, server: String, args: String): Boolean {
if (!allowArgs && args.isNotBlank()) return false
if (IBridgeCommand.getPermLevel(userId,server) < permLevel) {
MessageHandler.transmit(ApiMessage(text = "$user is not permitted to perform command: $alias"))
return false
}
return when (type) {
CommandType.PASSTHROUGH -> {
//TODO: use a new commandSender for each user
instance.commandSender.execute("$execute $args")
}
CommandType.RESPONSE -> {
//TODO: replace format variables, use arguments
MessageHandler.transmit(ApiMessage(text = response))
true
}
}
}
/**
*
*/
override fun validate(): Boolean {
return true
}
}
enum class CommandType {
PASSTHROUGH, RESPONSE
}

View File

@ -5,19 +5,19 @@ import matterlink.bridge.MessageHandler
import matterlink.config.cfg
object HelpCommand : IBridgeCommand {
override val name: String = "help"
override val alias: String = "help"
override val help: String = "Returns the help string for the given command. Syntax: help <command>"
override fun call(args: String): Boolean {
val msg: String = if (args.isEmpty()) {
"Available commands: ${ BridgeCommandRegistry.commandList}"
} else {
args.split(" ", ignoreCase = false)
.joinToString(separator = "\n") { "$it: ${ BridgeCommandRegistry.getHelpString(it) }" }
override val permLevel = 0
override fun execute(user:String, userId:String, server:String, args:String) : Boolean {
val msg: String = when {
args.isEmpty() ->
"Available commands: ${BridgeCommandRegistry.getCommandList(IBridgeCommand.getPermLevel(userId, server))}"
else -> args.split(" ", ignoreCase = false)
.joinToString(separator = "\n") {
"$it: ${ BridgeCommandRegistry.getHelpString(it) }"
}
}
MessageHandler.transmit(ApiMessage(
username = cfg.relay.systemUser,
text = msg
))
MessageHandler.transmit(ApiMessage(text = msg))
return true
}

View File

@ -1,7 +1,22 @@
package matterlink.bridge.command
import matterlink.config.PermissionConfig
interface IBridgeCommand {
val name: String
fun call(args: String): Boolean
val help: String
val alias : String
val help : String
val permLevel : Int
fun execute(user:String, userId:String, server:String, args:String) : Boolean
fun validate() = true
companion object {
fun getPermLevel(userId: String, server: String): Int {
if (PermissionConfig.perms[server] == null) return 0
return PermissionConfig.perms[server]?.get(userId) ?: 0
}
}
}

View File

@ -0,0 +1,10 @@
package matterlink.bridge.command
interface IMinecraftCommandSender {
/**
* @param cmdString The command to execute with its arguments
*
* @return True for success, or false for failure
*/
fun execute(cmdString: String) : Boolean
}

View File

@ -1,13 +0,0 @@
package matterlink.bridge.command
import matterlink.instance
class PassthroughCommand(override val name: String, val cmd: String) : IBridgeCommand {
override fun call(args: String): Boolean {
return instance.commandSender.execute("$cmd $args",100)
}
override val help: String = "No help available for this command."
}

View File

@ -1,26 +0,0 @@
package matterlink.bridge.command
import matterlink.instance
import matterlink.antiping
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.config.cfg
object PlayerListCommand : IBridgeCommand {
override val name: String = "players"
override val help: String = "Lists online players."
override fun call(args: String): Boolean {
if (args.isNotBlank()) return false
val playerList = instance.wrappedPlayerList()
MessageHandler.transmit(ApiMessage(
username = cfg.relay.systemUser,
text = when {
playerList.isNotEmpty() -> "players: " + playerList.joinToString(" ") { it.antiping }
else -> "No Players online"
}
))
return true
}
}

View File

@ -1,21 +0,0 @@
package matterlink.bridge.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.config.cfg
import matterlink.instance
object UptimeCommand : IBridgeCommand {
override val name: String = "uptime"
override val help: String = "Get server uptime."
override fun call(args: String): Boolean {
if (args.isNotBlank()) return false
MessageHandler.transmit(ApiMessage(
username = cfg.relay.systemUser,
text = instance.getUptimeAsString()
))
return true
}
}

View File

@ -1,11 +0,0 @@
package matterlink.command
interface IMinecraftCommandSender {
/**
* @param cmdString The command to execute with its arguments
* @param level Privilege level to execute this command at, currently unused
*
* @return Any output of the command
*/
fun execute(cmdString: String, level: Int) : Boolean
}

View File

@ -0,0 +1,48 @@
package matterlink.config
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import matterlink.bridge.command.CommandType
import matterlink.bridge.command.CustomCommand
import java.io.File
object CommandConfig {
private val gson: Gson = GsonBuilder().setPrettyPrinting().create()
private val configFile: File = cfg.cfgDirectory.resolve("commands.json")
private val default = arrayOf(
CustomCommand(
alias = "tps",
type = CommandType.PASSTHROUGH,
execute = "forge tps",
help = "Print server tps",
allowArgs = false
),
CustomCommand(
alias = "list",
type = CommandType.PASSTHROUGH,
execute = "list",
help = "List online players",
allowArgs = false
),
CustomCommand(
alias = "seed",
type = CommandType.PASSTHROUGH,
execute = "seed",
help = "Print server world seed",
allowArgs = false
)
)
fun readConfig() : Array<CustomCommand> {
if(!configFile.exists()) {
configFile.createNewFile()
configFile.writeText(gson.toJson(default))
return default
}
val text = configFile.readText()
return gson.fromJson(text, Array<CustomCommand>::class.java)
}
}

View File

@ -0,0 +1,27 @@
package matterlink.config
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.io.File
object PermissionConfig {
private val gson: Gson = GsonBuilder().setPrettyPrinting().create()
private val configFile: File = cfg.cfgDirectory.resolve("permissions.json")
private val default = hashMapOf<String,HashMap<String,Int>>()
var perms : HashMap<String,HashMap<String,Int>> = default
fun loadPermFile() {
if(!configFile.exists()) {
configFile.createNewFile()
perms = default
configFile.writeText(gson.toJson(default))
return
}
val text = configFile.readText()
perms = gson.fromJson(text, object : TypeToken <HashMap<String,HashMap<String,Int>>>(){}.type)
}
}

View File

@ -244,7 +244,7 @@ enable=true
#[[gateway.in]] specifies the account and channels we will receive messages from.
#The following example bridges between mattermost and irc
[[gateway.in]]
[[gateway.inout]]
account="irc.freenode"
channel="#matterlink"