Skip to content

Commit f694c71

Browse files
committed
Tweak the Cloudflare caching behavior for CD-ROM chunks
5bb4dde disabled it across the board, but it's actually beneficial for smaller files (under a couple of hundred megs). Make the UI side include the total file size in the request, and use that to determine if we should cache or not.
1 parent 1a106bb commit f694c71

2 files changed

Lines changed: 51 additions & 16 deletions

File tree

src/emulator/emulator-worker-cdrom-disk.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,16 @@ export function createEmulatorWorkerCDROMDisk(
3030
chunks.push(`${chunkStart}-${chunkEnd}`);
3131
chunkStart = chunkEnd;
3232
}
33+
// Minimal metadata for workers-site/cd-rom.ts to reconstruct
34+
const encoded = btoa(
35+
JSON.stringify({
36+
srcUrl: cdrom.srcUrl,
37+
totalSize,
38+
})
39+
);
3340
const spec = {
3441
name,
35-
baseUrl: `/CD-ROM/${btoa(cdrom.srcUrl)}`,
42+
baseUrl: `/CD-ROM/${encoded}`,
3643
totalSize,
3744
chunks,
3845
chunkSize: CHUNK_SIZE,

workers-site/cd-rom.ts

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
import {type EmulatorCDROM} from "../src/emulator/emulator-common";
22

3+
type CDROMSpec = {
4+
srcUrl: string;
5+
totalSize?: number;
6+
};
7+
38
export async function handleRequest(path: string, method: string) {
49
const pathPieces = path.split("/");
5-
let srcUrl;
10+
let specStr;
611
try {
7-
srcUrl = atob(pathPieces[2]);
12+
specStr = atob(pathPieces[2]);
813
} catch (e) {
9-
return errorResponse("Malformed CD-ROM src URL: " + pathPieces[2]);
14+
return errorResponse("Malformed CD-ROM spec: " + pathPieces[2]);
1015
}
1116

12-
if (!isValidSrcUrl(srcUrl)) {
13-
return errorResponse("Unexpected CD-ROM src URL: " + srcUrl);
17+
let spec: CDROMSpec;
18+
if (specStr.startsWith("{")) {
19+
try {
20+
spec = JSON.parse(specStr);
21+
} catch (e) {
22+
return errorResponse("Malformed CD-ROM spec: " + specStr);
23+
}
24+
} else {
25+
// Simple spec, just a URL.
26+
spec = {srcUrl: specStr};
27+
}
28+
29+
if (!isValidSrcUrl(spec.srcUrl)) {
30+
return errorResponse("Unexpected CD-ROM src URL: " + spec.srcUrl);
1431
}
1532

1633
if (method === "GET") {
17-
return await handleGET(pathPieces, srcUrl);
34+
return await handleGET(pathPieces, spec);
1835
}
1936
if (method === "PUT") {
20-
return await handlePUT(srcUrl);
37+
return await handlePUT(spec.srcUrl);
2138
}
2239

2340
return errorResponse("Method not allowed", 405);
@@ -56,7 +73,7 @@ export function isValidSrcUrl(srcUrl: string) {
5673
return false;
5774
}
5875

59-
async function handleGET(pathPieces: string[], srcUrl: string) {
76+
async function handleGET(pathPieces: string[], spec: CDROMSpec) {
6077
const chunkMatch = /(\d+)-(\d+).chunk$/.exec(pathPieces[3]);
6178
if (!chunkMatch) {
6279
return errorResponse("Malformed CD-ROM src chunk: " + pathPieces[3]);
@@ -69,7 +86,7 @@ async function handleGET(pathPieces: string[], srcUrl: string) {
6986
for (let retry = 0; retry < 3; retry++) {
7087
try {
7188
const {chunk, contentLength} = await fetchChunk(
72-
srcUrl,
89+
spec,
7390
chunkStart,
7491
chunkEnd
7592
);
@@ -90,7 +107,7 @@ async function handleGET(pathPieces: string[], srcUrl: string) {
90107
}
91108

92109
console.warn("CD-ROM fetch failed", {
93-
srcUrl,
110+
...spec,
94111
chunkStart,
95112
chunkEnd,
96113
chunkFetchError,
@@ -156,18 +173,29 @@ async function handlePUT(srcUrl: string) {
156173
}
157174

158175
async function fetchChunk(
159-
srcUrl: string,
176+
spec: CDROMSpec,
160177
chunkStart: number,
161178
chunkEnd: number
162179
) {
163-
const srcRes = await fetch(srcUrl, {
180+
// Don't allow Cloudflare to cache requests in large files, since it will attempt
181+
// to read the entire file (as opposed to just the range that we requested).
182+
const isLargeFile =
183+
spec.totalSize !== undefined && spec.totalSize > 250 * 1024 * 1024;
184+
const cacheOptions: Partial<RequestInit<RequestInitCfProperties>> =
185+
isLargeFile
186+
? {cache: "no-store"}
187+
: {
188+
cf: {
189+
cacheEverything: true,
190+
cacheTtl: 30 * 24 * 60 * 60,
191+
},
192+
};
193+
const srcRes = await fetch(spec.srcUrl, {
164194
headers: {
165195
"User-Agent": "Infinite Mac (+https://infinitemac.org)",
166196
"Range": `bytes=${chunkStart}-${chunkEnd}`,
167197
},
168-
// Don't allow Cloudflare to cache this request, since it will attempt
169-
// to read the entire file (as opposed to jus the range that we requested).
170-
cache: "no-store",
198+
...cacheOptions,
171199
signal: AbortSignal.timeout(2000),
172200
});
173201

0 commit comments

Comments
 (0)