1515import org .jetbrains .annotations .Nullable ;
1616import org .slf4j .Logger ;
1717import org .slf4j .LoggerFactory ;
18+ import org .togetherjava .tjbot .commands .Routine ;
1819import org .togetherjava .tjbot .commands .moderation .ModerationUtils ;
1920import org .togetherjava .tjbot .config .Config ;
2021import org .togetherjava .tjbot .db .Database ;
2627import java .time .temporal .TemporalAccessor ;
2728import java .util .*;
2829import java .util .List ;
29- import java .util .concurrent .Executors ;
3030import java .util .concurrent .ScheduledExecutorService ;
3131import java .util .concurrent .TimeUnit ;
3232import java .util .function .BiFunction ;
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 ,
@@ -105,7 +100,7 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
105100 }
106101
107102 /**
108- * Schedules the given task for execution at a fixed rate (see
103+ * Creates a schedule for execution at a fixed rate (see
109104 * {@link ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit)}). The
110105 * initial first execution will be delayed to the next fixed time that matches the given period,
111106 * effectively making execution stable at fixed times of a day - regardless of when this method
@@ -119,14 +114,11 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
119114 * Execution will also correctly roll over to the next day, for example if the method is
120115 * triggered at 21:30, the next execution will be at 4:00 the following day.
121116 *
122- * @param service the scheduler to use
123- * @param command the command to schedule
124117 * @param periodStartHour the hour of the day that marks the start of this period
125118 * @param periodHours the scheduling period in hours
126- * @return the instant when the command will be executed the first time
119+ * @return the according schedule representing the planned execution
127120 */
128- private static @ NotNull Instant scheduleAtFixedRateFromNextFixedTime (
129- @ NotNull ScheduledExecutorService service , @ NotNull Runnable command ,
121+ private static @ NotNull Schedule scheduleAtFixedRateFromNextFixedTime (
130122 @ SuppressWarnings ("SameParameterValue" ) int periodStartHour ,
131123 @ SuppressWarnings ("SameParameterValue" ) int periodHours ) {
132124 // NOTE This scheduler could be improved, for example supporting arbitrary periods (not just
@@ -152,9 +144,8 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
152144 Instant now = Instant .now ();
153145 Instant nextFixedTime =
154146 computeClosestNextScheduleDate (now , fixedScheduleHours , periodHours );
155- service . scheduleAtFixedRate ( command , ChronoUnit .SECONDS .between (now , nextFixedTime ),
147+ return new Schedule ( ScheduleMode . FIXED_RATE , ChronoUnit .SECONDS .between (now , nextFixedTime ),
156148 TimeUnit .HOURS .toSeconds (periodHours ), TimeUnit .SECONDS );
157- return nextFixedTime ;
158149 }
159150
160151 private static @ NotNull Instant computeClosestNextScheduleDate (@ NotNull Instant instant ,
@@ -212,19 +203,21 @@ private static boolean isSnowflakeAfter(@NotNull ISnowflake snowflake,
212203 return Optional .of (handleAction (Action .MESSAGE_DELETION , entry ));
213204 }
214205
215- /**
216- * Starts the routine, automatically checking the audit logs on a schedule.
217- */
218- public void start () {
219- // TODO This should be registered at some sort of routine system instead (see GH issue #235
220- // which adds support for routines)
221- Instant startInstant = scheduleAtFixedRateFromNextFixedTime ( checkAuditLogService ,
222- this :: checkAuditLogsRoutine , CHECK_AUDIT_LOG_START_HOUR ,
206+ @ Override
207+ public void run ( @ NotNull JDA jda ) {
208+ checkAuditLogsRoutine ( jda );
209+ }
210+
211+ @ Override
212+ public @ NotNull Schedule createSchedule () {
213+ Schedule schedule = scheduleAtFixedRateFromNextFixedTime ( CHECK_AUDIT_LOG_START_HOUR ,
223214 CHECK_AUDIT_LOG_EVERY_HOURS );
224- logger .info ("Checking audit logs is scheduled for {}." , startInstant );
215+ logger .info ("Checking audit logs is scheduled for {}." ,
216+ Instant .now ().plus (schedule .initialDuration (), schedule .unit ().toChronoUnit ()));
217+ return schedule ;
225218 }
226219
227- private void checkAuditLogsRoutine () {
220+ private void checkAuditLogsRoutine (@ NotNull JDA jda ) {
228221 logger .info ("Checking audit logs of all guilds..." );
229222
230223 jda .getGuildCache ().forEach (guild -> {
0 commit comments