Added dynamic flagging system to enable real-time adjustment of behavior.

This commit is contained in:
Logan Fick 2024-02-14 09:16:03 -05:00
parent 85b89b4750
commit 222f6101d4
Signed by: LogalDeveloper
GPG Key ID: 43E58A0C922AB7D1
3 changed files with 172 additions and 8 deletions

View File

@ -39,16 +39,16 @@ public final class MessageCreate implements MessageCreateListener {
*/
@Override
public void onMessageCreate(final MessageCreateEvent event) {
// Is this message being created outside of a server text channel, a server thread channel, or a server voice channel?
// Is this message being created outside a server text channel, a server thread channel, or a server voice channel?
final TextChannel channel = event.getChannel();
if (channel.asServerTextChannel().isEmpty() && channel.asServerThreadChannel().isEmpty() && channel.asServerVoiceChannel().isEmpty()) {
// Yes. Ignore it.
return;
}
// Is the user creating this message another bot, a webhook, or Crabstero itself?
// Is the user creating this message not a regular user or Crabstero itself?
final MessageAuthor author = event.getMessageAuthor();
if (author.isBotUser() || author.isWebhook() || author.isYourself()) {
if (!author.isRegularUser() || author.isYourself()) {
// Yes. Ignore it.
return;
}

View File

@ -0,0 +1,142 @@
/*
* Copyright 2024 Logan Fick
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
package dev.logal.crabstero.utils;
import dev.logal.crabstero.Crabstero;
import org.javacord.api.entity.channel.TextChannel;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;
import redis.clients.jedis.Jedis;
/**
* Provides ability to set and check for flags on text channels, servers, and users.
*/
public class FlagManager {
private final Crabstero crabstero; // The Crabstero instance using this configuration manager.
/**
* Creates a new configuration manager owned by a given instance of Crabstero.
*
* @param crabstero The instance of Crabstero.
*/
public FlagManager(final Crabstero crabstero) {
this.crabstero = crabstero;
}
/**
* Sets a flag of a given name on the given text channel.
*
* @param channel The text channel to set the flag on.
* @param flag The flag to set.
*/
public void setFlag(final TextChannel channel, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.set(channel.getIdAsString() + ":flags:" + flag, "");
}
}
/**
* Sets a flag of a given name on the given server.
*
* @param server The server to set the flag on.
* @param flag The flag to set.
*/
public void setFlag(final Server server, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.set("s" + server.getIdAsString() + ":flags:" + flag, "");
}
}
/**
* Sets a flag of a given name on the given user.
*
* @param user The user to set the flag on.
* @param flag The flag to set.
*/
public void setFlag(final User user, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.set("u" + user.getIdAsString() + ":flags:" + flag, "");
}
}
/**
* Clears the flag of a given name on the given text channel.
*
* @param channel The text channel to clear the flag on.
* @param flag The name of the flag to clear.
*/
public void clearFlag(final TextChannel channel, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.del(channel.getIdAsString() + ":flags:" + flag);
}
}
/**
* Clears the flag of a given name on the given server.
*
* @param server The server to clear the flag on.
* @param flag The name of the flag to clear.
*/
public void clearFlag(final Server server, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.del("s" + server.getIdAsString() + ":flags:" + flag);
}
}
/**
* Clears the flag of a given name on the given user.
*
* @param user The user to clear the flag on.
* @param flag The name of the flag to clear.
*/
public void clearFlag(final User user, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
jedis.del("u" + user.getIdAsString() + ":flags:" + flag);
}
}
/**
* Checks whether a flag of a given name is set on a given text channel.
*
* @param channel The text channel to check on.
* @param flag The name of the flag to check for.
* @return A boolean indicating whether the flag is set.
*/
public boolean isFlagSet(final TextChannel channel, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
return jedis.exists(channel.getIdAsString() + ":flags:" + flag);
}
}
/**
* Checks whether a flag of a given name is set on a given server.
*
* @param server The server to check on.
* @param flag The name of the flag to check for.
* @return A boolean indicating whether the flag is set.
*/
public boolean isFlagSet(final Server server, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
return jedis.exists("s" + server.getIdAsString() + ":flags:" + flag);
}
}
/**
* Checks whether a flag of a given name is set on a given user.
*
* @param user The user to check on.
* @param flag The name of the flag to check for.
* @return A boolean indicating whether the flag is set.
*/
public boolean isFlagSet(final User user, String flag){
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
return jedis.exists("u" + user.getIdAsString() + ":flags:" + flag);
}
}
}

