Skip to content

Commit ba52734

Browse files
committed
Integrated existing routines
1 parent ed0b1f3 commit ba52734

File tree

3 files changed

+34
-51
lines changed

3 files changed

+34
-51
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ public enum Features {
5151
Collection<Feature> features = new ArrayList<>();
5252

5353
// Routines
54-
// TODO This should be moved into some proper command system instead (see GH issue #235
55-
// which adds support for routines)
56-
new ModAuditLogRoutine(jda, database).start();
57-
new TemporaryModerationRoutine(jda, actionsStore).start();
54+
features.add(new ModAuditLogRoutine(database));
55+
features.add(new TemporaryModerationRoutine(jda, actionsStore));
5856

5957
// Message receivers
6058

application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryModerationRoutine.java

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.jetbrains.annotations.NotNull;
88
import org.slf4j.Logger;
99
import org.slf4j.LoggerFactory;
10+
import org.togetherjava.tjbot.commands.Routine;
1011
import org.togetherjava.tjbot.commands.moderation.ActionRecord;
1112
import org.togetherjava.tjbot.commands.moderation.ModerationAction;
1213
import org.togetherjava.tjbot.commands.moderation.ModerationActionsStore;
@@ -15,8 +16,6 @@
1516
import java.util.Map;
1617
import java.util.Objects;
1718
import java.util.Optional;
18-
import java.util.concurrent.Executors;
19-
import java.util.concurrent.ScheduledExecutorService;
2019
import java.util.concurrent.TimeUnit;
2120
import java.util.function.Function;
2221
import java.util.stream.Collectors;
@@ -26,19 +25,15 @@
2625
* Routine that revokes temporary moderation actions, such as temporary bans, as listed by
2726
* {@link ModerationActionsStore}.
2827
* <p>
29-
* The routine is started by using {@link #start()} and then automatically executes on a schedule.
30-
* <p>
3128
* Revoked actions are compatible with {@link ModerationActionsStore} and commands such as
3229
* {@link org.togetherjava.tjbot.commands.moderation.UnbanCommand} and
3330
* {@link org.togetherjava.tjbot.commands.moderation.AuditCommand}.
3431
*/
35-
public final class TemporaryModerationRoutine {
32+
public final class TemporaryModerationRoutine implements Routine {
3633
private static final Logger logger = LoggerFactory.getLogger(TemporaryModerationRoutine.class);
3734

3835
private final ModerationActionsStore actionsStore;
3936
private final JDA jda;
40-
private final ScheduledExecutorService checkExpiredActionsService =
41-
Executors.newSingleThreadScheduledExecutor();
4237
private final Map<ModerationAction, RevocableModerationAction> typeToRevocableAction;
4338

4439
/**
@@ -57,6 +52,16 @@ public TemporaryModerationRoutine(@NotNull JDA jda,
5752
Collectors.toMap(RevocableModerationAction::getApplyType, Function.identity()));
5853
}
5954

55+
@Override
56+
public void run(@NotNull JDA jda) {
57+
checkExpiredActions();
58+
}
59+
60+
@Override
61+
public @NotNull Schedule createSchedule() {
62+
return new Schedule(ScheduleMode.FIXED_DELAY, 5, 5, TimeUnit.MINUTES);
63+
}
64+
6065
private void checkExpiredActions() {
6166
logger.debug("Checking expired temporary moderation actions to revoke...");
6267

@@ -146,19 +151,6 @@ private void handleFailure(@NotNull Throwable failure,
146151
"Action type is not revocable: " + type);
147152
}
148153

149-
/**
150-
* Starts the routine, automatically checking expired temporary moderation actions on a
151-
* schedule.
152-
*/
153-
public void start() {
154-
// TODO This should be registered at some sort of routine system instead (see GH issue #235
155-
// which adds support for routines)
156-
// TODO The initial run has to be delayed until after the guild cache has been updated
157-
// (during CommandSystem startup)
158-
checkExpiredActionsService.scheduleWithFixedDelay(this::checkExpiredActions, 5, 5,
159-
TimeUnit.MINUTES);
160-
}
161-
162154
private record RevocationGroupIdentifier(long guildId, long targetId,
163155
@NotNull ModerationAction type) {
164156
static RevocationGroupIdentifier of(@NotNull ActionRecord actionRecord) {

application/src/main/java/org/togetherjava/tjbot/routines/ModAuditLogRoutine.java

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.jetbrains.annotations.Nullable;
1616
import org.slf4j.Logger;
1717
import org.slf4j.LoggerFactory;
18+
import org.togetherjava.tjbot.commands.Routine;
1819
import org.togetherjava.tjbot.commands.moderation.ModerationUtils;
1920
import org.togetherjava.tjbot.config.Config;
2021
import org.togetherjava.tjbot.db.Database;
@@ -26,7 +27,6 @@
2627
import java.time.temporal.TemporalAccessor;
2728
import java.util.*;
2829
import java.util.List;
29-
import java.util.concurrent.Executors;
3030
import java.util.concurrent.ScheduledExecutorService;
3131
import java.util.concurrent.TimeUnit;
3232
import java.util.function.BiFunction;
@@ -36,13 +36,13 @@
3636

3737
/**
3838
* Routine that automatically checks moderator actions on a schedule and logs them to dedicated
39-
* channels. Use {@link #start()} to trigger automatic execution of the routine.
39+
* channels.
4040
* <p>
4141
* The routine is executed periodically, for example three times per day. When it runs, it checks
4242
* all moderator actions, such as user bans, kicks, muting or message deletion. Actions are then
4343
* logged to a dedicated channel, given by {@link Config#getModAuditLogChannelPattern()}.
4444
*/
45-
public final class ModAuditLogRoutine {
45+
public final class ModAuditLogRoutine implements Routine {
4646
private static final Logger logger = LoggerFactory.getLogger(ModAuditLogRoutine.class);
4747
private static final int CHECK_AUDIT_LOG_START_HOUR = 4;
4848
private static final int CHECK_AUDIT_LOG_EVERY_HOURS = 8;
@@ -51,24 +51,19 @@ public final class ModAuditLogRoutine {
5151

5252
private final Predicate<TextChannel> isAuditLogChannel;
5353
private final Database database;
54-
private final JDA jda;
55-
private final ScheduledExecutorService checkAuditLogService =
56-
Executors.newSingleThreadScheduledExecutor();
5754

5855
/**
5956
* Creates a new instance.
6057
*
61-
* @param jda the JDA instance to use to send messages and retrieve information
6258
* @param database the database for memorizing audit log dates
6359
*/
64-
public ModAuditLogRoutine(@NotNull JDA jda, @NotNull Database database) {
60+
public ModAuditLogRoutine(@NotNull Database database) {
6561
Predicate<String> isAuditLogChannelName =
6662
Pattern.compile(Config.getInstance().getModAuditLogChannelPattern())
6763
.asMatchPredicate();
6864
isAuditLogChannel = channel -> isAuditLogChannelName.test(channel.getName());
6965

7066
this.database = database;
71-
this.jda = jda;
7267
}
7368

7469
private static @NotNull RestAction<MessageEmbed> handleAction(@NotNull Action action,
@@ -106,7 +101,7 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
106101
}
107102

108103
/**
109-
* Schedules the given task for execution at a fixed rate (see
104+
* Creates a schedule for execution at a fixed rate (see
110105
* {@link ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit)}). The
111106
* initial first execution will be delayed to the next fixed time that matches the given period,
112107
* effectively making execution stable at fixed times of a day - regardless of when this method
@@ -120,14 +115,11 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
120115
* Execution will also correctly roll over to the next day, for example if the method is
121116
* triggered at 21:30, the next execution will be at 4:00 the following day.
122117
*
123-
* @param service the scheduler to use
124-
* @param command the command to schedule
125118
* @param periodStartHour the hour of the day that marks the start of this period
126119
* @param periodHours the scheduling period in hours
127-
* @return the instant when the command will be executed the first time
120+
* @return the according schedule representing the planned execution
128121
*/
129-
private static @NotNull Instant scheduleAtFixedRateFromNextFixedTime(
130-
@NotNull ScheduledExecutorService service, @NotNull Runnable command,
122+
private static @NotNull Schedule scheduleAtFixedRateFromNextFixedTime(
131123
@SuppressWarnings("SameParameterValue") int periodStartHour,
132124
@SuppressWarnings("SameParameterValue") int periodHours) {
133125
// NOTE This scheduler could be improved, for example supporting arbitrary periods (not just
@@ -153,9 +145,8 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
153145
Instant now = Instant.now();
154146
Instant nextFixedTime =
155147
computeClosestNextScheduleDate(now, fixedScheduleHours, periodHours);
156-
service.scheduleAtFixedRate(command, ChronoUnit.SECONDS.between(now, nextFixedTime),
148+
return new Schedule(ScheduleMode.FIXED_RATE, ChronoUnit.SECONDS.between(now, nextFixedTime),
157149
TimeUnit.HOURS.toSeconds(periodHours), TimeUnit.SECONDS);
158-
return nextFixedTime;
159150
}
160151

161152
private static @NotNull Instant computeClosestNextScheduleDate(@NotNull Instant instant,
@@ -213,19 +204,21 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
213204
return Optional.of(handleAction(Action.MESSAGE_DELETION, entry));
214205
}
215206

216-
/**
217-
* Starts the routine, automatically checking the audit logs on a schedule.
218-
*/
219-
public void start() {
220-
// TODO This should be registered at some sort of routine system instead (see GH issue #235
221-
// which adds support for routines)
222-
Instant startInstant = scheduleAtFixedRateFromNextFixedTime(checkAuditLogService,
223-
this::checkAuditLogsRoutine, CHECK_AUDIT_LOG_START_HOUR,
207+
@Override
208+
public void run(@NotNull JDA jda) {
209+
checkAuditLogsRoutine(jda);
210+
}
211+
212+
@Override
213+
public @NotNull Schedule createSchedule() {
214+
Schedule schedule = scheduleAtFixedRateFromNextFixedTime(CHECK_AUDIT_LOG_START_HOUR,
224215
CHECK_AUDIT_LOG_EVERY_HOURS);
225-
logger.info("Checking audit logs is scheduled for {}.", startInstant);
216+
logger.info("Checking audit logs is scheduled for {}.",
217+
Instant.now().plus(schedule.initialDuration(), schedule.unit().toChronoUnit()));
218+
return schedule;
226219
}
227220

228-
private void checkAuditLogsRoutine() {
221+
private void checkAuditLogsRoutine(@NotNull JDA jda) {
229222
logger.info("Checking audit logs of all guilds...");
230223

231224
jda.getGuildCache().forEach(guild -> {

0 commit comments

Comments
 (0)