Files
quickdrop/server/api/drops/[id]/chunks/[index].get.ts
2026-08-07 22:13:25 -05:00

73 lines
2.0 KiB
TypeScript

import {
createError,
defineEventHandler,
getRouterParam,
sendStream,
setHeaders,
} from "h3";
import { dropStore, DropStoreError } from "../../../../utils/drop-store";
import { bearerToken, publicHeaders } from "../../../../utils/http";
export default defineEventHandler(async (event) => {
publicHeaders(event);
const token = bearerToken(event);
if (!token)
throw createError({
statusCode: 403,
statusMessage: "A valid lease is required.",
});
const id = String(getRouterParam(event, "id") || "").toUpperCase();
let handle:
| Awaited<ReturnType<typeof dropStore.readChunk>>["handle"]
| undefined;
let stream:
| ReturnType<NonNullable<typeof handle>["createReadStream"]>
| undefined;
let closed = false;
const close = async () => {
if (closed) return;
closed = true;
stream?.destroy();
await handle?.close().catch(() => undefined);
};
const abort = () => {
if (!event.node.res.writableEnded && stream && !stream.destroyed)
stream.destroy(new Error("Client disconnected."));
void close();
};
try {
const chunk = await dropStore.readChunk(
id,
Number(getRouterParam(event, "index")),
token,
);
handle = chunk.handle;
stream = handle.createReadStream();
event.node.res.once("close", abort);
event.node.res.once("finish", close);
setHeaders(event, {
"content-type": "application/octet-stream",
"content-length": chunk.size,
"cache-control": "private, no-store",
});
return await sendStream(event, stream);
} catch (error) {
await close();
if (error instanceof DropStoreError)
throw createError({
statusCode:
error.code === "expired"
? 410
: error.code === "not-found"
? 404
: 403,
statusMessage: error.message,
});
throw error;
} finally {
event.node.res.off("close", abort);
event.node.res.off("finish", close);
await close();
}
});