TheFrontier / SKC

Sponge+Kotlin annotation Commands
MIT License
0 stars 1 forks source link

Feature: Execution Transformers #1

Open ItsDoot opened 5 years ago

ItsDoot commented 5 years ago

Basically what I am looking for is a convenient way to wrap a function call given some annotations on the function.

A good starting point:

typealias ExecutionContext = MutableMap<String, Any?>

interface ExecutionTransformer {
    @Throws(CommandException::class)
    fun transform(src: CommandSource, context: ExecutionContext, next: () -> Unit)
}

My primary usecase: wrapping function calls in Exposed transaction blocks, to reduce redundancy.

import org.jetbrains.exposed.sql.transactions.transaction

annotation class Transactional

object TransactionExecutionTransformer : ExecutionTransformer {
    override fun transform(src: CommandSource, context: ExecutionContext, next: () -> Unit) {
        transaction {
            next()
        }
    }
}

@Transactional
@Command("mycmd")
fun mycmd(@Source src: CommandSource) {
    // we can do things with a table since we're in a transaction
}
ItsDoot commented 5 years ago

Commands requiring permissions should be built using an ExecutionTransformer.

annotation class Permission(val permission: String)

class PermissionTransformer(private val permission: String): ExecutionTransformer {
    override fun transform(src: CommandSource, context: ExecutionContext, next: () -> Unit) {
        if (!src.hasPermission(permission)) {
            throw CommandException(!"You do not have permission to use this command.")
        }
        next()
    }
}

@Permission("my.permission")
@Command("mycmd")
fun mycmd(@Source src: CommandSource) {
    // do stuff...
}

EDIT: Will not be doing this since permission checking is so integrated with CommandCallable

ItsDoot commented 5 years ago

Another usecase: Logging the time a command takes to run.


annotation class LogTime

class LogTimeTransformer(private val logger: Logger) : ExecutionTransformer {
    override fun transform(src: CommandSource, context: ExecutionContext, next: () -> Unit) {
        val time = measureTimeMillis {
            next()
        }
        logger.debug("Command took ${time}ms")
    }
}

@LogTime
@Command("mycmd")
fun mycmd(@Source src: CommandSource) {
    // do stuff...
}