Implement ETag logic for AWS and Cloudflare [#90] (#354)

This commit is contained in:
Brandon Liu
2024-02-07 11:46:05 +08:00
committed by GitHub
parent e86dd554be
commit 5b8627b0d8
2 changed files with 34 additions and 11 deletions

View File

@@ -5,6 +5,7 @@ import {
} from "aws-lambda"; } from "aws-lambda";
import { import {
Compression, Compression,
EtagMismatch,
PMTiles, PMTiles,
RangeResponse, RangeResponse,
ResolvedValueCache, ResolvedValueCache,
@@ -16,7 +17,11 @@ import { pmtiles_path, tileJSON, tile_path } from "../../shared/index";
import { createHash } from "crypto"; import { createHash } from "crypto";
import zlib from "zlib"; import zlib from "zlib";
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; import {
GetObjectCommand,
GetObjectCommandOutput,
S3Client,
} from "@aws-sdk/client-s3";
import { NodeHttpHandler } from "@aws-sdk/node-http-handler"; import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
// the region should default to the same one as the function // the region should default to the same one as the function
@@ -60,7 +65,9 @@ class S3Source implements Source {
signal?: AbortSignal, signal?: AbortSignal,
etag?: string etag?: string
): Promise<RangeResponse> { ): Promise<RangeResponse> {
const resp = await s3client.send( let resp: GetObjectCommandOutput;
try {
resp = await s3client.send(
new GetObjectCommand({ new GetObjectCommand({
// biome-ignore lint: aws api // biome-ignore lint: aws api
Bucket: process.env.BUCKET!, Bucket: process.env.BUCKET!,
@@ -68,8 +75,16 @@ class S3Source implements Source {
Key: pmtiles_path(this.archiveName, process.env.PMTILES_PATH), Key: pmtiles_path(this.archiveName, process.env.PMTILES_PATH),
// biome-ignore lint: aws api // biome-ignore lint: aws api
Range: "bytes=" + offset + "-" + (offset + length - 1), Range: "bytes=" + offset + "-" + (offset + length - 1),
// biome-ignore lint: aws api
IfMatch: etag,
}) })
); );
} catch (e: unknown) {
if (e instanceof Error && (e as Error).name === "PreconditionFailed") {
throw new EtagMismatch();
}
throw e;
}
const arr = await resp.Body?.transformToByteArray(); const arr = await resp.Body?.transformToByteArray();

View File

@@ -1,5 +1,6 @@
import { import {
Compression, Compression,
EtagMismatch,
PMTiles, PMTiles,
RangeResponse, RangeResponse,
ResolvedValueCache, ResolvedValueCache,
@@ -63,12 +64,19 @@ class R2Source implements Source {
pmtiles_path(this.archiveName, this.env.PMTILES_PATH), pmtiles_path(this.archiveName, this.env.PMTILES_PATH),
{ {
range: { offset: offset, length: length }, range: { offset: offset, length: length },
onlyIf: { etagMatches: etag },
} }
); );
if (!resp) { if (!resp) {
throw new KeyNotFoundError("Archive not found"); throw new KeyNotFoundError("Archive not found");
} }
const o = resp as R2ObjectBody; const o = resp as R2ObjectBody;
if (!o.body) {
throw new EtagMismatch();
}
const a = await o.arrayBuffer(); const a = await o.arrayBuffer();
return { return {
data: a, data: a,