From 53db4a858b17a5ccf10f13565eb00841fd8f26e4 Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 22 Aug 2026 12:44:18 +0200 Subject: [PATCH] perf: download icon and swf concurrently during furni import Run the independent icon and swf downloads in parallel via Promise.all instead of sequentially. The nitro fallback still runs after the swf check since it depends on the swf result. Combined with batch concurrency and the single FurnitureData write, this further cuts per-item import time (roughly halves the download phase). --- src/lib/services/furni-import.ts | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lib/services/furni-import.ts b/src/lib/services/furni-import.ts index 1aa9bfbf..0a77df27 100644 --- a/src/lib/services/furni-import.ts +++ b/src/lib/services/furni-import.ts @@ -502,6 +502,19 @@ export function __resetCatalogIdAllocatorForTests(): void { // ── Import Single Furni ───────────────────────────────────────────── +// Try each candidate URL in order until one downloads successfully. +async function tryDownloadCandidates( + urls: string[], + dest: string, + validate: "png" | "swf", +): Promise { + for (const url of urls) { + const dl = await downloadFile(url, dest, { validate }); + if (dl.ok) return true; + } + return false; +} + export async function importSingleFurni(params: { id: number; classname: string; @@ -703,29 +716,16 @@ export async function importSingleFurni(params: { `https://images.habbo.com/dcr/hof_furni/${rev}/${encodeURIComponent(safeSwfName)}.swf`, ); - // Download icon (try all candidate URLs) - let iconOk = false; - for (const iconUrl of iconUrls) { - const dl = await downloadFile(iconUrl, iconPath, { validate: "png" }); - if (dl.ok) { - iconOk = true; - break; - } - } - - // Download SWF (try all candidate URLs) - let swfOk = false; - for (const swfUrl of swfUrls) { - const dl = await downloadFile(swfUrl, swfPath, { validate: "swf" }); - if (dl.ok) { - swfOk = true; - break; - } - } + // Download icon + SWF concurrently (independent assets). Each tries its + // candidate URLs in order until one succeeds. + const [iconOkResult, swfOk] = await Promise.all([ + tryDownloadCandidates(iconUrls, iconPath, "png"), + tryDownloadCandidates(swfUrls, swfPath, "swf"), + ]); + let iconOk = iconOkResult; // ── Nitro bundle fallback: try downloading pre-made .nitro ──────── - // If SWF download failed, try downloading a pre-made .nitro from the - // source's nitro base URL (many retro hotels ship .nitro bundles). + // Only relevant when the SWF download failed, so it runs after SWF. let nitroDownloadOk = false; if ( !swfOk &&