View File

@ -28,12 +28,17 @@ import java.util.Random;
* Assists with generating Discord messages in response to other users and ingesting raw messages.
*/
public class MarkovChainMessages {
private static final String NO_REPLY_FLAG = "noReply";
private static final String NO_INGEST_FLAG = "noIngest";
private final Crabstero crabstero;
private final FlagManager flagManager;
private final AllowedMentions allowedMentions;
private final Random rng = new SecureRandom();
public MarkovChainMessages(final Crabstero crabstero) {
this.crabstero = crabstero;
this.flagManager = new FlagManager(crabstero);
// Set up an allowed mentions filter which blocks any mentions from generating notifications to users.
final AllowedMentionsBuilder builder = new AllowedMentionsBuilder();
@ -57,6 +62,15 @@ public class MarkovChainMessages {
return;
}
// Is a flag set on the text channel or server this message was sent in or the user who sent the message to prevent replying?
// TODO: The blind get()s are safe for now as MessageCreate does the necessary checks, but this could be done better.
if (flagManager.isFlagSet(channel, NO_REPLY_FLAG) ||
flagManager.isFlagSet(message.getServer().get(), NO_REPLY_FLAG) ||
flagManager.isFlagSet(message.getAuthor().asUser().get(), NO_REPLY_FLAG)){
// Yes, don't reply.
return;
}
final long channelID;
// Is this channel a thread?
if (channel.asServerThreadChannel().isPresent()) {
@ -67,7 +81,6 @@ public class MarkovChainMessages {
channelID = channel.getId();
}
final MessageBuilder response = new MessageBuilder();
final MarkovChain markovChain = new MarkovChain(channelID, this.crabstero);
@ -88,7 +101,7 @@ public class MarkovChainMessages {
try (final Jedis jedis = this.crabstero.getJedisPool().getResource()) {
final List<String> embedImageURLs = jedis.lrange(channelID + ":images", 0, -1);
if (embedImageURLs.size() > 0) {
if (!embedImageURLs.isEmpty()) {
embed.setImage(embedImageURLs.get(this.rng.nextInt(embedImageURLs.size())));
}
}
@ -114,12 +127,21 @@ public class MarkovChainMessages {
*/
public void ingestMessage(final Message message) {
final MessageAuthor author = message.getAuthor();
// Is the author of the message a bot, a webhook, or mentioning Crabstero?
if (author.isBotUser() || author.isWebhook() || message.getMentionedUsers().contains(message.getApi().getYourself())) {
// Is the author of the message not a regular user or mentioning Crabstero?
if (!author.isRegularUser() || message.getMentionedUsers().contains(message.getApi().getYourself())) {
// Yes. Ignore it.
return;
}
// Is a flag set on the text channel or server this message was sent in or the user who sent the message to prevent ingestion?
// TODO: The blind get()s are safe for now as MessageCreate does the necessary checks, but this could be done better.
if (flagManager.isFlagSet(message.getChannel(), NO_INGEST_FLAG) ||
flagManager.isFlagSet(message.getServer().get(), NO_INGEST_FLAG) ||
flagManager.isFlagSet(message.getAuthor().asUser().get(), NO_INGEST_FLAG)){
// Yes, don't reply.
return;
}
// Get the Markov chain for the message's text channel.
final long channelID = message.getChannel().getId();
final MarkovChain markovChain = new MarkovChain(channelID, this.crabstero);
@ -139,7 +161,7 @@ public class MarkovChainMessages {
* @param channelID The ID of the channel to use for the Markov Chain.
* @param embed The embed to ingest.
*/
public void ingestEmbed(final long channelID, final Embed embed) {
private void ingestEmbed(final long channelID, final Embed embed) {
// Get the Markov chain for the given channel ID.
final MarkovChain markovChain = new MarkovChain(channelID, this.crabstero);