Skip to content

Add Message and Event receivers #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 27, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.togetherjava.tjbot.commands.Commands;
import org.togetherjava.tjbot.commands.system.CommandSystem;
import org.togetherjava.tjbot.commands.Features;
import org.togetherjava.tjbot.commands.system.BotCore;
import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.db.Database;

Expand All @@ -22,7 +22,7 @@
* New commands can be created by implementing
* {@link net.dv8tion.jda.api.events.interaction.SlashCommandEvent} or extending
* {@link org.togetherjava.tjbot.commands.SlashCommandAdapter}. They can then be registered in
* {@link Commands}.
* {@link Features}.
*/
public enum Application {
;
Expand Down Expand Up @@ -79,7 +79,7 @@ public static void runBot(String token, Path databasePath) {
JDA jda = JDABuilder.createDefault(token)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.build();
jda.addEventListener(new CommandSystem(jda, database));
jda.addEventListener(new BotCore(jda, database));
jda.awaitReady();
logger.info("Bot is ready");

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.togetherjava.tjbot.commands;

import net.dv8tion.jda.api.hooks.EventListener;

/**
* Receives all incoming Discord events, unfiltered. A list of all available event types can be
* found in {@link net.dv8tion.jda.api.hooks.ListenerAdapter}.
*
* If possible, prefer one of the more concrete features instead, such as {@link SlashCommand} or
* {@link MessageReceiver}. Take care to not accidentally implement both, this and one of the other
* {@link Feature}s, as this might result in events being received multiple times.
* <p>
* All event receivers have to implement this interface. A new receiver can then be registered by
* adding it to {@link Features}.
* <p>
* <p>
* After registration, the system will notify a receiver for any incoming Discord event.
*/
@FunctionalInterface
public interface EventReceiver extends EventListener, Feature {
// Basically a renaming of JDAs EventListener, plus our Feature marker interface
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.togetherjava.tjbot.commands;

/**
* Interface for features supported by the bots core system.
* <p>
* New features are added in {@link org.togetherjava.tjbot.commands.Features} and from there picked
* up by {@link org.togetherjava.tjbot.commands.system.BotCore}.
*/
public interface Feature {
// Marker interface
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.togetherjava.tjbot.commands;

import net.dv8tion.jda.api.JDA;
import org.jetbrains.annotations.NotNull;
import org.togetherjava.tjbot.commands.basic.PingCommand;
import org.togetherjava.tjbot.commands.basic.VcActivityCommand;
import org.togetherjava.tjbot.commands.free.FreeCommand;
import org.togetherjava.tjbot.commands.mathcommands.TeXCommand;
import org.togetherjava.tjbot.commands.moderation.*;
import org.togetherjava.tjbot.commands.moderation.temp.TemporaryModerationRoutine;
import org.togetherjava.tjbot.commands.system.BotCore;
import org.togetherjava.tjbot.commands.tags.TagCommand;
import org.togetherjava.tjbot.commands.tags.TagManageCommand;
import org.togetherjava.tjbot.commands.tags.TagSystem;
import org.togetherjava.tjbot.commands.tags.TagsCommand;
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.routines.ModAuditLogRoutine;

import java.util.ArrayList;
import java.util.Collection;

/**
* Utility class that offers all features that should be registered by the system, such as commands.
* New features have to be added here, where {@link BotCore} will then pick it up from and register
* it with the system.
* <p>
* To add a new slash command, extend the commands returned by
* {@link #createFeatures(JDA, Database)}.
*/
public enum Features {
;

/**
* Creates all features that should be registered with this application.
* <p>
* Calling this method multiple times will result in multiple features being created, which
* generally should be avoided.
*
* @param jda the JDA instance commands will be registered at
* @param database the database of the application, which features can use to persist data
* @return a collection of all features
*/
public static @NotNull Collection<Feature> createFeatures(@NotNull JDA jda,
@NotNull Database database) {
TagSystem tagSystem = new TagSystem(database);
ModerationActionsStore actionsStore = new ModerationActionsStore(database);

// NOTE The system can add special system relevant commands also by itself,
// hence this list may not necessarily represent the full list of all commands actually
// available.
Collection<Feature> features = new ArrayList<>();

// Routines
// TODO This should be moved into some proper command system instead (see GH issue #235
// which adds support for routines)
new ModAuditLogRoutine(jda, database).start();
new TemporaryModerationRoutine(jda, actionsStore).start();

// Message receivers

// Event receivers
features.add(new RejoinMuteListener(actionsStore));

// Slash commands
features.add(new PingCommand());
features.add(new TeXCommand());
features.add(new TagCommand(tagSystem));
features.add(new TagManageCommand(tagSystem));
features.add(new TagsCommand(tagSystem));
features.add(new VcActivityCommand());
features.add(new WarnCommand(actionsStore));
features.add(new KickCommand(actionsStore));
features.add(new BanCommand(actionsStore));
features.add(new UnbanCommand(actionsStore));
features.add(new AuditCommand(actionsStore));
features.add(new MuteCommand(actionsStore));
features.add(new UnmuteCommand(actionsStore));

// Mixtures
features.add(new FreeCommand());

return features;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.togetherjava.tjbot.commands;

import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
import org.jetbrains.annotations.NotNull;

import java.util.regex.Pattern;

/**
* Receives incoming Discord guild messages from channels matching a given pattern.
* <p>
* All message receivers have to implement this interface. For convenience, there is a
* {@link MessageReceiverAdapter} available that implemented most methods already. A new receiver
* can then be registered by adding it to {@link Features}.
* <p>
* <p>
* After registration, the system will notify a receiver whenever a new message was sent or an
* existing message was updated in any channel matching the {@link #getChannelNamePattern()} the bot
* is added to.
*/
public interface MessageReceiver extends Feature {
/**
* Retrieves the pattern matching the names of channels of which this receiver is interested in
* receiving sent messages from. Called by the core system once during the startup in order to
* register the receiver accordingly.
* <p>
* Changes on the pattern returned by this method afterwards will not be picked up.
*
* @return the pattern matching the names of relevant channels
*/
@NotNull
Pattern getChannelNamePattern();

/**
* Triggered by the core system whenever a new message was sent and received in a text channel
* of a guild the bot has been added to.
*
* @param event the event that triggered this, containing information about the corresponding
* message that was sent and received
*/
void onMessageReceived(@NotNull GuildMessageReceivedEvent event);

/**
* Triggered by the core system whenever an existing message was edited in a text channel of a
* guild the bot has been added to.
*
* @param event the event that triggered this, containing information about the corresponding
* message that was edited
*/
void onMessageUpdated(@NotNull GuildMessageUpdateEvent event);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.togetherjava.tjbot.commands;

import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
import org.jetbrains.annotations.NotNull;

import java.util.regex.Pattern;

/**
* Adapter implementation of a {@link MessageReceiver}. A new receiver can then be registered by
* adding it to {@link Features}.
* <p>
* {@link #onMessageReceived(GuildMessageReceivedEvent)} and
* {@link #onMessageUpdated(GuildMessageUpdateEvent)} can be overridden if desired. The default
* implementation is empty, the adapter will not react to such events.
*/
public abstract class MessageReceiverAdapter implements MessageReceiver {

private final Pattern channelNamePattern;

/**
* Creates an instance of a message receiver with the given pattern.
*
* @param channelNamePattern the pattern matching names of channels interested in, only messages
* from matching channels will be received
*/
protected MessageReceiverAdapter(@NotNull Pattern channelNamePattern) {
this.channelNamePattern = channelNamePattern;
}

@Override
public final @NotNull Pattern getChannelNamePattern() {
return channelNamePattern;
}

@SuppressWarnings("NoopMethodInAbstractClass")
@Override
public void onMessageReceived(@NotNull GuildMessageReceivedEvent event) {
// Adapter does not react by default, subclasses may change this behavior
}

@SuppressWarnings("NoopMethodInAbstractClass")
@Override
public void onMessageUpdated(@NotNull GuildMessageUpdateEvent event) {
// Adapter does not react by default, subclasses may change this behavior
}
}
Loading