File size: 4,140 Bytes
ee3e190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
109
110
111
112
113
114
115
116
117
118
119
120
121
// Updated Cloudflare Worker for Backblaze B2 with NestJS Backend Resizing
export default {
  async fetch(request, env, ctx) {
    try {
      const url = new URL(request.url);

      // 1. Restrict to CDN domain only
      if (url.hostname !== 'cdn.aksharbhesaniya.dev') {
        return new Response('Forbidden', { status: 403 });
      }

      // 2. Serve from cache if available
      const cache = caches.default;
      const cacheKey = new Request(url.toString(), request);
      const cached = await cache.match(cacheKey);
      if (cached) {
        console.log('Cache HIT:', url.toString());
        return cached;
      }

      console.log('Cache MISS:', url.toString());

      // 3. Read resize parameters
      const width = url.searchParams.get('w');
      const height = url.searchParams.get('h');
      const quality = url.searchParams.get('q');

      // 4. Check if resizing is requested
      const needsResize = width || height || quality;

      if (needsResize) {
        // ===== RESIZE PATH: Proxy to NestJS Backend =====
        const backendUrl = env.BACKEND_URL || 'https://api.streamflix.com';
        const filePath = url.pathname.substring(1); // Remove leading slash

        // Build backend resize URL
        const resizeUrl = new URL(`${backendUrl}/backblaze/resize`);
        resizeUrl.searchParams.set('path', filePath);
        if (width) resizeUrl.searchParams.set('w', width);
        if (height) resizeUrl.searchParams.set('h', height);
        if (quality) resizeUrl.searchParams.set('q', quality);

        console.log('Fetching resized image from backend:', resizeUrl.toString());

        // Fetch resized image from NestJS backend
        const backendResponse = await fetch(resizeUrl.toString());

        if (!backendResponse.ok) {
          return new Response('Resize failed', { status: backendResponse.status });
        }

        // Cache and return resized image
        const response = new Response(backendResponse.body, {
          headers: {
            'Content-Type': backendResponse.headers.get('Content-Type') || 'image/jpeg',
            'Cache-Control': 'public, max-age=31536000', // Cache for 1 year
            'X-Resize-Backend': 'NestJS',
          },
        });

        ctx.waitUntil(cache.put(cacheKey, response.clone()));
        return response;
      } else {
        // ===== ORIGINAL PATH: Serve from B2 directly =====
        // 5. Load B2 secrets
        const KEY_ID = env.B2_KEY_ID;
        const APP_KEY = env.B2_APP_KEY;
        const BUCKET = env.B2_BUCKET;

        if (!KEY_ID || !APP_KEY || !BUCKET) {
          return new Response('Missing B2 config', { status: 500 });
        }

        // 6. Authorize Backblaze B2
        const authRes = await fetch(
          'https://api.backblazeb2.com/b2api/v2/b2_authorize_account',
          {
            headers: { Authorization: 'Basic ' + btoa(`${KEY_ID}:${APP_KEY}`) },
          },
        );

        if (!authRes.ok) {
          return new Response('B2 auth failed', { status: 502 });
        }

        const auth = await authRes.json();

        // 7. Build file URL
        const cleanPath = url.pathname;
        const fileUrl = `${auth.downloadUrl}/file/${BUCKET}${cleanPath}`;

        console.log('Fetching original from B2:', fileUrl);

        // 8. Fetch file from B2
        const origin = await fetch(fileUrl, {
          headers: { Authorization: auth.authorizationToken },
        });

        if (!origin.ok) {
          return new Response('File not found', { status: origin.status });
        }

        // 9. Cache and return original
        const response = new Response(origin.body, {
          headers: {
            'Content-Type': origin.headers.get('Content-Type') || 'image/jpeg',
            'Cache-Control': 'public, max-age=31536000', // Cache for 1 year
            'X-Source': 'B2-Direct',
          },
        });

        ctx.waitUntil(cache.put(cacheKey, response.clone()));
        return response;
      }
    } catch (err) {
      console.error('Worker error:', err);
      return new Response('Internal Error: ' + err.message, { status: 500 });
    }
  },
};