mirror of
https://github.com/protomaps/PMTiles.git
synced 2026-02-04 19:01:08 +00:00
cloudflare cache API
This commit is contained in:
@@ -14,8 +14,10 @@ import {
|
|||||||
|
|
||||||
interface Env {
|
interface Env {
|
||||||
BUCKET: R2Bucket;
|
BUCKET: R2Bucket;
|
||||||
|
ALLOWED_ORIGINS?: string;
|
||||||
PMTILES_PATH?: string;
|
PMTILES_PATH?: string;
|
||||||
TILE_PATH?: string;
|
TILE_PATH?: string;
|
||||||
|
CACHE_MAX_AGE?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class KeyNotFoundError extends Error {
|
class KeyNotFoundError extends Error {
|
||||||
@@ -101,14 +103,66 @@ export default {
|
|||||||
env: Env,
|
env: Env,
|
||||||
ctx: ExecutionContext
|
ctx: ExecutionContext
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
|
if (request.method.toUpperCase() === "POST")
|
||||||
|
return new Response(undefined, { status: 405 });
|
||||||
|
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const {ok, name, tile, ext} = tile_path(url.pathname, env.TILE_PATH);
|
const { ok, name, tile, ext } = tile_path(url.pathname, env.TILE_PATH);
|
||||||
|
|
||||||
|
const cache = caches.default;
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
let allowed_origin = "";
|
||||||
|
if (typeof env.ALLOWED_ORIGINS !== "undefined") {
|
||||||
|
for (let o of env.ALLOWED_ORIGINS.split(",")) {
|
||||||
|
if (o === request.headers.get("Origin") || o === "*") {
|
||||||
|
allowed_origin = o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cached = await cache.match(request.url);
|
||||||
|
if (cached) {
|
||||||
|
let resp_headers = new Headers(cached.headers);
|
||||||
|
if (allowed_origin)
|
||||||
|
resp_headers.set("Access-Control-Allow-Origin", allowed_origin);
|
||||||
|
resp_headers.set("Vary", "Origin");
|
||||||
|
|
||||||
|
return new Response(cached.body, {
|
||||||
|
headers: resp_headers,
|
||||||
|
status: cached.status,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheableResponse = (
|
||||||
|
body: ArrayBuffer | string | undefined,
|
||||||
|
cacheable_headers: Headers,
|
||||||
|
status: number
|
||||||
|
) => {
|
||||||
|
cacheable_headers.set("Cache-Control", "max-age=" + env.CACHE_MAX_AGE);
|
||||||
|
let cacheable = new Response(body, {
|
||||||
|
headers: cacheable_headers,
|
||||||
|
status: status,
|
||||||
|
});
|
||||||
|
|
||||||
|
// normalize HEAD requests
|
||||||
|
ctx.waitUntil(cache.put(request.url, cacheable));
|
||||||
|
|
||||||
|
let resp_headers = new Headers(cacheable_headers);
|
||||||
|
if (allowed_origin)
|
||||||
|
resp_headers.set("Access-Control-Allow-Origin", allowed_origin);
|
||||||
|
resp_headers.set("Vary", "Origin");
|
||||||
|
return new Response(body, { headers: resp_headers, status: status });
|
||||||
|
};
|
||||||
|
|
||||||
|
const cacheable_headers = new Headers();
|
||||||
const source = new R2Source(env, name);
|
const source = new R2Source(env, name);
|
||||||
const p = new PMTiles(source, CACHE);
|
const p = new PMTiles(source, CACHE);
|
||||||
|
try {
|
||||||
let header = await p.getHeader();
|
const p_header = await p.getHeader();
|
||||||
|
if (tile[0] < p_header.minZoom || tile[0] > p_header.maxZoom) {
|
||||||
|
return cacheableResponse(undefined, cacheable_headers, 404);
|
||||||
|
}
|
||||||
|
|
||||||
for (const pair of [
|
for (const pair of [
|
||||||
[TileType.Mvt, "mvt"],
|
[TileType.Mvt, "mvt"],
|
||||||
@@ -116,43 +170,44 @@ export default {
|
|||||||
[TileType.Jpeg, "jpg"],
|
[TileType.Jpeg, "jpg"],
|
||||||
[TileType.Webp, "webp"],
|
[TileType.Webp, "webp"],
|
||||||
]) {
|
]) {
|
||||||
if (header.tileType === pair[0] && ext !== pair[1]) {
|
if (p_header.tileType === pair[0] && ext !== pair[1]) {
|
||||||
return new Response("Bad request: archive has type ." + pair[1], {
|
return cacheableResponse(
|
||||||
status: 400,
|
"Bad request: archive has type ." + pair[1],
|
||||||
});
|
cacheable_headers,
|
||||||
|
400
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize by checking header min/maxzoom
|
|
||||||
try {
|
|
||||||
const tiledata = await p.getZxy(tile[0], tile[1], tile[2]);
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set("Access-Control-Allow-Origin", "*"); // TODO: make configurable
|
|
||||||
|
|
||||||
switch (header.tileType) {
|
|
||||||
case TileType.Mvt:
|
|
||||||
headers.set("Content-Type", "application/vnd.vector-tile");
|
|
||||||
break;
|
|
||||||
case TileType.Png:
|
|
||||||
headers.set("Content-Type", "image/png");
|
|
||||||
break;
|
|
||||||
case TileType.Jpeg:
|
|
||||||
headers.set("Content-Type", "image/jpeg");
|
|
||||||
break;
|
|
||||||
case TileType.Webp:
|
|
||||||
headers.set("Content-Type", "image/webp");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: optimize by making decompression optional
|
// TODO: optimize by making decompression optional
|
||||||
|
const tiledata = await p.getZxy(tile[0], tile[1], tile[2]);
|
||||||
|
|
||||||
|
switch (p_header.tileType) {
|
||||||
|
case TileType.Mvt:
|
||||||
|
cacheable_headers.set(
|
||||||
|
"Content-Type",
|
||||||
|
"application/vnd.vector-tile"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case TileType.Png:
|
||||||
|
cacheable_headers.set("Content-Type", "image/png");
|
||||||
|
break;
|
||||||
|
case TileType.Jpeg:
|
||||||
|
cacheable_headers.set("Content-Type", "image/jpeg");
|
||||||
|
break;
|
||||||
|
case TileType.Webp:
|
||||||
|
cacheable_headers.set("Content-Type", "image/webp");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (tiledata) {
|
if (tiledata) {
|
||||||
return new Response(tiledata.data, { headers: headers, status: 200 });
|
return cacheableResponse(tiledata.data, cacheable_headers, 200);
|
||||||
} else {
|
} else {
|
||||||
return new Response(undefined, { headers: headers, status: 204 });
|
return cacheableResponse(undefined, cacheable_headers, 204);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof KeyNotFoundError) {
|
if (e instanceof KeyNotFoundError) {
|
||||||
return new Response("Archive not found", { status: 404 });
|
return cacheableResponse("Archive not found", cacheable_headers, 404);
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
name = "pmtiles-cloudflare"
|
name = "pmtiles-cloudflare"
|
||||||
main = "src/index.ts"
|
main = "src/index.ts"
|
||||||
compatibility_date = "2022-10-18"
|
compatibility_date = "2022-10-18"
|
||||||
|
minify = true
|
||||||
|
|
||||||
# Replace the bucket names with your own
|
# Replace the bucket names with your own
|
||||||
r2_buckets = [
|
r2_buckets = [
|
||||||
|
|||||||
Reference in New Issue
Block a user