From e8908812214961a4632157a3d6645ba421184915 Mon Sep 17 00:00:00 2001 From: b3ni15 Date: Thu, 16 Oct 2025 10:08:47 +0200 Subject: [PATCH] refactor: Update message deletion logic to handle rate limits and improve error handling --- src/app/api/cron/cleanup/route.ts | 46 +++++++++++++++++++---------- src/app/api/delete/route.ts | 39 +++++++++++++----------- src/app/download/[file_id]/page.tsx | 2 +- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/app/api/cron/cleanup/route.ts b/src/app/api/cron/cleanup/route.ts index e8b661f..fcfd7af 100644 --- a/src/app/api/cron/cleanup/route.ts +++ b/src/app/api/cron/cleanup/route.ts @@ -33,15 +33,22 @@ export async function POST(request: Request) { const [parts]: any[] = await connection.query('SELECT discord_message_id FROM file_parts WHERE file_id = ?', [file_id]); if (parts.length > 0) { - const deletePromises = parts.map((part: { discord_message_id: string }) => { - if (!part.discord_message_id) return Promise.resolve(); + for (const part of parts) { + if (!part.discord_message_id) continue; const deleteUrl = `https://discord.com/api/v10/channels/${process.env.DISCORD_CHANNEL_ID}/messages/${part.discord_message_id}`; - return fetch(deleteUrl, { - method: 'DELETE', - headers: { 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}` }, - }); - }); - await Promise.allSettled(deletePromises); + try { + const res = await fetch(deleteUrl, { + method: 'DELETE', + headers: { 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}` }, + }); + if (!res.ok && res.status !== 404) { + console.warn(`Cleanup: Failed to delete message ${part.discord_message_id}. Status: ${res.status}`); + } + } catch (e) { + console.error(`Cleanup: Error deleting message ${part.discord_message_id}:`, e); + } + await new Promise(resolve => setTimeout(resolve, 1000)); // 1s delay + } } await connection.query('DELETE FROM file_parts WHERE file_id = ?', [file_id]); @@ -65,15 +72,22 @@ export async function POST(request: Request) { ); if (partsRows.length > 0) { - const deletePromises = partsRows.map((part: { discord_message_id: string }) => { - if (!part.discord_message_id) return Promise.resolve(); + for (const part of partsRows) { + if (!part.discord_message_id) continue; const deleteUrl = `https://discord.com/api/v10/channels/${process.env.DISCORD_CHANNEL_ID}/messages/${part.discord_message_id}`; - return fetch(deleteUrl, { - method: 'DELETE', - headers: { 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}` }, - }); - }); - await Promise.allSettled(deletePromises); + try { + const res = await fetch(deleteUrl, { + method: 'DELETE', + headers: { 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}` }, + }); + if (!res.ok && res.status !== 404) { + console.warn(`Cleanup: Failed to delete message ${part.discord_message_id}. Status: ${res.status}`); + } + } catch (e) { + console.error(`Cleanup: Error deleting message ${part.discord_message_id}:`, e); + } + await new Promise(resolve => setTimeout(resolve, 1000)); // 1s delay + } } await connection.query('UPDATE files SET deleted = 1 WHERE id = ?', [file_id]); diff --git a/src/app/api/delete/route.ts b/src/app/api/delete/route.ts index 4566181..aa12e6b 100644 --- a/src/app/api/delete/route.ts +++ b/src/app/api/delete/route.ts @@ -35,28 +35,33 @@ export async function POST(request: Request) { [file_id] ); - // 3. Delete each message from Discord using the Bot API - const deletePromises = partsRows.map((part: { discord_message_id: string }) => { + // 3. Delete each message from Discord sequentially to avoid rate limits + for (const part of partsRows) { + if (!part.discord_message_id) continue; + const deleteUrl = `https://discord.com/api/v10/channels/${process.env.DISCORD_CHANNEL_ID}/messages/${part.discord_message_id}`; - return fetch(deleteUrl, { - method: 'DELETE', - headers: { - 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}`, + try { + const res = await fetch(deleteUrl, { + method: 'DELETE', + headers: { 'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}` }, + }); + + if (!res.ok && res.status !== 404) { // Don't warn on 404 (already deleted) + console.warn(`Failed to delete message ${part.discord_message_id}. Status: ${res.status}`); } - }); - }); - - const results = await Promise.allSettled(deletePromises); - results.forEach(result => { - if (result.status === 'rejected') { - console.warn('Failed to delete a message from Discord:', result.reason); + } catch (e) { + console.error(`Error deleting message ${part.discord_message_id}:`, e); } - }); - // 4. Mark the file as deleted in the database (soft delete) - await connection.query('UPDATE files SET deleted = 1 WHERE id = ?', [file_id]); + // Wait 1 second between delete requests to avoid hitting Discord's rate limits. + await new Promise(resolve => setTimeout(resolve, 1000)); + } - return NextResponse.json({ success: true, message: 'File marked for deletion.' }); + // 4. Hard delete the file from the database + await connection.query('DELETE FROM file_parts WHERE file_id = ?', [file_id]); + await connection.query('DELETE FROM files WHERE id = ?', [file_id]); + + return NextResponse.json({ success: true, message: 'File permanently deleted.' }); } finally { connection.release(); diff --git a/src/app/download/[file_id]/page.tsx b/src/app/download/[file_id]/page.tsx index ecbbfda..4f2e7f1 100644 --- a/src/app/download/[file_id]/page.tsx +++ b/src/app/download/[file_id]/page.tsx @@ -110,7 +110,7 @@ export default function DownloadPage() { const response = await fetchWithRetry(`/api/download-part/${file_id}/${part.part_index}`); const buffer = await response.arrayBuffer(); encryptedParts[part.part_index] = { index: part.part_index, data: buffer }; - setDownloadedBytes(prev => prev + buffer.byteLength); + setDownloadedBytes(prev => prev + part.size); setProgress(prev => prev + (1 / metadata.num_parts) * 50); });