@@ -23,6 +23,7 @@ import {
2323 dormantChannelTimeout ,
2424 dormantChannelLoop ,
2525 askHelpChannelId ,
26+ ongoingEmptyTimeout ,
2627} from '../env' ;
2728import { isTrustedMember } from '../util/inhibitors' ;
2829
@@ -66,6 +67,8 @@ export class HelpChanModule extends Module {
6667 . setDescription ( DORMANT_MESSAGE ) ;
6768
6869 busyChannels : Set < string > = new Set ( ) ; // a lock to eliminate race conditions
70+ // a lock used to prevent multiple timeouts running on the same channel
71+ ongoingEmptyTimeouts : Set < string > = new Set ( ) ;
6972
7073 private getChannelName ( guild : Guild ) {
7174 const takenChannelNames = guild . channels . cache
@@ -81,13 +84,68 @@ export class HelpChanModule extends Module {
8184 return `${ this . CHANNEL_PREFIX } ${ decidedChannel } ` ;
8285 }
8386
87+ private getOngoingChannels ( ) {
88+ return this . client . channels . cache
89+ . filter (
90+ channel =>
91+ ( channel as TextChannel ) . parentID === categories . ongoing ,
92+ )
93+ . array ( ) as TextChannel [ ] ;
94+ }
95+
8496 @listener ( { event : 'ready' } )
8597 async startDormantLoop ( ) {
8698 setInterval ( ( ) => {
8799 this . checkDormantPossibilities ( ) ;
88100 } , dormantChannelLoop ) ;
89101 }
90102
103+ @listener ( { event : 'ready' } )
104+ async initialCheckEmptyOngoing ( ) {
105+ for ( const channel of this . getOngoingChannels ( ) ) {
106+ if ( await this . checkEmptyOngoing ( channel ) ) {
107+ await this . startEmptyTimeout ( channel ) ;
108+ }
109+ }
110+ }
111+
112+ // Utility function used to check if there are no messages in an ongoing channel, meaning the bot
113+ // is the most recent message. This will be caused if somebody deletes their message after they
114+ // claim a channel.
115+ async checkEmptyOngoing ( channel : TextChannel ) {
116+ const messages = await channel . messages . fetch ( ) ;
117+
118+ return messages . array ( ) [ 0 ] . author . id === this . client . user ?. id ;
119+ }
120+
121+ async startEmptyTimeout ( channel : TextChannel ) {
122+ if ( this . ongoingEmptyTimeouts . has ( channel . id ) ) return ;
123+
124+ this . ongoingEmptyTimeouts . add ( channel . id ) ;
125+
126+ setTimeout ( async ( ) => {
127+ this . ongoingEmptyTimeouts . delete ( channel . id ) ;
128+
129+ if ( await this . checkEmptyOngoing ( channel ) ) {
130+ await this . markChannelAsDormant ( channel ) ;
131+ }
132+ } , ongoingEmptyTimeout ) ;
133+ }
134+
135+ @listener ( { event : 'messageDelete' } )
136+ async onMessageDeleted ( msg : Message ) {
137+ if (
138+ msg . channel . type !== 'text' ||
139+ ! msg . channel . parentID ||
140+ msg . channel . parentID !== categories . ongoing
141+ )
142+ return ;
143+
144+ if ( await this . checkEmptyOngoing ( msg . channel ) ) {
145+ await this . startEmptyTimeout ( msg . channel ) ;
146+ }
147+ }
148+
91149 async moveChannel ( channel : TextChannel , category : string ) {
92150 const parent = channel . guild . channels . resolve ( category ) ;
93151 if ( parent == null ) return ;
@@ -248,20 +306,13 @@ export class HelpChanModule extends Module {
248306 }
249307
250308 private async checkDormantPossibilities ( ) {
251- const ongoingChannels = this . client . channels . cache . filter ( channel => {
252- if ( channel . type === 'dm' ) return false ;
253-
254- return ( channel as TextChannel ) . parentID === categories . ongoing ;
255- } ) ;
256-
257- for ( const channel of ongoingChannels . array ( ) ) {
258- const messages = await ( channel as TextChannel ) . messages . fetch ( ) ;
309+ for ( const channel of this . getOngoingChannels ( ) ) {
310+ const messages = await channel . messages . fetch ( ) ;
259311
260- const diff =
261- ( Date . now ( ) - messages . array ( ) [ 0 ] . createdAt . getTime ( ) ) / 1000 ;
312+ const diff = Date . now ( ) - messages . array ( ) [ 0 ] . createdAt . getTime ( ) ;
262313
263314 if ( diff > dormantChannelTimeout )
264- await this . markChannelAsDormant ( channel as TextChannel ) ;
315+ await this . markChannelAsDormant ( channel ) ;
265316 }
266317 }
267318
0 commit comments