FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Added migration to add timeout to help channel db data, and added fra… · Java-Discord/JavaBot@8299f01 · GitHub

Commit 8299f01

Browse files
committed
Added migration to add timeout to help channel db data, and added framework for semantic analysis of help channel content.
1 parent a92dbcd commit 8299f01

13 files changed

Lines changed: 325 additions & 40 deletions

File tree

‎src/main/java/com/javadiscord/javabot/data/h2db/DbActions.java‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,32 @@ public class DbActions {
1515
// Hide the constructor.
1616
private DbActions () {}
1717

18+
public static void doAction(ConnectionConsumer consumer) throws SQLException {
19+
try (var c = Bot.dataSource.getConnection()) {
20+
consumer.consume(c);
21+
}
22+
}
23+
24+
public static <T> T map(ConnectionFunction<T> function) throws SQLException {
25+
try (var c = Bot.dataSource.getConnection()) {
26+
return function.apply(c);
27+
}
28+
}
29+
30+
public static <T> T mapQuery(String query, StatementModifier modifier, ResultSetMapper<T> mapper) throws SQLException {
31+
try (var c = Bot.dataSource.getConnection(); var stmt = c.prepareStatement(query)) {
32+
modifier.modify(stmt);
33+
var rs = stmt.executeQuery();
34+
return mapper.map(rs);
35+
}
36+
}
37+
1838
/**
1939
* Does an asynchronous database action using the bot's async pool.
2040
* @param consumer The consumer that will use a connection.
2141
* @return A future that completes when the action is complete.
2242
*/
23-
public static CompletableFuture<Void> doAction(ConnectionConsumer consumer) {
43+
public static CompletableFuture<Void> doAsyncAction(ConnectionConsumer consumer) {
2444
CompletableFuture<Void> future = new CompletableFuture<>();
2545
Bot.asyncPool.submit(() -> {
2646
try (var c = Bot.dataSource.getConnection()) {
@@ -42,7 +62,7 @@ public static CompletableFuture<Void> doAction(ConnectionConsumer consumer) {
4262
* @param <T> The type of data access object. Usually some kind of repository.
4363
* @return A future that completes when the action is complete.
4464
*/
45-
public static <T> CompletableFuture<Void> doDaoAction(Function<Connection, T> daoConstructor, DaoConsumer<T> consumer) {
65+
public static <T> CompletableFuture<Void> doAsyncDaoAction(Function<Connection, T> daoConstructor, DaoConsumer<T> consumer) {
4666
CompletableFuture<Void> future = new CompletableFuture<>();
4767
Bot.asyncPool.submit(() -> {
4868
try (var c = Bot.dataSource.getConnection()) {
@@ -56,7 +76,7 @@ public static <T> CompletableFuture<Void> doDaoAction(Function<Connection, T> da
5676
return future;
5777
}
5878

59-
public static <T> CompletableFuture<T> doAction(ConnectionFunction<T> function) {
79+
public static <T> CompletableFuture<T> mapAsync(ConnectionFunction<T> function) {
6080
CompletableFuture<T> future = new CompletableFuture<>();
6181
Bot.asyncPool.submit(() -> {
6282
try (var c = Bot.dataSource.getConnection()) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.javadiscord.javabot.data.h2db;
2+
3+
import java.sql.ResultSet;
4+
import java.sql.SQLException;
5+
6+
@FunctionalInterface
7+
public interface ResultSetMapper<T> {
8+
T map(ResultSet rs) throws SQLException;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.javadiscord.javabot.data.h2db;
2+
3+
import java.sql.PreparedStatement;
4+
import java.sql.SQLException;
5+
6+
@FunctionalInterface
7+
public interface StatementModifier {
8+
void modify(PreparedStatement s) throws SQLException;
9+
}

‎src/main/java/com/javadiscord/javabot/data/properties/config/guild/HelpConfig.java‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import net.dv8tion.jda.api.entities.Category;
88
import net.dv8tion.jda.api.entities.Role;
99

10+
import java.util.List;
11+
1012
/**
1113
* Configuration for the guild's help system.
1214
*/
@@ -71,15 +73,22 @@ public class HelpConfig extends GuildConfigItem {
7173
*/
7274
private int preferredOpenChannelCount = 3;
7375

76+
/**
77+
* A list of successive timeouts (in minutes) to use when checking to see if
78+
* a help channel is still active. The bot waits X minutes since the last
79+
* human message before sending an activity check, and waits
80+
*/
81+
private List<Integer> inactivityTimeouts = List.of(30, 60, 120, 180);
82+
7483
/**
7584
* The number of minutes of inactivity before a channel is considered inactive.
7685
*/
7786
private int inactivityTimeoutMinutes = 30;
7887

7988
/**
80-
* The number of minutes of inactivity before a previously inactive channel
81-
* is removed. This is measured from the time at which the bot determined
82-
* the channel to be inactive.
89+
* The number of minutes to wait before closing an inactive channel. An
90+
* inactive channel is one in which the most recent message is an unanswered
91+
* activity check that was sent by this bot.
8392
*/
8493
private int removeTimeoutMinutes = 60;
8594

‎src/main/java/com/javadiscord/javabot/events/InteractionListener.java‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.javadiscord.javabot.events;
22

33
import com.javadiscord.javabot.Bot;
4+
import com.javadiscord.javabot.commands.Responses;
45
import com.javadiscord.javabot.commands.staff_commands.Ban;
56
import com.javadiscord.javabot.commands.staff_commands.Kick;
67
import com.javadiscord.javabot.commands.staff_commands.Unban;
@@ -12,6 +13,8 @@
1213
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
1314
import net.dv8tion.jda.api.hooks.ListenerAdapter;
1415

16+
import java.sql.SQLException;
17+
1518
@Slf4j
1619
public class InteractionListener extends ListenerAdapter {
1720

@@ -109,10 +112,16 @@ private void handleHelpChannel(ButtonClickEvent event, String action) {
109112
} else if (action.equals("not-done")) {
110113
log.info("Removing timeout check message in {} because it was marked as not-done.", channel.getAsMention());
111114
event.getMessage().delete().queue();
112-
channel.sendMessage(String.format(
113-
"Okay, we'll keep this channel reserved for you, and check again in **%d** minutes.",
114-
config.getInactivityTimeoutMinutes()
115-
)).queue();
115+
try {
116+
int nextTimeout = channelManager.getNextTimeout(channel);
117+
channelManager.setTimeout(channel, nextTimeout);
118+
channel.sendMessage(String.format(
119+
"Okay, we'll keep this channel reserved for you, and check again in **%d** minutes.",
120+
nextTimeout
121+
)).queue();
122+
} catch (SQLException e) {
123+
Responses.error(event.getHook(), "An error occurred while managing this help channel.").queue();
124+
}
116125
}
117126
}
118127
}

‎src/main/java/com/javadiscord/javabot/service/Startup.java‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.javadiscord.javabot.data.mongodb.Database;
99
import com.javadiscord.javabot.events.StarboardListener;
1010
import com.javadiscord.javabot.service.help.HelpChannelUpdater;
11+
import com.javadiscord.javabot.service.help.checks.SimpleGreetingCheck;
1112
import com.javadiscord.javabot.utils.Misc;
1213
import com.mongodb.MongoClient;
1314
import com.mongodb.MongoClientURI;
@@ -19,6 +20,7 @@
1920
import org.slf4j.LoggerFactory;
2021

2122
import java.util.Arrays;
23+
import java.util.List;
2224
import java.util.concurrent.TimeUnit;
2325

2426
@Slf4j
@@ -82,7 +84,14 @@ public void onReady(ReadyEvent event) {
8284

8385
// Schedule the help channel updater to run periodically for each guild.
8486
var helpConfig = Bot.config.get(guild).getHelp();
85-
Bot.asyncPool.scheduleAtFixedRate(new HelpChannelUpdater(event.getJDA(), helpConfig), 5, helpConfig.getUpdateIntervalSeconds(), TimeUnit.SECONDS);
87+
Bot.asyncPool.scheduleAtFixedRate(
88+
new HelpChannelUpdater(event.getJDA(), helpConfig, List.of(
89+
new SimpleGreetingCheck()
90+
)),
91+
5,
92+
helpConfig.getUpdateIntervalSeconds(),
93+
TimeUnit.SECONDS
94+
);
8695
}
8796

8897
} catch (MongoException e) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.javadiscord.javabot.service.help;
2+
3+
import net.dv8tion.jda.api.entities.Message;
4+
import net.dv8tion.jda.api.entities.TextChannel;
5+
import net.dv8tion.jda.api.entities.User;
6+
import net.dv8tion.jda.api.requests.RestAction;
7+
8+
import java.util.List;
9+
10+
/**
11+
* Defines an analysis that can be performed on a list of messages and semantic
12+
* data obtained from a reserved help channel, possibly in order to provide
13+
* contextual help or guidance to the owner of the channel.
14+
*/
15+
public interface ChannelSemanticCheck {
16+
/**
17+
* Performs a check on the given data.
18+
* @param channel The reserved help channel.
19+
* @param owner The user who reserved the help channel.
20+
* @param messages The list of messages sent in the channel since the user
21+
* reserved it, ordered from newest to oldest.
22+
* @param semanticData Extra semantic data that may be useful in determining
23+
* when to do things.
24+
* @return A rest action that completes when this check is done.
25+
*/
26+
RestAction<?> doCheck(TextChannel channel, User owner, List<Message> messages, ChannelSemanticData semanticData);
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.javadiscord.javabot.service.help;
2+
3+
import net.dv8tion.jda.api.entities.Message;
4+
import net.dv8tion.jda.api.entities.User;
5+
6+
import javax.annotation.Nullable;
7+
import java.time.Duration;
8+
import java.util.List;
9+
10+
public record ChannelSemanticData(
11+
@Nullable Message initialMessage,
12+
Duration timeSinceFirstMessage,
13+
List<User> nonOwnerParticipants,
14+
List<Message> botMessages
15+
) {
16+
public boolean containsBotMessageContent(String content) {
17+
return botMessages.stream()
18+
.anyMatch(m -> m.getContentRaw().contains(content));
19+
}
20+
}

‎src/main/java/com/javadiscord/javabot/service/help/HelpChannelManager.java‎

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.javadiscord.javabot.service.help;
22

33
import com.javadiscord.javabot.Bot;
4+
import com.javadiscord.javabot.data.h2db.DbActions;
45
import com.javadiscord.javabot.data.properties.config.guild.HelpConfig;
56
import lombok.extern.slf4j.Slf4j;
67
import net.dv8tion.jda.api.entities.Message;
@@ -10,6 +11,7 @@
1011
import net.dv8tion.jda.api.requests.RestAction;
1112

1213
import java.sql.SQLException;
14+
import java.time.LocalDateTime;
1315

1416
/**
1517
* This manager is responsible for all the main interactions that affect the
@@ -81,9 +83,11 @@ public void openNew() {
8183
*/
8284
public void reserve(TextChannel channel, User reservingUser, Message message) throws SQLException {
8385
try (var con = Bot.dataSource.getConnection();
84-
var stmt = con.prepareStatement("INSERT INTO reserved_help_channels (channel_id, user_id) VALUES (?, ?)")) {
86+
var stmt = con.prepareStatement("INSERT INTO reserved_help_channels (channel_id, user_id, timeout) VALUES (?, ?, ?)")) {
8587
stmt.setLong(1, channel.getIdLong());
8688
stmt.setLong(2, reservingUser.getIdLong());
89+
int timeout = config.getInactivityTimeouts().get(0);
90+
stmt.setInt(3, timeout);
8791
stmt.executeUpdate();
8892
}
8993
var target = config.getReservedChannelCategory();
@@ -162,4 +166,55 @@ public RestAction<?> unreserveChannel(TextChannel channel) {
162166
return channel.delete();
163167
}
164168
}
169+
170+
public void setTimeout(TextChannel channel, int timeout) throws SQLException {
171+
try (var con = Bot.dataSource.getConnection();
172+
var stmt = con.prepareStatement("UPDATE reserved_help_channels SET timeout = ? WHERE channel_id = ?")
173+
) {
174+
stmt.setInt(1, timeout);
175+
stmt.setLong(2, channel.getIdLong());
176+
stmt.executeUpdate();
177+
}
178+
}
179+
180+
public int getTimeout(TextChannel channel) throws SQLException {
181+
try (var con = Bot.dataSource.getConnection();
182+
var stmt = con.prepareStatement("SELECT timeout FROM reserved_help_channels WHERE channel_id = ?")
183+
) {
184+
stmt.setLong(1, channel.getIdLong());
185+
var rs = stmt.executeQuery();
186+
if (rs.next()) {
187+
return rs.getInt(1);
188+
} else {
189+
throw new SQLException("Could not get timeout for channel_id " + channel.getId());
190+
}
191+
}
192+
}
193+
194+
public LocalDateTime getReservedAt(TextChannel channel) throws SQLException {
195+
return DbActions.mapQuery(
196+
"SELECT reserved_at FROM reserved_help_channels WHERE channel_id = ?",
197+
s -> s.setLong(1, channel.getIdLong()),
198+
rs -> {
199+
if (!rs.next()) throw new SQLException("No data!");
200+
return rs.getTimestamp(1).toLocalDateTime();
201+
}
202+
);
203+
}
204+
205+
public int getNextTimeout(TextChannel channel) throws SQLException {
206+
if (config.getInactivityTimeouts().isEmpty()) {
207+
log.warn("No help channel inactivity timeouts have been configured!");
208+
return 60;
209+
}
210+
int currentTimeout = getTimeout(channel);
211+
int maxTimeout = config.getInactivityTimeouts().get(0);
212+
for (var t : config.getInactivityTimeouts()) {
213+
if (t > currentTimeout) {
214+
return t;
215+
}
216+
if (t > maxTimeout) maxTimeout = t;
217+
}
218+
return maxTimeout;
219+
}
165220
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL