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 ,
@@ -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