Skip to content

Commit

Permalink
Feature/jshell (#870)
Browse files Browse the repository at this point in the history
* Feature/jshell from fork (#869)

* JShell feature added

* Added option to get the snippets of another user

* Refactored JShell eval into its own class

* Changed RateLimiter so it's a global limiter and not a per user limiter + merged user and oneOffSession together

* Added context action for running java code

* Fixing sonar wranings for jshell

* Added startupt scripts for jshell

* Formating jshell classes

* JShell javadoc and many minor code improvements

* JShell more minor code improvements

* Other minor code changes

* JShell now allows wrong uri and dead server, will give correct response to the user and will log them as warns

* Forgot one exception javadoc for jshell feature

* JShell refactored snippets send conditions
  • Loading branch information
Alathreon committed Aug 11, 2023
1 parent 0de9992 commit 03b1112
Show file tree
Hide file tree
Showing 26 changed files with 1,229 additions and 5 deletions.
5 changes: 5 additions & 0 deletions application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,9 @@
"logErrorChannelWebhook": "<put_your_webhook_here>",
"openaiApiKey": "<check pins in #tjbot_discussion for the key>",
"sourceCodeBaseUrl": "<https://github.com/<your_account_here>/<your_repo_here>/blob/master/application/src/main/java/>"
"jshell": {
"baseUrl": "<put_jshell_rest_api_url_here>",
"rateLimitWindowSeconds": 10,
"rateLimitRequestsInWindow": 3
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public final class Config {
private final String logErrorChannelWebhook;
private final String openaiApiKey;
private final String sourceCodeBaseUrl;
private final JShellConfig jshell;

@SuppressWarnings("ConstructorWithTooManyParameters")
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
Expand Down Expand Up @@ -74,7 +75,8 @@ private Config(@JsonProperty(value = "token", required = true) String token,
@JsonProperty(value = "logErrorChannelWebhook",
required = true) String logErrorChannelWebhook,
@JsonProperty(value = "openaiApiKey", required = true) String openaiApiKey,
@JsonProperty(value = "sourceCodeBaseUrl", required = true) String sourceCodeBaseUrl) {
@JsonProperty(value = "sourceCodeBaseUrl", required = true) String sourceCodeBaseUrl,
@JsonProperty(value = "jshell", required = true) JShellConfig jshell) {
this.token = Objects.requireNonNull(token);
this.gistApiKey = Objects.requireNonNull(gistApiKey);
this.databasePath = Objects.requireNonNull(databasePath);
Expand All @@ -99,6 +101,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
this.logErrorChannelWebhook = Objects.requireNonNull(logErrorChannelWebhook);
this.openaiApiKey = Objects.requireNonNull(openaiApiKey);
this.sourceCodeBaseUrl = Objects.requireNonNull(sourceCodeBaseUrl);
this.jshell = Objects.requireNonNull(jshell);
}

/**
Expand Down Expand Up @@ -330,4 +333,13 @@ public String getOpenaiApiKey() {
public String getSourceCodeBaseUrl() {
return sourceCodeBaseUrl;
}

/**
* The configuration about jshell REST API and command/code action settings.
*
* @return the jshell configuration
*/
public JShellConfig getJshell() {
return jshell;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.togetherjava.tjbot.config;


import org.togetherjava.tjbot.features.utils.RateLimiter;

import java.util.Objects;

/**
* JShell config.
*
* @param baseUrl the base url of the JShell REST API
* @param rateLimitWindowSeconds the number of seconds of the {@link RateLimiter rate limiter} for
* jshell commands and code actions
* @param rateLimitRequestsInWindow the number of requests of the {@link RateLimiter rate limiter}
* for jshell commands and code actions
*/
public record JShellConfig(String baseUrl, int rateLimitWindowSeconds,
int rateLimitRequestsInWindow) {
/**
* Creates a JShell config.
*
* @param baseUrl the base url of the JShell REST API, must be not null
* @param rateLimitWindowSeconds the number of seconds of the {@link RateLimiter rate limiter}
* for jshell commands and code actions, must be higher than 0
* @param rateLimitRequestsInWindow the number of requests of the {@link RateLimiter rate
* limiter} for jshell commands and code actions, must be higher than 0
*/
public JShellConfig {
Objects.requireNonNull(baseUrl);
if (rateLimitWindowSeconds < 0) {
throw new IllegalArgumentException(
"Illegal rateLimitWindowSeconds : " + rateLimitWindowSeconds);
}
if (rateLimitRequestsInWindow < 0) {
throw new IllegalArgumentException(
"Illegal rateLimitRequestsInWindow : " + rateLimitRequestsInWindow);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.togetherjava.tjbot.features.code.CodeMessageManualDetection;
import org.togetherjava.tjbot.features.filesharing.FileSharingMessageListener;
import org.togetherjava.tjbot.features.help.*;
import org.togetherjava.tjbot.features.jshell.JShellCommand;
import org.togetherjava.tjbot.features.jshell.JShellEval;
import org.togetherjava.tjbot.features.mathcommands.TeXCommand;
import org.togetherjava.tjbot.features.mathcommands.wolframalpha.WolframAlphaCommand;
import org.togetherjava.tjbot.features.mediaonly.MediaOnlyChannelListener;
Expand Down Expand Up @@ -67,13 +69,15 @@ private Features() {
* @return a collection of all features
*/
public static Collection<Feature> createFeatures(JDA jda, Database database, Config config) {
JShellEval jshellEval = new JShellEval(config.getJshell());

TagSystem tagSystem = new TagSystem(database);
BookmarksSystem bookmarksSystem = new BookmarksSystem(config, database);
ModerationActionsStore actionsStore = new ModerationActionsStore(database);
ModAuditLogWriter modAuditLogWriter = new ModAuditLogWriter(config);
ScamHistoryStore scamHistoryStore = new ScamHistoryStore(database);
HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database);
CodeMessageHandler codeMessageHandler = new CodeMessageHandler();
CodeMessageHandler codeMessageHandler = new CodeMessageHandler(jshellEval);
ChatGptService chatGptService = new ChatGptService(config);

// NOTE The system can add special system relevant commands also by itself,
Expand Down Expand Up @@ -143,6 +147,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new ReportCommand(config));
features.add(new BookmarksCommand(bookmarksSystem));
features.add(new ChatGptCommand(chatGptService));
features.add(new JShellCommand(jshellEval));
return features;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.togetherjava.tjbot.features.UserInteractor;
import org.togetherjava.tjbot.features.componentids.ComponentIdGenerator;
import org.togetherjava.tjbot.features.componentids.ComponentIdInteractor;
import org.togetherjava.tjbot.features.jshell.JShellEval;
import org.togetherjava.tjbot.features.utils.CodeFence;
import org.togetherjava.tjbot.features.utils.MessageUtils;

Expand Down Expand Up @@ -62,11 +63,14 @@ public final class CodeMessageHandler extends MessageReceiverAdapter implements

/**
* Creates a new instance.
*
* @param jshellEval used to execute java code and build visual result
*/
public CodeMessageHandler() {
public CodeMessageHandler(JShellEval jshellEval) {
componentIdInteractor = new ComponentIdInteractor(getInteractionType(), getName());

List<CodeAction> codeActions = List.of(new FormatCodeCommand());
List<CodeAction> codeActions =
List.of(new FormatCodeCommand(), new EvalCodeCommand(jshellEval));

labelToCodeAction = codeActions.stream()
.collect(Collectors.toMap(CodeAction::getLabel, Function.identity(), (x, y) -> y,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.togetherjava.tjbot.features.code;

import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;

import org.togetherjava.tjbot.features.jshell.JShellEval;
import org.togetherjava.tjbot.features.utils.CodeFence;
import org.togetherjava.tjbot.features.utils.Colors;
import org.togetherjava.tjbot.features.utils.ConnectionFailedException;
import org.togetherjava.tjbot.features.utils.RequestFailedException;

/**
* Evaluates the given code with jshell.
* <p>
* It will not work of the code isn't valid java or jshell compatible code.
*/
final class EvalCodeCommand implements CodeAction {
private final JShellEval jshellEval;

EvalCodeCommand(JShellEval jshellEval) {
this.jshellEval = jshellEval;
}

@Override
public String getLabel() {
return "Run code";
}

@Override
public MessageEmbed apply(CodeFence codeFence) {
if (codeFence.code().isEmpty()) {
return new EmbedBuilder().setColor(Colors.ERROR_COLOR)
.setDescription("There is nothing to evaluate")
.build();
}
try {
return jshellEval.evaluateAndRespond(null, codeFence.code(), false, false);
} catch (RequestFailedException | ConnectionFailedException e) {
return new EmbedBuilder().setColor(Colors.ERROR_COLOR)
.setDescription("Request failed: " + e.getMessage())
.build();
}
}

}
Loading

0 comments on commit 03b1112

Please sign in to comment.