Skip to content

Commit 46539ef

Browse files
committed
[ci-skip] Add eval engine for debugging the clientn
1 parent a68bd2f commit 46539ef

File tree

3 files changed

+166
-6
lines changed

3 files changed

+166
-6
lines changed

testbot/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
java
33
application
4+
kotlin("jvm")
45
}
56

67
group = "me.duncte123"
@@ -15,6 +16,9 @@ dependencies {
1516
// Include the lavalink client
1617
implementation(projects.lavalinkClient)
1718

19+
// implementation(kotlin("stdlib")) // Do we need this?
20+
implementation(kotlin("scripting-jsr223"))
21+
1822
// other libs such as a discord client and a logger
1923
implementation(libs.jda)
2024
implementation(libs.logger.impl)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package me.duncte123.testbot;
2+
3+
import dev.arbjerg.lavalink.client.LavalinkClient;
4+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
5+
6+
import javax.script.ScriptEngine;
7+
import javax.script.ScriptEngineManager;
8+
import javax.script.ScriptException;
9+
import javax.script.SimpleBindings;
10+
import java.util.List;
11+
import java.util.concurrent.ExecutorService;
12+
import java.util.concurrent.Executors;
13+
import java.util.concurrent.Future;
14+
import java.util.concurrent.TimeUnit;
15+
import java.util.function.Function;
16+
import java.util.stream.Collectors;
17+
18+
public class EvalEngine {
19+
private final ExecutorService evalThread = Executors.newThreadPerTaskExecutor(
20+
(it) -> Thread.ofVirtual()
21+
.name("eval-thread")
22+
.unstarted(it)
23+
);
24+
25+
private final ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("kts");
26+
27+
private final LavalinkClient client;
28+
29+
public EvalEngine(LavalinkClient client) {
30+
this.client = client;
31+
this.initEngine();
32+
}
33+
34+
public Object eval(SlashCommandInteractionEvent slashEvent, String code) {
35+
final var bindings = new SimpleBindings();
36+
37+
bindings.put("client", this.client);
38+
bindings.put("event", slashEvent);
39+
bindings.put("guild", slashEvent.getGuild());
40+
bindings.put("jda", slashEvent.getJDA());
41+
42+
final Future<Object> future = this.evalThread.submit(() -> {
43+
try {
44+
return this.engine.eval(code, bindings);
45+
} catch (final Exception e) {
46+
return e;
47+
}
48+
});
49+
50+
51+
try {
52+
return future.get(5, TimeUnit.SECONDS);
53+
} catch (Exception ex) {
54+
future.cancel(true);
55+
return ex;
56+
}
57+
}
58+
59+
private void initEngine() {
60+
final var packageImports = List.of(
61+
"java.io",
62+
"java.lang",
63+
"java.math",
64+
"java.time",
65+
"java.util",
66+
"java.util.concurrent",
67+
"java.util.stream",
68+
"net.dv8tion.jda.api",
69+
"net.dv8tion.jda.internal.entities",
70+
"net.dv8tion.jda.api.entities",
71+
"net.dv8tion.jda.api.entities.channel",
72+
"net.dv8tion.jda.api.entities.channel.attribute",
73+
"net.dv8tion.jda.api.entities.channel.middleman",
74+
"net.dv8tion.jda.api.entities.channel.concrete",
75+
"net.dv8tion.jda.api.managers",
76+
"net.dv8tion.jda.internal.managers",
77+
"net.dv8tion.jda.api.utils",
78+
"dev.arbjerg.lavalink.client",
79+
"dev.arbjerg.lavalink.client.player",
80+
"dev.arbjerg.lavalink.client.http",
81+
"dev.arbjerg.lavalink.client.event"
82+
);
83+
84+
final List<String> classImports = List.of(
85+
// Nothing needed for now
86+
);
87+
88+
// classImports.joinToString(separator = "\nimport ", postfix = "\n")
89+
90+
final var importString = packageImports.stream()
91+
.map((i) -> "import " + i + ".*")
92+
.collect(Collectors.joining("\n"))/* + classImports.stream().collect(Collectors.joining(
93+
"", "\nimport ", "\n"
94+
))*/;
95+
96+
97+
try {
98+
this.engine.eval(importString);
99+
} catch (ScriptException e) {
100+
throw new RuntimeException(e);
101+
}
102+
}
103+
}

testbot/src/main/java/me/duncte123/testbot/JDAListener.java

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@
1717
import net.dv8tion.jda.api.interactions.commands.OptionType;
1818
import net.dv8tion.jda.api.interactions.commands.build.Commands;
1919
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
20+
import net.dv8tion.jda.api.requests.RestAction;
2021
import org.jetbrains.annotations.NotNull;
2122
import org.slf4j.Logger;
2223
import org.slf4j.LoggerFactory;
2324

2425
public class JDAListener extends ListenerAdapter {
26+
private static final long DUNCTE = 191231307290771456L;
27+
2528
private static final Logger LOG = LoggerFactory.getLogger(JDAListener.class);
2629

2730
private final LavalinkClient client;
31+
private final EvalEngine evalEngine;
2832

2933
public JDAListener(LavalinkClient client) {
3034
this.client = client;
35+
this.evalEngine = new EvalEngine(client);
3136
}
3237

3338
@Override
@@ -38,11 +43,11 @@ public void onReady(@NotNull ReadyEvent event) {
3843
.addCommands(
3944
Commands.slash("lyrics", "Testing custom requests"),
4045
Commands.slash("node", "What node am I on?"),
41-
Commands.slash("del-node", "test")
46+
Commands.slash("eval", "test out some code")
4247
.addOption(
4348
OptionType.STRING,
44-
"node-name",
45-
"Name of the node",
49+
"script",
50+
"Script to eval",
4651
true
4752
),
4853
Commands.slash("join", "Join the voice channel you are in."),
@@ -87,9 +92,25 @@ public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent even
8792

8893
break;
8994
}
90-
case "del-node": {
91-
this.client.removeNode(event.getOption("node-name").getAsString());
92-
event.reply("Ok").queue();
95+
case "eval": {
96+
final var user = event.getUser();
97+
98+
if (user.getIdLong() != DUNCTE) {
99+
event.replyFormat("I'm sorry %s, I'm afraid I can't let you do that", user.getAsMention()).queue();
100+
return;
101+
}
102+
103+
event.deferReply().queue();
104+
105+
Thread.ofVirtual().start(() -> {
106+
try {
107+
final var script = event.getOption("script").getAsString();
108+
final var result = this.evalEngine.eval(event, script);
109+
this.parseEvalResult(event, result);
110+
} catch (final Exception e) {
111+
LOG.error("Failed to eval", e);
112+
}
113+
});
93114
break;
94115
}
95116
case "join":
@@ -242,6 +263,38 @@ public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent even
242263
}
243264
}
244265

266+
private void parseEvalResult(SlashCommandInteractionEvent event, Object result) {
267+
final var hook = event.getHook();
268+
269+
if (result == null) {
270+
hook.sendMessage("No result").queue();
271+
return;
272+
}
273+
274+
switch (result) {
275+
case Throwable thr: {
276+
hook.sendMessage("ERROR: " + thr).queue();
277+
break;
278+
}
279+
280+
case RestAction<?> ra: {
281+
ra.queue(
282+
(res) -> {
283+
hook.sendMessage("Rest action success: " + res).queue();
284+
},
285+
(err) -> {
286+
hook.sendMessage("Rest action error: " + err).queue();
287+
}
288+
);
289+
}
290+
291+
default: {
292+
hook.sendMessage("result: " + result).queue();
293+
break;
294+
}
295+
}
296+
}
297+
245298
// Makes sure that the bot is in a voice channel!
246299
private void joinHelper(SlashCommandInteractionEvent event) {
247300
final Member member = event.getMember();

0 commit comments

Comments
 (0)