diff --git a/src/main/java/com/gmail/inverseconduit/BotConfig.java b/src/main/java/com/gmail/inverseconduit/BotConfig.java
index 4b59537..cf3c84f 100644
--- a/src/main/java/com/gmail/inverseconduit/BotConfig.java
+++ b/src/main/java/com/gmail/inverseconduit/BotConfig.java
@@ -8,6 +8,7 @@
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
+
import com.gmail.inverseconduit.datatype.CredentialsProvider;
/**
@@ -76,6 +77,7 @@ public String getLoginPassword() {
/**
* Gets the string sequence that triggers the bot.
*
+ * @return the string considered the trigger
* @deprecated This constant is only here for legacy purposes. Use
* @ListenerProperty to specify the command invocation
* sequence(s).
diff --git a/src/main/java/com/gmail/inverseconduit/bot/AbstractBot.java b/src/main/java/com/gmail/inverseconduit/bot/AbstractBot.java
new file mode 100644
index 0000000..23aac84
--- /dev/null
+++ b/src/main/java/com/gmail/inverseconduit/bot/AbstractBot.java
@@ -0,0 +1,37 @@
+package com.gmail.inverseconduit.bot;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import com.gmail.inverseconduit.chat.ChatWorker;
+import com.gmail.inverseconduit.datatype.ChatMessage;
+
+public abstract class AbstractBot implements ChatWorker {
+
+ protected final ScheduledExecutorService executor = Executors
+ .newSingleThreadScheduledExecutor();
+
+ protected final ExecutorService processingThread = Executors
+ .newSingleThreadExecutor();
+
+ protected final BlockingQueue messageQueue = new LinkedBlockingQueue<>();
+
+ @Override
+ public final synchronized boolean enqueueMessage(ChatMessage chatMessage)
+ throws InterruptedException {
+ return messageQueue.offer(chatMessage, 200, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public abstract void start();
+
+ @Override
+ protected void finalize() {
+ executor.shutdownNow();
+ }
+
+}
diff --git a/src/main/java/com/gmail/inverseconduit/bot/DefaultBot.java b/src/main/java/com/gmail/inverseconduit/bot/DefaultBot.java
index 522bb40..b6faf20 100644
--- a/src/main/java/com/gmail/inverseconduit/bot/DefaultBot.java
+++ b/src/main/java/com/gmail/inverseconduit/bot/DefaultBot.java
@@ -1,23 +1,22 @@
package com.gmail.inverseconduit.bot;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
-import com.gmail.inverseconduit.chat.ChatWorker;
+import com.gmail.inverseconduit.AppContext;
+import com.gmail.inverseconduit.BotConfig;
+import com.gmail.inverseconduit.chat.ChatInterface;
import com.gmail.inverseconduit.chat.Subscribable;
import com.gmail.inverseconduit.commands.CommandHandle;
import com.gmail.inverseconduit.datatype.ChatMessage;
+import com.gmail.inverseconduit.datatype.SeChatDescriptor;
/**
* Defines bot core functionality. A bot manages {@link CommandHandle
- * CommandHandles}.
- * Additionally messages should be enqueued to him, using
+ * CommandHandles}. Additionally messages should be enqueued to him, using
* {@link DefaultBot#enqueueMessage(ChatMessage) enqueueMessage}.
*
* These messages will get preprocessed and then passed to their respective
@@ -27,21 +26,16 @@
* >vincentyification@gmail.com>
* @author Vogel612<vogel612@gmx.de>
*/
-public class DefaultBot implements Subscribable, ChatWorker {
+public class DefaultBot extends AbstractBot implements Subscribable {
- private final Logger LOGGER = Logger.getLogger(DefaultBot.class.getName());
+ private final Logger LOGGER = Logger.getLogger(DefaultBot.class.getName());
- protected final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+ protected final ChatInterface chatInterface;
- protected final BlockingQueue messageQueue = new LinkedBlockingQueue<>();
+ protected final Set commands = new HashSet<>();
- protected final Set commands = new HashSet<>();
-
- public DefaultBot() {}
-
- @Override
- public synchronized boolean enqueueMessage(ChatMessage chatMessage) throws InterruptedException {
- return messageQueue.offer(chatMessage, 200, TimeUnit.MILLISECONDS);
+ public DefaultBot(ChatInterface chatInterface) {
+ this.chatInterface = chatInterface;
}
@Override
@@ -51,14 +45,22 @@ public void start() {
private void processMessageQueue() {
while (messageQueue.peek() != null) {
- LOGGER.info("processing message from queue");
- processMessage();
+ LOGGER.finest("processing message from queue");
+ processingThread.submit(() -> processMessage(messageQueue.poll()));
}
}
- private void processMessage() {
- final ChatMessage message = messageQueue.poll();
- commands.stream().filter(c -> c.matchesSyntax(message.getMessage())).findFirst().ifPresent(c -> c.execute(message));
+ private void processMessage(final ChatMessage chatMessage) {
+ final String trigger = AppContext.INSTANCE.get(BotConfig.class).getTrigger();
+ if ( !chatMessage.getMessage().startsWith(trigger)) { return; }
+
+ commands.stream()
+ // FIXME: make the trigger removal for call-by-name better!!
+ .filter(c -> c.getName().equalsIgnoreCase(chatMessage.getMessage().replace(trigger, ""))).findFirst().map(c -> c.execute(chatMessage)).ifPresent(result -> chatInterface.sendMessage(SeChatDescriptor.buildSeChatDescriptorFrom(chatMessage), result));
+ }
+
+ public Set getCommands() {
+ return Collections.unmodifiableSet(commands);
}
@Override
@@ -71,8 +73,8 @@ public void unSubscribe(CommandHandle subscriber) {
commands.remove(subscriber);
}
- @Override
- protected void finalize() {
- executor.shutdownNow();
+ public void shutdown() {
+ executor.shutdown();
}
+
}
diff --git a/src/main/java/com/gmail/inverseconduit/bot/InteractionBot.java b/src/main/java/com/gmail/inverseconduit/bot/InteractionBot.java
new file mode 100644
index 0000000..72718f4
--- /dev/null
+++ b/src/main/java/com/gmail/inverseconduit/bot/InteractionBot.java
@@ -0,0 +1,59 @@
+package com.gmail.inverseconduit.bot;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.gmail.inverseconduit.bot.interactions.Interaction;
+import com.gmail.inverseconduit.bot.interactions.Interactions;
+import com.gmail.inverseconduit.chat.ChatInterface;
+import com.gmail.inverseconduit.chat.Subscribable;
+import com.gmail.inverseconduit.datatype.ChatMessage;
+import com.gmail.inverseconduit.datatype.SeChatDescriptor;
+
+public class InteractionBot extends AbstractBot implements
+ Subscribable {
+
+ private final ChatInterface chatInterface;
+
+ protected final Set interactions = new HashSet<>();
+
+ public InteractionBot(ChatInterface chatInterface) {
+ this.chatInterface = chatInterface;
+ Interactions.getPerminteractions().forEach(interactions::add);
+ }
+
+ @Override
+ public void start() {
+ executor.scheduleAtFixedRate(this::processInteractions, 200, 700,
+ TimeUnit.MILLISECONDS);
+ }
+
+ private void processInteractions() {
+ if (messageQueue.peek() != null) {
+ processingThread.submit(() -> interact(messageQueue.poll()));
+ }
+ }
+
+ private void interact(ChatMessage message) {
+ interactions
+ .stream()
+ .filter(interaction -> interaction.getCondition().test(
+ message.getMessage()))
+ .findFirst()
+ .ifPresent(
+ action -> chatInterface.sendMessage(SeChatDescriptor
+ .buildSeChatDescriptorFrom(message), action
+ .getResponse()));
+ }
+
+ @Override
+ public void subscribe(Interaction subscriber) {
+ interactions.add(subscriber);
+ }
+
+ @Override
+ public void unSubscribe(Interaction subscriber) {
+ interactions.remove(subscriber);
+ }
+}
diff --git a/src/main/java/com/gmail/inverseconduit/bot/Program.java b/src/main/java/com/gmail/inverseconduit/bot/Program.java
index 7d0fe89..11994ea 100644
--- a/src/main/java/com/gmail/inverseconduit/bot/Program.java
+++ b/src/main/java/com/gmail/inverseconduit/bot/Program.java
@@ -14,12 +14,10 @@
import com.gmail.inverseconduit.SESite;
import com.gmail.inverseconduit.chat.ChatInterface;
import com.gmail.inverseconduit.chat.StackExchangeChat;
-import com.gmail.inverseconduit.chat.commands.ChatCommands;
import com.gmail.inverseconduit.commands.CommandHandle;
+import com.gmail.inverseconduit.commands.sets.CoreBotCommands;
import com.gmail.inverseconduit.datatype.SeChatDescriptor;
import com.gmail.inverseconduit.javadoc.JavaDocAccessor;
-import com.gmail.inverseconduit.scripts.ScriptRunner;
-import com.gmail.inverseconduit.scripts.ScriptRunnerCommands;
/**
* Class to contain the program, to be started from main. This class is
@@ -27,167 +25,104 @@
*
* @author vogel612<vogel612@gmx.de>
*/
-@SuppressWarnings("deprecation")
public class Program {
- private static final Logger LOGGER = Logger.getLogger(Program.class
- .getName());
-
- private static final ScheduledExecutorService executor = Executors
- .newSingleThreadScheduledExecutor();
-
- private static final BotConfig config = AppContext.INSTANCE
- .get(BotConfig.class);
-
- private final DefaultBot bot;
-
- private final ChatInterface chatInterface;
-
- private final ScriptRunner scriptRunner;
-
- private final JavaDocAccessor javaDocAccessor;
-
- private static final Pattern javadocPattern = Pattern.compile(
- "^" + Pattern.quote(config.getTrigger()) + "javadoc:(.*)",
- Pattern.DOTALL);
-
- /**
- * @throws IOException
- * if there's a problem loading the Javadocs
- */
- public Program() throws IOException {
- LOGGER.finest("Instantiating Program");
- chatInterface = new StackExchangeChat();
- bot = new DefaultBot();
-
- chatInterface.subscribe(bot);
-
- javaDocAccessor = new JavaDocAccessor(chatInterface,
- config.getJavadocsDir());
- scriptRunner = new ScriptRunner(chatInterface);
- LOGGER.info("Basic component setup complete");
- }
-
- /**
- * This is where the beef happens. Glue all the stuff together here
- */
- public void startup() {
- LOGGER.info("Beginning startup process");
- bindDefaultCommands();
- login();
- for (Integer room : config.getRooms()) {
- chatInterface.joinChat(new SeChatDescriptor.DescriptorBuilder(
- SESite.STACK_OVERFLOW).setRoom(() -> room).build());
- }
- scheduleQueryingThread();
- bot.start();
- LOGGER.info("Startup completed.");
- }
-
- private void scheduleQueryingThread() {
- executor.scheduleAtFixedRate(
- () -> {
- try {
- chatInterface.queryMessages();
- } catch (RuntimeException | Error e) {
- Logger.getAnonymousLogger().log(Level.SEVERE,
- "Throwable occurred in querying thread", e);
- throw e;
- } catch (Exception e) {
- Logger.getAnonymousLogger().log(Level.WARNING,
- "Exception occured in querying thread:", e);
- }
- }, 5, 3, TimeUnit.SECONDS);
- Logger.getAnonymousLogger().info("querying thread started");
- }
-
- private void login() {
- boolean loggedIn = chatInterface.login(SESite.STACK_OVERFLOW, config);
- if (!loggedIn) {
- Logger.getAnonymousLogger().severe("Login failed!");
- System.exit(2);
- }
- }
-
- private void bindDefaultCommands() {
- bindHelpCommand();
- bindShutdownCommand();
- bindEvalCommand();
- bindLoadCommand();
- bindJavaDocCommand();
- bindTestCommand();
- bindSummonCommand();
- bindUnsummonCommand();
- }
-
- private void bindUnsummonCommand() {
- CommandHandle unsummon = ChatCommands.unsummonCommand(chatInterface);
- bot.subscribe(unsummon);
- }
-
- private void bindSummonCommand() {
- CommandHandle summon = ChatCommands.summonCommand(chatInterface);
- bot.subscribe(summon);
- }
-
- private void bindEvalCommand() {
- CommandHandle eval = ScriptRunnerCommands.evalCommand(scriptRunner);
- bot.subscribe(eval);
- }
-
- private void bindLoadCommand() {
- CommandHandle load = ScriptRunnerCommands.loadCommand(scriptRunner);
- bot.subscribe(load);
- }
-
- private void bindHelpCommand() {
- CommandHandle help = new CommandHandle.Builder(
- "help",
- s -> {
- return s.trim().startsWith(config.getTrigger() + "help");
- },
- message -> {
- chatInterface.sendMessage(
- SeChatDescriptor.buildSeChatDescriptorFrom(message),
- String.format(
- "@%s I am JavaBot, maintained by Uni, Vogel, and a few others. You can find me on http://github.com/Vincentyification/JavaBot",
- message.getUsername()));
- }).build();
- bot.subscribe(help);
- }
-
- private void bindJavaDocCommand() {
- CommandHandle javaDoc = new CommandHandle.Builder("javadoc",
- javadocPattern.asPredicate(), message -> {
- Matcher matcher = javadocPattern.matcher(message
- .getMessage());
- matcher.find();
- javaDocAccessor.javadoc(message, matcher.group(1).trim());
- }).build();
- bot.subscribe(javaDoc);
- }
-
- private void bindShutdownCommand() {
- CommandHandle shutdown = new CommandHandle.Builder("shutdown", s -> {
- return s.trim().startsWith(config.getTrigger() + "shutdown");
- }, message -> {
- // FIXME: Require permissions for this
- chatInterface.broadcast("*~going down*");
- executor.shutdownNow();
- System.exit(0);
- }).build();
- bot.subscribe(shutdown);
- }
-
- private void bindTestCommand() {
- CommandHandle test = new CommandHandle.Builder(
- "test",
- s -> s.equals("test"),
- message -> {
- chatInterface.sendMessage(
- SeChatDescriptor.buildSeChatDescriptorFrom(message),
- "*~response*");
- }).build();
- bot.subscribe(test);
- }
+ private static final Logger LOGGER = Logger.getLogger(Program.class.getName());
+
+ private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
+ private static final BotConfig config = AppContext.INSTANCE.get(BotConfig.class);
+
+ private final DefaultBot bot;
+
+ private final InteractionBot interactionBot;
+
+ private final ChatInterface chatInterface = new StackExchangeChat();
+
+ private final JavaDocAccessor javaDocAccessor;
+
+ private static final Pattern javadocPattern = Pattern.compile("^" + Pattern.quote(config.getTrigger()) + "javadoc:(.*)", Pattern.DOTALL);
+
+ /**
+ * @throws IOException
+ * if there's a problem loading the Javadocs
+ */
+ // TODO: get the chatInterface solved via Dependency Injection instead.
+ // This would greatly improve testability and ease of switching
+ // implementations
+ public Program() throws IOException {
+ LOGGER.finest("Instantiating Program");
+ bot = new DefaultBot(chatInterface);
+ interactionBot = new InteractionBot(chatInterface);
+
+ //better not get ExceptionInInitializerError
+ javaDocAccessor = new JavaDocAccessor(config.getJavadocsDir());
+ chatInterface.subscribe(bot);
+ chatInterface.subscribe(interactionBot);
+ LOGGER.info("Basic component setup complete");
+ }
+
+ /**
+ * This is where the beef happens. Glue all the stuff together here
+ */
+ public void startup() {
+ LOGGER.info("Beginning startup process");
+ bindDefaultCommands();
+ login();
+ for (Integer room : config.getRooms()) {
+ chatInterface.joinChat(new SeChatDescriptor.DescriptorBuilder(SESite.STACK_OVERFLOW).setRoom(() -> room).build());
+ }
+ scheduleQueryingThread();
+ bot.start();
+ interactionBot.start();
+ LOGGER.info("Startup completed.");
+ }
+
+ private void scheduleQueryingThread() {
+ executor.scheduleAtFixedRate(() -> {
+ try {
+ chatInterface.queryMessages();
+ } catch(RuntimeException | Error e) {
+ Logger.getAnonymousLogger().log(Level.SEVERE, "Runtime Exception or Error occurred in querying thread", e);
+ throw e;
+ } catch(Exception e) {
+ Logger.getAnonymousLogger().log(Level.WARNING, "Exception occured in querying thread:", e);
+ }
+ }, 5, 3, TimeUnit.SECONDS);
+ Logger.getAnonymousLogger().info("querying thread started");
+ }
+
+ private void login() {
+ boolean loggedIn = chatInterface.login(SESite.STACK_OVERFLOW, config);
+ if ( !loggedIn) {
+ Logger.getAnonymousLogger().severe("Login failed!");
+ System.exit(2);
+ }
+ }
+
+ private void bindDefaultCommands() {
+ bindShutdownCommand();
+ bindJavaDocCommand();
+ new CoreBotCommands(chatInterface).allCommands().forEach(bot::subscribe);
+ }
+
+ private void bindJavaDocCommand() {
+ CommandHandle javaDoc = new CommandHandle.Builder("javadoc", message -> {
+ Matcher matcher = javadocPattern.matcher(message.getMessage());
+ matcher.find();
+ return javaDocAccessor.javadoc(message, matcher.group(1).trim());
+ }).build();
+ bot.subscribe(javaDoc);
+ }
+
+ private void bindShutdownCommand() {
+ CommandHandle shutdown = new CommandHandle.Builder("shutdown", message -> {
+ // FIXME: Require permissions for this
+ chatInterface.broadcast("*~going down*");
+ executor.shutdownNow();
+ System.exit(0);
+ return "";
+ }).build();
+ bot.subscribe(shutdown);
+ }
}
diff --git a/src/main/java/com/gmail/inverseconduit/bot/interactions/Interaction.java b/src/main/java/com/gmail/inverseconduit/bot/interactions/Interaction.java
new file mode 100644
index 0000000..a1ae7c2
--- /dev/null
+++ b/src/main/java/com/gmail/inverseconduit/bot/interactions/Interaction.java
@@ -0,0 +1,24 @@
+package com.gmail.inverseconduit.bot.interactions;
+
+import java.util.function.Predicate;
+
+public class Interaction {
+
+ private final Predicate condition;
+
+ private final String response;
+
+ public Interaction(Predicate condition, String response) {
+ this.condition = condition;
+ this.response = response;
+ }
+
+ public Predicate getCondition() {
+ return condition;
+ }
+
+ public String getResponse() {
+ return response;
+ }
+
+}
diff --git a/src/main/java/com/gmail/inverseconduit/bot/interactions/Interactions.java b/src/main/java/com/gmail/inverseconduit/bot/interactions/Interactions.java
new file mode 100644
index 0000000..1873cc8
--- /dev/null
+++ b/src/main/java/com/gmail/inverseconduit/bot/interactions/Interactions.java
@@ -0,0 +1,29 @@
+package com.gmail.inverseconduit.bot.interactions;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public final class Interactions {
+
+ private static final Set permInteractions = new HashSet<>();
+
+ static {
+ permInteractions.add(howDoI());
+ permInteractions.add(thatWord());
+ }
+
+ public static Set getPerminteractions() {
+ return Collections.unmodifiableSet(permInteractions);
+ }
+
+ private static Interaction howDoI() {
+ return new Interaction((s) -> {
+ return s.startsWith("how do I") || s.startsWith("how do i");
+ }, "~ Write **code**");
+ }
+
+ private static Interaction thatWord() {
+ return new Interaction((s) -> s.contains("you keep using that word"), "https://www.youtube.com/watch?v=G2y8Sx4B2Sk");
+ }
+}
diff --git a/src/main/java/com/gmail/inverseconduit/chat/ChatInterface.java b/src/main/java/com/gmail/inverseconduit/chat/ChatInterface.java
index d512678..6be81af 100644
--- a/src/main/java/com/gmail/inverseconduit/chat/ChatInterface.java
+++ b/src/main/java/com/gmail/inverseconduit/chat/ChatInterface.java
@@ -19,7 +19,7 @@
* @author Vogel612<vogel612@gmx.de>
*/
@ThreadSafe
-public interface ChatInterface extends Subscribable {
+public interface ChatInterface extends Subscribable, AutoCloseable {
/**
* Queries the messages of the chat. This method is designed to be called
@@ -89,4 +89,9 @@ public interface ChatInterface extends Subscribable {
* the broadcast message
*/
void broadcast(String message);
+
+ @Override
+ default void close() throws Exception {
+
+ }
}
diff --git a/src/main/java/com/gmail/inverseconduit/chat/StackExchangeChat.java b/src/main/java/com/gmail/inverseconduit/chat/StackExchangeChat.java
index 1ffb2b5..bc540f1 100644
--- a/src/main/java/com/gmail/inverseconduit/chat/StackExchangeChat.java
+++ b/src/main/java/com/gmail/inverseconduit/chat/StackExchangeChat.java
@@ -326,4 +326,12 @@ public void unSubscribe(final ChatWorker subscriber) {
subscribers.remove(subscriber);
}
+ @Override
+ public void close() throws Exception {
+ subscribers.clear();
+ chatMap.clear();
+ sender.shutdown();
+ webClient.closeAllWindows();
+ }
+
}
diff --git a/src/main/java/com/gmail/inverseconduit/chat/Subscribable.java b/src/main/java/com/gmail/inverseconduit/chat/Subscribable.java
index 7a5f2bc..0443052 100644
--- a/src/main/java/com/gmail/inverseconduit/chat/Subscribable.java
+++ b/src/main/java/com/gmail/inverseconduit/chat/Subscribable.java
@@ -6,6 +6,8 @@
* One can subscribe and unSubscribe instances of T to recieve produced U's
*
* @author Vogel612<vogel612@gmx.de>
+ * @param
+ * The Class of Subscriber instances, that can handle instances of U
*/
public interface Subscribable {
diff --git a/src/main/java/com/gmail/inverseconduit/commands/CommandHandle.java b/src/main/java/com/gmail/inverseconduit/commands/CommandHandle.java
index 5ce05b4..05db77c 100644
--- a/src/main/java/com/gmail/inverseconduit/commands/CommandHandle.java
+++ b/src/main/java/com/gmail/inverseconduit/commands/CommandHandle.java
@@ -1,55 +1,54 @@
package com.gmail.inverseconduit.commands;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
import com.gmail.inverseconduit.datatype.ChatMessage;
/**
* Simple handle for a Command. Consists of a {@link Predicate} to match
- * messages (aka. invocations) against, a helpText,
- * an infoText and a {@link Consumer Consumer} for {@link ChatMessage
- * ChatMessages}
+ * messages (aka. invocations) against, a helpText, an infoText and a
+ * {@link Consumer Consumer} for {@link ChatMessage ChatMessages}
*
* @author vogel612<vogel612@gmx.de>
*/
public class CommandHandle {
- private final Predicate matchesSyntax;
+ private final String name;
- private final String name;
+ private final String helpText;
- private final String helpText;
+ private final String infoText;
- private final String infoText;
-
- private final Consumer consumer;
+ private final Function consumer;
/**
* Command Builder for assembling commands. The command builder is not
- * intended
- * to be threadsafe or reusable.
- * After building a command it should be disposed of, or undefined results
- * may
- * occur
+ * intended to be threadsafe or reusable. After building a command it should
+ * be disposed of, or undefined results may occur
*
* @author vogel612<vogel612@gmx.de>
*/
public static class Builder {
- private Predicate matchesSyntax;
+ private String name;
- private String name;
+ private String helpText = "";
- private String helpText = "";
+ private String infoText = "";
- private String infoText = "";
+ private Function consumer;
- private Consumer consumer;
+ @Deprecated
+ @SuppressWarnings("unused")
+ public Builder(String name, Predicate matchesSyntax, Function consumer) {
+ this.name = name;
+ this.consumer = consumer;
+ }
- public Builder(String name, Predicate matchesSyntax, Consumer consumer) {
+ public Builder(String name, Function consumer) {
this.name = name;
- this.matchesSyntax = matchesSyntax;
this.consumer = consumer;
}
@@ -57,8 +56,7 @@ public Builder(String name, Predicate matchesSyntax, Consumer {
- return s.trim().equals(config.getTrigger() + "unsummon");
- }, message -> {
+ return new CommandHandle.Builder("unsummon", message -> {
SeChatDescriptor descriptor = SeChatDescriptor.buildSeChatDescriptorFrom(message);
- chatInterface.sendMessage(descriptor, "*~bye, bye*");
chatInterface.leaveChat(descriptor);
+ return "*~bye, bye*";
}).build();
}
public static CommandHandle summonCommand(ChatInterface chatInterface) {
- return new CommandHandle.Builder("summon", s -> {
- return s.trim().startsWith(config.getTrigger()) && s.trim().matches(".*summon (stack(overflow|exchange)|meta) [0-9]{1,6}");
- }, message -> {
+ return new CommandHandle.Builder("summon", message -> {
Logger.getAnonymousLogger().info("Actually invoking summon command");
- SeChatDescriptor callingRoomDescriptor = SeChatDescriptor.buildSeChatDescriptorFrom(message);
String[] args = message.getMessage().trim().split(" ");
final SESite targetSite;
switch (args[1].toLowerCase()) {
@@ -42,16 +33,14 @@ public static CommandHandle summonCommand(ChatInterface chatInterface) {
targetSite = SESite.META_STACK_EXCHANGE;
break;
default:
- chatInterface.sendMessage(callingRoomDescriptor, "The given site was not one of stackoverflow, stackexchange or meta");
- return;
+ return "The given site was not one of stackoverflow, stackexchange or meta";
}
try {
final int targetRoom = Integer.parseInt(args[2]);
- if ( !chatInterface.joinChat(new SeChatDescriptor.DescriptorBuilder(targetSite).setRoom(() -> targetRoom).build())) {
- chatInterface.sendMessage(callingRoomDescriptor, "Could not join room.");
- }
+ if ( !chatInterface.joinChat(new SeChatDescriptor.DescriptorBuilder(targetSite).setRoom(() -> targetRoom).build())) { return "Could not join room."; }
+ return "Successfully joined room";
} catch(NumberFormatException ex) {
- chatInterface.sendMessage(callingRoomDescriptor, "Could not determine roomnumber.");
+ return "Could not determine roomnumber.";
}
}).build();
}
diff --git a/src/main/java/com/gmail/inverseconduit/commands/sets/CoreBotCommands.java b/src/main/java/com/gmail/inverseconduit/commands/sets/CoreBotCommands.java
new file mode 100644
index 0000000..b17a541
--- /dev/null
+++ b/src/main/java/com/gmail/inverseconduit/commands/sets/CoreBotCommands.java
@@ -0,0 +1,87 @@
+package com.gmail.inverseconduit.commands.sets;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import com.gmail.inverseconduit.AppContext;
+import com.gmail.inverseconduit.BotConfig;
+import com.gmail.inverseconduit.chat.ChatInterface;
+import com.gmail.inverseconduit.commands.CommandHandle;
+import com.gmail.inverseconduit.scripts.ScriptRunner;
+
+public final class CoreBotCommands {
+
+ private static final BotConfig BOT_CONFIG = AppContext.INSTANCE.get(BotConfig.class);
+
+ final Set allCommands = new HashSet<>();
+
+ public CoreBotCommands(ChatInterface chatInterface) {
+ createSummonCommands(chatInterface);
+ createGroovyCommands();
+ createHelpCommand();
+ createAboutCommand();
+ createTestCommand();
+ }
+
+ public Set allCommands() {
+ return Collections.unmodifiableSet(allCommands);
+ }
+
+ private void createSummonCommands(ChatInterface chatInterface) {
+ allCommands.add(ChatCommands.unsummonCommand(chatInterface));
+ allCommands.add(ChatCommands.summonCommand(chatInterface));
+ }
+
+ private void createGroovyCommands() {
+ ScriptRunner runner = new ScriptRunner();
+ allCommands.add(ScriptRunnerCommands.evalCommand(runner));
+ allCommands.add(ScriptRunnerCommands.loadCommand(runner));
+ }
+
+ private void createAboutCommand() {
+ CommandHandle about =
+ new CommandHandle.Builder(
+ "about",
+ message -> {
+ return String.format("@%s I am JavaBot, maintained by Uni, Vogel, and a few others. You can find me on http://github.com/Vincentyification/JavaBot", message.getUsername());
+ }).build();
+ allCommands.add(about);
+ }
+
+ private void createHelpCommand() {
+ CommandHandle help = new CommandHandle.Builder("help", message -> {
+ String[] parts = message.getMessage().split(" ");
+ String commandName = parts[parts.length - 1];
+ Optional helpText = allCommands.stream().filter(c -> c.getName().equals(commandName)).findFirst().map(c -> c.getHelpText());
+ if (helpText.isPresent()) { return helpText.get(); }
+ return "help command: Get additional info about a command of your choice, syntax:" + BOT_CONFIG.getTrigger() + "help [commandName]";
+ }).setHelpText("help command: Get additional info about a command of your choice, syntax:" + BOT_CONFIG.getTrigger() + "help [commandName]").build();
+ allCommands.add(help);
+ }
+
+ // FIXME: Javadoc accessor needs configuration
+ /*
+ * private void bindJavaDocCommand() { CommandHandle javaDoc = new
+ * CommandHandle.Builder("javadoc", message -> { Matcher matcher =
+ * javadocPattern.matcher(message .getMessage()); matcher.find(); return
+ * javaDocAccessor.javadoc(message, matcher.group(1) .trim()); }).build();
+ * allCommands.add(javaDoc); }
+ */
+
+ /*
+ * private void bindShutdownCommand() { CommandHandle shutdown = new
+ * CommandHandle.Builder("shutdown", message -> { // FIXME: Require
+ * permissions for this chatInterface.broadcast("*~going down*"); // FIXME:
+ * needs to be solved differently executor.shutdownNow(); System.exit(0);
+ * return ""; }).build(); allCommands.add(shutdown); }
+ */
+
+ private void createTestCommand() {
+ CommandHandle test = new CommandHandle.Builder("test", message -> {
+ return "*~response*";
+ }).build();
+ allCommands.add(test);
+ }
+}
diff --git a/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunnerCommands.java b/src/main/java/com/gmail/inverseconduit/commands/sets/ScriptRunnerCommands.java
similarity index 59%
rename from src/main/java/com/gmail/inverseconduit/scripts/ScriptRunnerCommands.java
rename to src/main/java/com/gmail/inverseconduit/commands/sets/ScriptRunnerCommands.java
index 80e963c..abac312 100644
--- a/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunnerCommands.java
+++ b/src/main/java/com/gmail/inverseconduit/commands/sets/ScriptRunnerCommands.java
@@ -1,4 +1,4 @@
-package com.gmail.inverseconduit.scripts;
+package com.gmail.inverseconduit.commands.sets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -6,28 +6,30 @@
import com.gmail.inverseconduit.AppContext;
import com.gmail.inverseconduit.BotConfig;
import com.gmail.inverseconduit.commands.CommandHandle;
+import com.gmail.inverseconduit.scripts.ScriptRunner;
public final class ScriptRunnerCommands {
private static final BotConfig config = AppContext.INSTANCE.get(BotConfig.class);
- private static final Pattern evalPattern = Pattern.compile("^" + Pattern.quote(config.getTrigger()) + "eval:(.*)", Pattern.DOTALL);
+ private static final Pattern evalPattern = Pattern.compile("^" + Pattern.quote(config.getTrigger()) + "eval (.*)", Pattern.DOTALL);
- private static final Pattern loadPattern = Pattern.compile("^" + Pattern.quote(config.getTrigger()) + "load:(.*)", Pattern.DOTALL);
+ private static final Pattern loadPattern = Pattern.compile("^" + Pattern.quote(config.getTrigger()) + "load (.*)", Pattern.DOTALL);
public static CommandHandle evalCommand(ScriptRunner scriptRunner) {
- return new CommandHandle.Builder("eval", evalPattern.asPredicate(), message -> {
+ return new CommandHandle.Builder("eval", message -> {
Matcher matcher = evalPattern.matcher(message.getMessage());
matcher.find();
- scriptRunner.evaluateGroovy(message, matcher.group(1));
- }).setHelpText("Evaluates a given groovy script. Syntax: '{trigger}eval:{groovy}'").setInfoText("GroovyScript evalutation").build();
+ return scriptRunner.evaluateGroovy(message, matcher.group(1).trim());
+ }).setHelpText("Evaluates a given groovy script. Syntax: '" + config.getTrigger() + "eval {groovy}'").setInfoText("GroovyScript evaluation").build();
}
public static CommandHandle loadCommand(ScriptRunner scriptRunner) {
- return new CommandHandle.Builder("load", loadPattern.asPredicate(), message -> {
+ return new CommandHandle.Builder("load", message -> {
Matcher matcher = loadPattern.matcher(message.getMessage());
matcher.find();
- scriptRunner.evaluateAndCache(message, matcher.group(1));
+ scriptRunner.evaluateAndCache(matcher.group(1));
+ return "Thanks, I'll remember that";
}).build();
}
}
diff --git a/src/main/java/com/gmail/inverseconduit/javadoc/JavaDocAccessor.java b/src/main/java/com/gmail/inverseconduit/javadoc/JavaDocAccessor.java
index 7429fea..d1e0c62 100644
--- a/src/main/java/com/gmail/inverseconduit/javadoc/JavaDocAccessor.java
+++ b/src/main/java/com/gmail/inverseconduit/javadoc/JavaDocAccessor.java
@@ -4,13 +4,10 @@
import java.nio.file.Files;
import java.nio.file.Path;
-import com.gmail.inverseconduit.chat.ChatInterface;
import com.gmail.inverseconduit.datatype.ChatMessage;
-import com.gmail.inverseconduit.datatype.SeChatDescriptor;
public class JavaDocAccessor {
- private final ChatInterface chatInterface;
private final JavadocDao dao;
@@ -22,9 +19,7 @@ public class JavaDocAccessor {
* @throws IOException
* if there's a problem reading a Javadoc file
*/
- public JavaDocAccessor(ChatInterface chatInterface, Path dir) throws IOException {
- this.chatInterface = chatInterface;
-
+ public JavaDocAccessor(Path dir) throws IOException {
dao = new JavadocDao();
Path java8Api = dir.resolve("java8.zip");
@@ -45,7 +40,7 @@ public JavaDocAccessor(ChatInterface chatInterface, Path dir) throws IOException
}
}
- public void javadoc(ChatMessage chatMessage, String commandText) {
+ public String javadoc(ChatMessage chatMessage, String commandText) {
String response;
try {
response = generateResponse(commandText);
@@ -53,8 +48,7 @@ public void javadoc(ChatMessage chatMessage, String commandText) {
throw new RuntimeException("Problem getting Javadoc info.", e);
}
- response = ":" + chatMessage.getMessageId() + " " + response;
- chatInterface.sendMessage(SeChatDescriptor.buildSeChatDescriptorFrom(chatMessage), response);
+ return ":" + chatMessage.getMessageId() + " " + response;
}
private String generateResponse(String commandText) throws IOException {
diff --git a/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunner.java b/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunner.java
index 2daa390..840ffb1 100644
--- a/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunner.java
+++ b/src/main/java/com/gmail/inverseconduit/scripts/ScriptRunner.java
@@ -7,12 +7,11 @@
import java.util.logging.Logger;
+import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilerConfiguration;
import com.gmail.inverseconduit.ScriptBase;
-import com.gmail.inverseconduit.chat.ChatInterface;
import com.gmail.inverseconduit.datatype.ChatMessage;
-import com.gmail.inverseconduit.datatype.SeChatDescriptor;
/**
* Class to run chat Code. The relevant commands submit code from the chat to
@@ -34,32 +33,36 @@ public class ScriptRunner {
private final GroovyClassLoader groovyLoader;
- private final ChatInterface chatInterface;
-
- public ScriptRunner(ChatInterface chatInterface) {
+ public ScriptRunner() {
// Groovy
groovyConfig = new CompilerConfiguration();
groovyConfig.setScriptBaseClass(ScriptBase.class.getName());
- scriptBinding.setVariable("javaBot", chatInterface);
+ // scriptBinding.setVariable("javaBot", null);
+ //FIXME: we could use JavaBot for this
groovyLoader = new GroovyClassLoader(this.getClass().getClassLoader(), groovyConfig);
groovyShell = new GroovyShell(this.getClass().getClassLoader(), scriptBinding, groovyConfig);
- this.chatInterface = chatInterface;
}
- public void evaluateGroovy(ChatMessage msg, String commandText) {
- LOGGER.finest("Evaluating Groovy Script");
-
- Object result = groovyShell.evaluate(createCodeSource(commandText));
- chatInterface.sendMessage(SeChatDescriptor.buildSeChatDescriptorFrom(msg), result == null
- ? "[tag:groovy]: no result"
- : "[tag:groovy]: " + result.toString());
+ public String evaluateGroovy(ChatMessage msg, String commandText) {
+ LOGGER.info("Evaluating Groovy Script");
+ Object result;
+ try {
+ result = groovyShell.evaluate(createCodeSource(commandText));
+ } catch(CompilationFailedException ex) {
+ result = "compilation failed with error " + ex.getMessage();
+ } catch(Exception ex) {
+ result = "undefined execution error: " + ex.getMessage();
+ }
+ LOGGER.info("Result:" + result);
+ return result == null
+ ? String.format(":%d [tag:groovy]: no result", msg.getMessageId())
+ : String.format(":%d [tag:groovy]: %s", msg.getMessageId(), result.toString());
}
- public void evaluateAndCache(ChatMessage msg, String commandText) {
+ public void evaluateAndCache(String commandText) {
LOGGER.finest("Compiling class to cache it");
groovyLoader.parseClass(createCodeSource(commandText), true);
- chatInterface.sendMessage(SeChatDescriptor.buildSeChatDescriptorFrom(msg), "Thanks, I'll remember that");
}
private GroovyCodeSource createCodeSource(String commandText) {
diff --git a/src/test/java/com/gmail/inverseconduit/utils/PrintUtilTest.java b/src/test/java/com/gmail/inverseconduit/utils/PrintUtilTest.java
index 7747435..5f04756 100644
--- a/src/test/java/com/gmail/inverseconduit/utils/PrintUtilTest.java
+++ b/src/test/java/com/gmail/inverseconduit/utils/PrintUtilTest.java
@@ -5,7 +5,6 @@
import java.util.Arrays;
import java.util.List;
-import org.junit.Ignore;
import org.junit.Test;
public class PrintUtilTest {
@@ -95,8 +94,6 @@ public void sophisticatedLink() {
final List parts = PrintUtils.splitUsefully(testString);
- System.out.println(parts.toString());
-
assertEquals("[a very sophisticated link](https://chat.meta.stackexchange.com/rooms/89 \"with a title text\")", parts.get(1));
assertEquals(5, parts.size());
}