Skip to content

Commit d751fcb

Browse files
committed
MessageReceivers now subscribe to channels by name patterns
1 parent 6f10bce commit d751fcb

File tree

3 files changed

+65
-27
lines changed

3 files changed

+65
-27
lines changed

application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,33 @@
44
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
55
import org.jetbrains.annotations.NotNull;
66

7+
import java.util.regex.Pattern;
8+
79
/**
8-
* Receives incoming Discord guild messages.
10+
* Receives incoming Discord guild messages from channels matching a given pattern.
911
* <p>
1012
* All message receivers have to implement this interface. For convenience, there is a
1113
* {@link MessageReceiverAdapter} available that implemented most methods already. A new receiver
1214
* can then be registered by adding it to {@link Features}.
1315
* <p>
1416
* <p>
1517
* After registration, the system will notify a receiver whenever a new message was sent or an
16-
* existing message was updated in any of the guilds the bot is added to.
18+
* existing message was updated in any channel matching the {@link #getChannelNamePattern()} the bot
19+
* is added to.
1720
*/
1821
public interface MessageReceiver extends Feature {
22+
/**
23+
* Retrieves the pattern matching the names of channels of which this receiver is interested in
24+
* receiving sent messages from. Called by the core system once during the startup in order to
25+
* register the receiver accordingly.
26+
* <p>
27+
* Changes on the pattern returned by this method afterwards will not be picked up.
28+
*
29+
* @return the pattern matching the names of relevant channels
30+
*/
31+
@NotNull
32+
Pattern getChannelNamePattern();
33+
1934
/**
2035
* Triggered by the core system whenever a new message was sent and received in a text channel
2136
* of a guild the bot has been added to.

application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
55
import org.jetbrains.annotations.NotNull;
66

7+
import java.util.regex.Pattern;
8+
79
/**
810
* Adapter implementation of a {@link MessageReceiver}. A new receiver can then be registered by
911
* adding it to {@link Features}.
@@ -14,6 +16,23 @@
1416
*/
1517
public abstract class MessageReceiverAdapter implements MessageReceiver {
1618

19+
private final Pattern channelNamePattern;
20+
21+
/**
22+
* Creates an instance of a message receiver with the given pattern.
23+
*
24+
* @param channelNamePattern the pattern matching names of channels interested in, only messages
25+
* from matching channels will be received
26+
*/
27+
protected MessageReceiverAdapter(@NotNull Pattern channelNamePattern) {
28+
this.channelNamePattern = channelNamePattern;
29+
}
30+
31+
@Override
32+
public final @NotNull Pattern getChannelNamePattern() {
33+
return channelNamePattern;
34+
}
35+
1736
@SuppressWarnings("NoopMethodInAbstractClass")
1837
@Override
1938
public void onMessageReceived(@NotNull GuildMessageReceivedEvent event) {

application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
import net.dv8tion.jda.api.JDA;
44
import net.dv8tion.jda.api.Permission;
5+
import net.dv8tion.jda.api.entities.AbstractChannel;
56
import net.dv8tion.jda.api.entities.Guild;
67
import net.dv8tion.jda.api.entities.TextChannel;
7-
import net.dv8tion.jda.api.events.GenericEvent;
88
import net.dv8tion.jda.api.events.ReadyEvent;
99
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
1010
import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent;
1111
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
1212
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
1313
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
1414
import net.dv8tion.jda.api.exceptions.ErrorHandler;
15-
import net.dv8tion.jda.api.hooks.EventListener;
1615
import net.dv8tion.jda.api.hooks.ListenerAdapter;
1716
import net.dv8tion.jda.api.interactions.commands.Command;
1817
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
@@ -32,7 +31,9 @@
3231
import java.util.concurrent.ExecutorService;
3332
import java.util.concurrent.Executors;
3433
import java.util.function.Function;
34+
import java.util.regex.Pattern;
3535
import java.util.stream.Collectors;
36+
import java.util.stream.Stream;
3637

3738
/**
3839
* The bot core is the core of command handling in this application.
@@ -53,6 +54,7 @@ public final class BotCore extends ListenerAdapter implements SlashCommandProvid
5354
private final Map<String, SlashCommand> nameToSlashCommands;
5455
private final ComponentIdParser componentIdParser;
5556
private final ComponentIdStore componentIdStore;
57+
private final Map<Pattern, MessageReceiver> channelNameToMessageReceiver = new HashMap<>();
5658

5759
/**
5860
* Creates a new command system which uses the given database to allow commands to persist data.
@@ -70,8 +72,8 @@ public BotCore(@NotNull JDA jda, @NotNull Database database) {
7072
features.stream()
7173
.filter(MessageReceiver.class::isInstance)
7274
.map(MessageReceiver.class::cast)
73-
.map(MessageReceiverAsEventListener::new)
74-
.forEach(jda::addEventListener);
75+
.forEach(messageReceiver -> channelNameToMessageReceiver
76+
.put(messageReceiver.getChannelNamePattern(), messageReceiver));
7577

7678
// Event receivers
7779
features.stream()
@@ -129,6 +131,29 @@ public void onReady(@NotNull ReadyEvent event) {
129131
logger.debug("Bot core is now ready");
130132
}
131133

134+
@Override
135+
public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) {
136+
getMessageReceiversSubscribedTo(event.getChannel())
137+
.forEach(messageReceiver -> messageReceiver.onMessageReceived(event));
138+
}
139+
140+
@Override
141+
public void onGuildMessageUpdate(@NotNull GuildMessageUpdateEvent event) {
142+
getMessageReceiversSubscribedTo(event.getChannel())
143+
.forEach(messageReceiver -> messageReceiver.onMessageUpdated(event));
144+
}
145+
146+
private @NotNull Stream<MessageReceiver> getMessageReceiversSubscribedTo(
147+
@NotNull AbstractChannel channel) {
148+
String channelName = channel.getName();
149+
return channelNameToMessageReceiver.entrySet()
150+
.stream()
151+
.filter(patternAndReceiver -> patternAndReceiver.getKey()
152+
.matcher(channelName)
153+
.matches())
154+
.map(Map.Entry::getValue);
155+
}
156+
132157
@Override
133158
public void onSlashCommand(@NotNull SlashCommandEvent event) {
134159
logger.debug("Received slash command '{}' (#{}) on guild '{}'", event.getName(),
@@ -283,25 +308,4 @@ private interface TriConsumer<A, B, C> {
283308
*/
284309
void accept(A first, B second, C third);
285310
}
286-
287-
private static final class MessageReceiverAsEventListener implements EventListener {
288-
private final MessageReceiver messageReceiver;
289-
290-
MessageReceiverAsEventListener(MessageReceiver messageReceiver) {
291-
this.messageReceiver = messageReceiver;
292-
}
293-
294-
@SuppressWarnings("squid:S2583") // False-positive about the if-else-instanceof, sonar
295-
// thinks the second case is unreachable; but it passes
296-
// without pattern-matching. Probably a bug in SonarLint
297-
// with Java 17.
298-
@Override
299-
public void onEvent(@NotNull GenericEvent event) {
300-
if (event instanceof GuildMessageReceivedEvent receivedEvent) {
301-
messageReceiver.onMessageReceived(receivedEvent);
302-
} else if (event instanceof GuildMessageUpdateEvent updateEvent) {
303-
messageReceiver.onMessageUpdated(updateEvent);
304-
}
305-
}
306-
}
307311
}

0 commit comments

Comments
 (0)