feat: purge status channel on startup for clean dashboard
- Add purgeChannel() to Channel interface and DiscordChannel - Uses bulkDelete for recent messages, individual delete for old ones - Called once at startup before creating fresh dashboard messages
This commit is contained in:
@@ -494,6 +494,53 @@ export class DiscordChannel implements Channel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async purgeChannel(jid: string): Promise<number> {
|
||||||
|
if (!this.client) return 0;
|
||||||
|
let deleted = 0;
|
||||||
|
try {
|
||||||
|
const channelId = jid.replace(/^dc:/, '');
|
||||||
|
const channel = await this.client.channels.fetch(channelId);
|
||||||
|
if (!channel || !('bulkDelete' in channel)) return 0;
|
||||||
|
const tc = channel as TextChannel;
|
||||||
|
|
||||||
|
// Fetch and delete in batches (bulkDelete handles up to 100, only < 14 days old)
|
||||||
|
let hasMore = true;
|
||||||
|
while (hasMore) {
|
||||||
|
const messages = await tc.messages.fetch({ limit: 100 });
|
||||||
|
if (messages.size === 0) break;
|
||||||
|
|
||||||
|
// Separate into bulk-deletable (< 14 days) and old messages
|
||||||
|
const twoWeeksAgo = Date.now() - 14 * 24 * 60 * 60 * 1000;
|
||||||
|
const recent = messages.filter(
|
||||||
|
(m) => m.createdTimestamp > twoWeeksAgo,
|
||||||
|
);
|
||||||
|
const old = messages.filter(
|
||||||
|
(m) => m.createdTimestamp <= twoWeeksAgo,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (recent.size >= 2) {
|
||||||
|
await tc.bulkDelete(recent);
|
||||||
|
deleted += recent.size;
|
||||||
|
} else if (recent.size === 1) {
|
||||||
|
await recent.first()!.delete();
|
||||||
|
deleted += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [, msg] of old) {
|
||||||
|
await msg.delete();
|
||||||
|
deleted += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMore = messages.size === 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info({ jid, deleted }, 'Purged channel messages');
|
||||||
|
} catch (err) {
|
||||||
|
logger.error({ jid, err, deleted }, 'Failed to purge channel messages');
|
||||||
|
}
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
async editMessage(
|
async editMessage(
|
||||||
jid: string,
|
jid: string,
|
||||||
messageId: string,
|
messageId: string,
|
||||||
|
|||||||
15
src/index.ts
15
src/index.ts
@@ -756,7 +756,10 @@ async function buildUsageContent(): Promise<string> {
|
|||||||
|
|
||||||
lines.push(`• 업타임: ${formatElapsed(os.uptime() * 1000)}`);
|
lines.push(`• 업타임: ${formatElapsed(os.uptime() * 1000)}`);
|
||||||
|
|
||||||
return lines.join('\n') + `\n\n_${new Date().toLocaleTimeString('ko-KR', { hour: '2-digit', minute: '2-digit' })}_`;
|
return (
|
||||||
|
lines.join('\n') +
|
||||||
|
`\n\n_${new Date().toLocaleTimeString('ko-KR', { hour: '2-digit', minute: '2-digit' })}_`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Dashboard Lifecycle ─────────────────────────────────────────
|
// ── Dashboard Lifecycle ─────────────────────────────────────────
|
||||||
@@ -1115,6 +1118,16 @@ async function main(): Promise<void> {
|
|||||||
});
|
});
|
||||||
queue.setProcessMessagesFn(processGroupMessages);
|
queue.setProcessMessagesFn(processGroupMessages);
|
||||||
recoverPendingMessages();
|
recoverPendingMessages();
|
||||||
|
// Purge old messages in status channel before creating fresh dashboards
|
||||||
|
if (STATUS_CHANNEL_ID) {
|
||||||
|
const statusJid = `dc:${STATUS_CHANNEL_ID}`;
|
||||||
|
const ch = channels.find(
|
||||||
|
(c) => c.name.startsWith('discord') && c.isConnected() && c.purgeChannel,
|
||||||
|
);
|
||||||
|
if (ch?.purgeChannel) {
|
||||||
|
await ch.purgeChannel(statusJid);
|
||||||
|
}
|
||||||
|
}
|
||||||
await startStatusDashboard();
|
await startStatusDashboard();
|
||||||
await startUsageDashboard();
|
await startUsageDashboard();
|
||||||
startMessageLoop().catch((err) => {
|
startMessageLoop().catch((err) => {
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export interface Channel {
|
|||||||
syncGroups?(force: boolean): Promise<void>;
|
syncGroups?(force: boolean): Promise<void>;
|
||||||
// Optional: get channel metadata (position, category) for ordering.
|
// Optional: get channel metadata (position, category) for ordering.
|
||||||
getChannelMeta?(jids: string[]): Promise<Map<string, ChannelMeta>>;
|
getChannelMeta?(jids: string[]): Promise<Map<string, ChannelMeta>>;
|
||||||
|
// Optional: delete all messages in a channel (used for dashboard cleanup).
|
||||||
|
purgeChannel?(jid: string): Promise<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback type that channels use to deliver inbound messages
|
// Callback type that channels use to deliver inbound messages
|
||||||
|
|||||||
Reference in New Issue
Block a user