Files
PMTiles/serverless/cloudflare/worker.ts
Brandon Liu 95b1f90a04 Revert "cloudflare worker: cache holds promises instead of buffers"
see errors related to "The script will never generate a response."

This reverts commit e0402ded7f.
2022-07-21 10:23:13 +08:00

127 lines
2.8 KiB
TypeScript

import { PMTiles, Source } from "../../js";
interface Env {
BUCKET: R2Bucket;
CACHE_TTL: string;
}
interface CacheEntry {
lastUsed: number;
buffer: DataView;
}
export class LRUCache {
entries: Map<string, CacheEntry>;
counter: number;
constructor() {
this.entries = new Map<string, CacheEntry>();
this.counter = 0;
}
async get(
bucket: R2Bucket,
key: string,
offset: number,
length: number
): Promise<[boolean, DataView]> {
let cacheKey = key + ":" + offset + "-" + length;
let val = this.entries.get(cacheKey);
if (val) {
val.lastUsed = this.counter++;
return [true, val.buffer];
}
let resp = await bucket.get(key, {
range: { offset: offset, length: length },
});
let a = await (resp as R2ObjectBody).arrayBuffer();
let d = new DataView(a);
this.entries.set(cacheKey, {
lastUsed: this.counter++,
buffer: d,
});
if (this.entries.size > 128) {
let minUsed = Infinity;
let minKey = undefined;
this.entries.forEach((val, key) => {
if (val.lastUsed < minUsed) {
minUsed = val.lastUsed;
minKey = key;
}
});
if (minKey) this.entries.delete(minKey);
}
return [false, d];
}
}
let worker_cache = new LRUCache();
const TILE = new RegExp(
/^\/([0-9a-zA-Z\/!\-_\.\*\'\(\)]+)\/(\d+)\/(\d+)\/(\d+).pbf$/
);
export default {
async fetch(
request: Request,
env: Env,
context: ExecutionContext
): Promise<Response> {
let url = new URL(request.url);
let match = url.pathname.match(TILE);
let subrequests = 1;
if (match) {
class TempSource {
getKey() {
return "";
}
async getBytes(offset: number, length: number) {
let result = await worker_cache.get(
env.BUCKET,
match![1] + ".pmtiles",
offset,
length
);
if (!result[0]) subrequests++;
return result[1];
}
}
let source = new TempSource();
let p = new PMTiles(source);
let metadata = await p.metadata();
let entry = await p.getZxy(+match[2], +match[3], +match[4]);
if (entry) {
let tile = await env.BUCKET.get(match![1] + ".pmtiles", {
range: { offset: entry.offset, length: entry.length },
});
let headers = new Headers();
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Content-Type", "application/x-protobuf");
headers.set("X-Pmap-Subrequests", subrequests.toString());
if (metadata.compression === "gzip") {
headers.set("Content-Encoding", "gzip");
}
return new Response((tile as R2ObjectBody).body, {
headers: headers,
encodeBody: "manual",
} as any);
}
}
return new Response("Not Found");
},
};