-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpre-fetch.ts
108 lines (90 loc) · 3.53 KB
/
pre-fetch.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { Client, Message, NewsChannel, PrivateThreadChannel, PublicThreadChannel, StageChannel, TextChannel, VoiceChannel } from 'discord.js';
import { MediaModule } from './types';
import { getCurrentStartEnd } from './prisma';
import { debugLog } from './logger';
/**
* Fetch all messages in the submissions channel for the current submission period
* and cache them to memory to receive reactions
* @param mediaModule The media module to pre-fetch messages for
* @param client The logged in Discord client
* @returns A promise that resolves when the messages have been fetched
*/
export const preFetchSubmissionPeriodMessages = async (
client: Client<true>,
mediaModule: MediaModule,
): Promise<void> => {
const debugTag = `[${mediaModule.name}/pre-fetch]`;
const { submissionsChannelId } = mediaModule;
debugLog(`${debugTag} Fetching messages for submission period to receive reactions`);
const submissionsChannel = await client.channels.fetch(submissionsChannelId).catch(() => null);
if (!submissionsChannel) {
debugLog(`${debugTag} Submissions channel not found`);
return;
}
if (!submissionsChannel.isTextBased()) {
debugLog(`${debugTag} Submissions channel not text based`);
return;
}
if (submissionsChannel.isDMBased()) {
debugLog(`${debugTag} Submissions channel is DM based`);
return;
}
const { currStart, currEnd } = getCurrentStartEnd(
mediaModule.cronOutputSubmission,
mediaModule.cronTimezone,
)
debugLog(`${debugTag} Fetching messages from ${currStart.toISOString()} to ${currEnd.toISOString()}`);
// Note: Since this is used to cache the "current" submission period,
// we don't have to provide an end date and worry about timezones
const messages = await fetchMessages(submissionsChannel, currStart, new Date(), true);
debugLog(`${debugTag} Fetched ${messages.size} messages, cached to memory to receive reactions`);
return;
}
export const fetchMessages = async (
channel: TextChannel | NewsChannel | StageChannel | PrivateThreadChannel | PublicThreadChannel | VoiceChannel,
start: Date, // Oldest date, fetch messages before this date
end?: Date, // Newest date, fetch messages after this date
shouldCache = false
): Promise<Map<string, Message<true>>> => {
const debugTag = `[${channel.name}/fetch]`;
const fetchBatch = async (fromMessageId: string | undefined) => {
const messages = await channel.messages.fetch({
before: fromMessageId,
limit: 100,
cache: shouldCache,
}).catch((e) => {
debugLog(`${debugTag} Failed to fetch messages:`, e);
return null;
});
return messages;
}
const startVal = start.valueOf();
const endVal = end?.valueOf() ?? Date.now();
let fromMessageId: string | undefined = undefined;
const messages = new Map<string, Message<true>>();
await new Promise<void>((resolve) => {
const run = async () => {
const innerMessages = await fetchBatch(fromMessageId);
if (innerMessages === null || innerMessages.size === 0) {
resolve();
return;
}
const inTimeFrame = innerMessages.filter((message) => {
const createdAt = message.createdAt.valueOf();
return createdAt >= startVal && createdAt <= endVal;
});
if (inTimeFrame.size === 0) {
resolve();
return;
}
inTimeFrame.forEach((message) => {
messages.set(message.id, message);
});
fromMessageId = innerMessages.lastKey();
await run();
}
run();
});
debugLog(`${debugTag} Fetched ${messages.size} messages`);
return messages;
}