From ef137199ec2d81d5baa81efed24397e57be989a1 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 9 Apr 2026 10:22:59 +0400 Subject: [PATCH] fixed cors issue --- frontend/src/hooks/usePreloadOrchestrator.ts | 64 ++------------------ frontend/src/lib/offline/DownloadManager.ts | 35 ++++++++++- 2 files changed, 37 insertions(+), 62 deletions(-) diff --git a/frontend/src/hooks/usePreloadOrchestrator.ts b/frontend/src/hooks/usePreloadOrchestrator.ts index ce01e9d..b5d8deb 100644 --- a/frontend/src/hooks/usePreloadOrchestrator.ts +++ b/frontend/src/hooks/usePreloadOrchestrator.ts @@ -18,10 +18,8 @@ import { extractStoragePath, queuePresignedUrls, isRelativeStoragePath, - markPresignedUrlFailed, markPresignedUrlsVerified, isPresignedUrl, - buildProxyUrl, } from '../lib/assetUrl'; import { logger } from '../lib/logger'; import type { BlobUrlReadyEvent } from '../types/offline'; @@ -173,7 +171,7 @@ export function usePreloadOrchestrator( }); // Use DownloadManager for unified download and blob URL creation - // Mark presigned URL as verified if download succeeds + // DownloadManager automatically handles presigned URL → proxy fallback downloadManager .addJob({ assetId: item.id, @@ -192,44 +190,11 @@ export function usePreloadOrchestrator( markPresignedUrlsVerified(); } }) - .catch(async (err) => { + .catch((err) => { logger.error('[PRELOAD] Download failed', { url: item.url.slice(-50), error: err?.message, }); - - // If presigned URL failed (e.g., CORS), retry with proxy URL - if (storageKey && isPresignedUrl(item.url)) { - markPresignedUrlFailed(storageKey); - const proxyUrl = buildProxyUrl(storageKey); - logger.info('[PRELOAD] Retrying with proxy URL', { - storageKey: storageKey.slice(-50), - proxyUrl: proxyUrl.slice(-60), - }); - - try { - await downloadManager.addJob({ - assetId: item.id, - projectId: '', - url: proxyUrl, - filename: storageKey.split('/').pop() || 'asset', - variantType: 'original', - assetType: mapAssetType(item.assetType), - priority: item.priority, - storageKey, - createBlobUrl: true, - persist: false, - }); - logger.info('[PRELOAD] Proxy download complete', { - url: proxyUrl.slice(-60), - }); - } catch (retryErr) { - logger.error('[PRELOAD] Proxy download also failed', { - url: proxyUrl.slice(-60), - error: retryErr instanceof Error ? retryErr.message : 'unknown', - }); - } - } }); preloadedUrls.add(storageKey); @@ -582,6 +547,7 @@ export function usePreloadOrchestrator( // Partial downloads (video/audio/transition) use presigned URL directly for playback const createBlobUrl = assetType === 'image' || maxBytes === undefined; + // DownloadManager automatically handles presigned URL → proxy fallback return downloadManager .addJob({ assetId: id, @@ -601,33 +567,11 @@ export function usePreloadOrchestrator( markPresignedUrlsVerified(); } }) - .catch(async (err) => { + .catch((err) => { logger.error('[PRELOAD] Download failed', { url: resolvedUrl.slice(-50), error: err?.message, }); - // Retry with proxy if presigned URL failed - if (isPresignedUrl(resolvedUrl)) { - markPresignedUrlFailed(normalizedKey); - const proxyUrl = buildProxyUrl(normalizedKey); - try { - await downloadManager.addJob({ - assetId: id, - projectId: '', - url: proxyUrl, - filename: normalizedKey.split('/').pop() || 'asset', - variantType: 'original', - assetType: mapAssetType(assetType), - priority, - storageKey: normalizedKey, - createBlobUrl, - persist: false, - maxBytes, // Preserve partial preload behavior for retry - }); - } catch { - // Ignore retry failures - } - } }); }; diff --git a/frontend/src/lib/offline/DownloadManager.ts b/frontend/src/lib/offline/DownloadManager.ts index 2bad79a..55b68a5 100644 --- a/frontend/src/lib/offline/DownloadManager.ts +++ b/frontend/src/lib/offline/DownloadManager.ts @@ -10,7 +10,12 @@ import { OFFLINE_CONFIG } from '../../config/offline.config'; import { downloadEventBus } from './DownloadEventBus'; import { StorageManager } from './StorageManager'; import { OfflineDbManager } from '../offlineDb/OfflineDbManager'; -import { extractStoragePath } from '../assetUrl'; +import { + extractStoragePath, + isPresignedUrl, + markPresignedUrlFailed, + buildProxyUrl, +} from '../assetUrl'; import { logger } from '../logger'; import type { PreloadJobStatus, @@ -39,6 +44,7 @@ interface DownloadJob { persist?: boolean; // Persist to IndexedDB for resume (default: true) maxBytes?: number; // Partial download limit (undefined = full download) isPartial?: boolean; // Whether this was a partial download (for tracking) + usedProxyFallback?: boolean; // Whether we've already tried proxy URL fallback abortController?: AbortController; resolve?: () => void; reject?: (error: Error) => void; @@ -402,10 +408,35 @@ class DownloadManagerClass { return; } - job.retryCount++; const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + // If presigned URL failed and we haven't tried proxy yet, fall back to proxy + if (isPresignedUrl(job.url) && !job.usedProxyFallback) { + markPresignedUrlFailed(job.storageKey); + const proxyUrl = buildProxyUrl(job.storageKey); + + logger.info('[DownloadManager] Presigned URL failed, retrying with proxy', { + storageKey: job.storageKey.slice(-50), + error: errorMessage, + }); + + // Update job to use proxy URL and retry immediately + job.url = proxyUrl; + job.usedProxyFallback = true; + job.retryCount = 0; // Reset retry count for proxy attempt + job.bytesLoaded = 0; + job.progress = 0; + job.status = 'queued'; + + // Retry immediately with proxy URL + this.queue.unshift(job); + this.processQueue(); + return; + } + + job.retryCount++; + if (job.retryCount < this.config.maxRetries) { // Retry with backoff job.status = 'queued';