Created
May 17, 2021 01:12
-
-
Save Moire9/121ca7d89fc352ed6f22ab48a6608202 to your computer and use it in GitHub Desktop.
Class to simplify eval commands for kotlin discord bots using kord. Currently uses slash commands, it would be easy to just use regular commands. To use, just initialize, and invoke with a string containing code to be executed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dev.kord.common.annotation.KordPreview | |
import dev.kord.core.Kord | |
import dev.kord.core.behavior.interaction.EphemeralInteractionResponseBehavior | |
import dev.kord.core.behavior.interaction.followUp | |
import dev.kord.core.entity.Guild | |
import dev.kord.core.entity.channel.Channel | |
import java.io.ByteArrayOutputStream | |
import java.io.PrintStream | |
import javax.script.ScriptEngineManager | |
import javax.script.ScriptException | |
@Suppress("unused") @KordPreview class EvalContext( | |
val client: Kord, | |
val channel: Channel, | |
val guild: Guild, | |
private val ack: EphemeralInteractionResponseBehavior | |
) { | |
private companion object { | |
/** This must contain the FULLY QUALIFIED NAME of this class!! */ | |
const val CLASS_NAME = "EvalContext" | |
private val man = object : ScriptEngineManager(Thread.currentThread().contextClassLoader) { | |
operator fun invoke() = getEngineByExtension("kts")!! | |
} | |
} | |
private val buf = StringBuilder() | |
private var ret: Any? = Unit | |
private var error = true | |
internal suspend operator fun invoke(code: String) = try { | |
@Suppress("UNCHECKED_CAST") | |
ret = (man().eval("run<suspend $CLASS_NAME.()->Any?>{{$code}}") | |
as suspend EvalContext.() -> Any?)(this) | |
error = false | |
} catch (e: ScriptException) { | |
out("```" + buildString { | |
var a = true | |
var b = false | |
for (line in ByteArrayOutputStream().also { e.printStackTrace(PrintStream(it)) }.toString(Charsets.UTF_8) | |
.lines()) { | |
if (a) { | |
val s = line.split(':', limit = 2)[1].trimStart() | |
appendLine(s) | |
if (s.startsWith("Error: incomplete code")) break | |
a = false | |
continue | |
} | |
if (b && line.isBlank()) break | |
if (line.trimStart().startsWith('^')) b = true | |
appendLine(line) | |
} | |
}.also(System.err::print) + "```") | |
} catch (e: Throwable) { | |
out("```" + buildString { | |
append("Exception in thread \"${Thread.currentThread().name}\" ") | |
for (line in ByteArrayOutputStream().also { e.printStackTrace(PrintStream(it)) }.toString(Charsets.UTF_8) | |
.lines()) { | |
if (line.startsWith("\tat Line_1\$1\$1.invokeSuspend(Line_1.kts:")) { | |
appendLine("\tat <eval>(<eval>:${line.split(':', limit = 2)[1].dropLast(1)})") | |
break | |
} | |
appendLine(line) | |
} | |
}.also(System.err::print) + "```") | |
} finally { | |
try { | |
var out = buf.toString() | |
if (!error) { | |
val hr = ret != Unit | |
val b = out.isBlank() | |
if (b && !hr) out = "\u200B" else { | |
if (!b) out = "```\n$out\n```" | |
if (hr) out += "```Return value: ${ret.toString()}```" | |
} | |
} | |
ack.followUp(out) | |
} catch (e: Exception) { e.printStackTrace() } | |
} | |
fun out(message: Any?) { buf.append(message) } | |
fun out(message: Int) { buf.append(message) } | |
fun out(message: Long) { buf.append(message) } | |
fun out(message: Byte) { buf.append(message) } | |
fun out(message: Short) { buf.append(message) } | |
fun out(message: Char) { buf.append(message) } | |
fun out(message: Boolean) { buf.append(message) } | |
fun out(message: Float) { buf.append(message) } | |
fun out(message: Double) { buf.append(message) } | |
fun out(message: CharArray) { buf.append(message) } | |
fun outln(message: Any?) { buf.appendLine(message) } | |
fun outln(message: Int) { buf.appendLine(message) } | |
fun outln(message: Long) { buf.appendLine(message) } | |
fun outln(message: Byte) { buf.appendLine(message) } | |
fun outln(message: Short) { buf.appendLine(message) } | |
fun outln(message: Char) { buf.appendLine(message) } | |
fun outln(message: Boolean) { buf.appendLine(message) } | |
fun outln(message: Float) { buf.appendLine(message) } | |
fun outln(message: Double) { buf.appendLine(message) } | |
fun outln(message: CharArray) { buf.appendLine(message) } | |
fun outln() { buf.appendLine() } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment