cache = new ConcurrentLinkedDeque<>();
/**
* Amount of messages since the last synchronization.
*
@@ -95,8 +96,10 @@ public void synchronize() {
* Synchronizes Messages saved in the Database with what is currently stored in memory and wait until the synchronization finishes.
*/
public void synchronizeNow() {
- cacheRepository.delete(cache.size());
- cacheRepository.insertList(new ArrayList<>(cache));
+ if (messageCount == 0) {
+ return;
+ }
+ cacheRepository.replaceWithList(new ArrayList<>(cache));
messageCount = 0;
log.info("Synchronized Database with local Cache.");
}
diff --git a/src/main/java/net/discordjug/javabot/data/h2db/message_cache/dao/MessageCacheRepository.java b/src/main/java/net/discordjug/javabot/data/h2db/message_cache/dao/MessageCacheRepository.java
index e86f1408e..8af5c7bd3 100644
--- a/src/main/java/net/discordjug/javabot/data/h2db/message_cache/dao/MessageCacheRepository.java
+++ b/src/main/java/net/discordjug/javabot/data/h2db/message_cache/dao/MessageCacheRepository.java
@@ -8,6 +8,7 @@
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
+import org.springframework.transaction.support.TransactionTemplate;
import java.sql.*;
import java.util.ArrayList;
@@ -23,14 +24,27 @@
@Repository
public class MessageCacheRepository {
private final JdbcTemplate jdbcTemplate;
-
+ private final TransactionTemplate template;
+
/**
- * Inserts a {@link List} of {@link CachedMessage} objects.
+ * Replaces the entire message cache with a {@link List} of {@link CachedMessage} objects.
*
- * @param messages The List to insert.
- * @throws SQLException If an error occurs.
+ * @param messages The new message cache.
*/
- public void insertList(@NotNull List messages) throws DataAccessException {
+ public void replaceWithList(@NotNull List messages) {
+ template.execute(_ -> {
+ clear();
+ insertList(messages);
+ return null;
+ });
+ }
+
+ private void clear() throws DataAccessException {
+ jdbcTemplate.update("DELETE FROM message_cache_attachments WHERE 1 = 1");
+ jdbcTemplate.update("DELETE FROM message_cache WHERE 1 = 1");
+ }
+
+ private void insertList(@NotNull List messages) throws DataAccessException {
jdbcTemplate.batchUpdate("MERGE INTO message_cache (message_id, author_id, message_content) VALUES (?, ?, ?)",
new BatchPreparedStatementSetter() {
@Override
@@ -77,11 +91,10 @@ public int getBatchSize() {
* Gets all Messages from the Database.
*
* @return A {@link List} of {@link CachedMessage}s.
- * @throws SQLException If anything goes wrong.
*/
public List getAll() throws DataAccessException {
List messagesWithLink = jdbcTemplate.query(
- "SELECT * FROM message_cache LEFT JOIN message_cache_attachments ON message_cache.message_id = message_cache_attachments.message_id",
+ "SELECT * FROM message_cache LEFT JOIN message_cache_attachments ON message_cache.message_id = message_cache_attachments.message_id ORDER BY message_cache.message_id ASC",
(rs, _) -> this.read(rs));
Map messages=new LinkedHashMap<>();
for (CachedMessage msg : messagesWithLink) {
@@ -94,22 +107,6 @@ public List getAll() throws DataAccessException {
return new ArrayList<>(messages.values());
}
- /**
- * Deletes the given amount of Messages.
- *
- * @param amount The amount to delete.
- * @return If any rows we're affected.
- * @throws SQLException If anything goes wrong.
- */
- public boolean delete(int amount) throws DataAccessException {
- int rows = jdbcTemplate.update("DELETE FROM message_cache LIMIT ?", amount);
- if(rows > 0){
- jdbcTemplate.update("DELETE FROM message_cache_attachments WHERE message_id NOT IN (SELECT message_id FROM message_cache)");
- return true;
- }
- return false;
- }
-
private CachedMessage read(ResultSet rs) throws SQLException {
List attachments = new ArrayList<>();
String attachment = rs.getString("link");
diff --git a/src/main/java/net/discordjug/javabot/listener/filter/MessageFilterHandler.java b/src/main/java/net/discordjug/javabot/listener/filter/MessageFilterHandler.java
index 94205eb37..528ab7fd6 100644
--- a/src/main/java/net/discordjug/javabot/listener/filter/MessageFilterHandler.java
+++ b/src/main/java/net/discordjug/javabot/listener/filter/MessageFilterHandler.java
@@ -13,6 +13,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* This class is responsible for calling {@link MessageFilter}s on incoming messages and optionally replacing the message.
@@ -28,6 +29,7 @@ public class MessageFilterHandler extends ListenerAdapter {
private final List filters;
private final AutoMod autoMod;
+ private final Executor asyncPool;
@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
@@ -42,36 +44,39 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
new ArrayList<>(event.getMessage().getEmbeds())
);
- boolean handled = false;
- for (MessageFilter filter : filters) {
- MessageModificationStatus status = filter.processMessage(content);
- if (status == MessageModificationStatus.MODIFIED) {
- handled = true;
- } else if (status == MessageModificationStatus.STOP_PROCESSING) {
- return;
- }
- }
+ asyncPool.execute(() -> {
+ boolean handled = false;
- if (handled) {
- IWebhookContainer webhookContainer = null;
- long threadId = 0;
- if (event.isFromType(ChannelType.TEXT)) {
- webhookContainer = event.getChannel().asTextChannel();
+ for (MessageFilter filter : filters) {
+ MessageModificationStatus status = filter.processMessage(content);
+ if (status == MessageModificationStatus.MODIFIED) {
+ handled = true;
+ } else if (status == MessageModificationStatus.STOP_PROCESSING) {
+ return;
+ }
}
- if (event.isFromThread()) {
- StandardGuildChannel parentChannel = event.getChannel()
- .asThreadChannel()
- .getParentChannel()
- .asStandardGuildChannel();
- threadId = event.getChannel().getIdLong();
- webhookContainer = (IWebhookContainer) parentChannel;
+
+ if (handled) {
+ IWebhookContainer webhookContainer = null;
+ long threadId = 0;
+ if (event.isFromType(ChannelType.TEXT)) {
+ webhookContainer = event.getChannel().asTextChannel();
+ }
+ if (event.isFromThread()) {
+ StandardGuildChannel parentChannel = event.getChannel()
+ .asThreadChannel()
+ .getParentChannel()
+ .asStandardGuildChannel();
+ threadId = event.getChannel().getIdLong();
+ webhookContainer = (IWebhookContainer) parentChannel;
+ }
+ if (webhookContainer == null) {
+ return;
+ }
+ replaceMessage(webhookContainer, threadId, content);
}
- if (webhookContainer == null) {
- return;
- }
- replaceMessage(webhookContainer, threadId, content);
- }
+ });
}
private boolean shouldRunFilters(@NotNull MessageReceivedEvent event) {
diff --git a/src/main/java/net/discordjug/javabot/listener/filter/MessageRuleFilter.java b/src/main/java/net/discordjug/javabot/listener/filter/MessageRuleFilter.java
index 4ae9a6c7e..beda91832 100644
--- a/src/main/java/net/discordjug/javabot/listener/filter/MessageRuleFilter.java
+++ b/src/main/java/net/discordjug/javabot/listener/filter/MessageRuleFilter.java
@@ -9,6 +9,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;
@@ -25,6 +26,8 @@
import net.discordjug.javabot.util.GsonUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message.Attachment;
+import net.dv8tion.jda.api.utils.TimeUtil;
+import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.stereotype.Component;
@@ -103,7 +106,28 @@ private boolean matches(MessageContent content, MessageRule rule) {
}
}
}
- return matchesSHA;
+ if (!matchesSHA) {
+ return false;
+ }
+ if (rule.getNoMessagesFromAuthorBeforeSeconds() > 0) {
+ OffsetDateTime maxTime = content.event().getMessage().getTimeCreated()
+ .minusSeconds(rule.getNoMessagesFromAuthorBeforeSeconds());
+ long authorId = content.event().getAuthor().getIdLong();
+ return !hasMessagesOlderThan(maxTime, content.event().getGuild(), authorId);
+ }
+ return true;
+ }
+
+ private boolean hasMessagesOlderThan(OffsetDateTime maxTime, Guild guild, long authorId) {
+ if (messageCache.cache.stream()
+ .filter(msg -> TimeUtil.getTimeCreated(msg.getMessageId()).isBefore(maxTime))
+ .anyMatch(msg -> msg.getAuthorId() == authorId)) {
+ return true;
+ }
+ return guild.searchMessages()
+ .authors(authorId)
+ .maxId(TimeUtil.getDiscordTimestamp(maxTime.toInstant().toEpochMilli()))
+ .complete().asResults().getTotalResults() > 0;
}
private String computeAttachmentDescription(List attachments) {