From f6ce166b11edb0edfd894b31e9845e5c3a91aad2 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 19 Oct 2024 16:35:44 -0600 Subject: [PATCH] fetch tags --- server/main.ts | 24 +++++++++++++++++++----- server/router.ts | 30 +++++++++++++++++------------- server/tags/getTagDir.ts | 14 ++++++++++++++ server/tags/routes.ts | 31 +++++++++++++++++++++++++++++++ server/util/packVersion.ts | 34 ++++++++++++++++++++++++++++++++++ types.ts | 1 + 6 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 server/tags/getTagDir.ts create mode 100644 server/tags/routes.ts create mode 100644 server/util/packVersion.ts diff --git a/server/main.ts b/server/main.ts index 2de66f6..ecdf611 100644 --- a/server/main.ts +++ b/server/main.ts @@ -3,6 +3,8 @@ import { serveDir, serveFile } from "@std/http/file-server"; import { BearMetalStore } from "@bearmetal/store"; import { ensureDir, ensureFile, exists } from "@std/fs"; import { Router } from "./router.ts"; +import { getPackVersion } from "./util/packVersion.ts"; +import { createTagRoutes } from "./tags/routes.ts"; const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./"; @@ -14,6 +16,19 @@ sockpuppet.addHandler((req: Request) => { return serveFile(req, url.searchParams.get("location") as string); }); +// sockpuppet.addHandler((req: Request) => { +// const method = req.method; +// if (method === "OPTIONS") { +// return new Response(null, { +// status: 200, +// headers: { +// "Access-Control-Allow-Origin": "*", +// "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", +// }, +// }); +// } +// }); + const router = new Router(); router.route("/api/dir") .get(async () => { @@ -171,11 +186,8 @@ router.route("/api/packs") router.route("/api/pack/version") .get(() => { using store = new BearMetalStore(); - const packMeta = Deno.readTextFileSync( - store.get("packlocation") + "/pack.mcmeta", - ); - const packMetaJson = JSON.parse(packMeta); - return new Response(packMetaJson.pack.pack_format.toString(), { + const version = getPackVersion(store); + return new Response(version.toString(), { status: 200, }); }) @@ -210,6 +222,8 @@ router.route("/api/versions") return new Response(JSON.stringify(versions), { status: 200 }); }); +createTagRoutes(router); + sockpuppet.addHandler((req: Request) => { if (new URL(req.url).pathname.startsWith("/api")) return; diff --git a/server/router.ts b/server/router.ts index 06f2962..a67f79b 100644 --- a/server/router.ts +++ b/server/router.ts @@ -1,5 +1,5 @@ export class Router { - private routes: Record = {}; + private routes: Map = new Map(); public route(route: string) { const methods: Record = { @@ -8,8 +8,8 @@ export class Router { put: () => undefined, delete: () => undefined, }; - this.routes[route] = this.routes[route] || []; - this.routes[route].push((r, c) => { + this.routes.set(route, this.routes.get(route) || []); + this.routes.get(route)?.push((r, c) => { switch (r.method) { case "GET": return methods.get?.(r, c); @@ -45,16 +45,20 @@ export class Router { public handle = async (req: Request): Promise => { const url = new URL(req.url); - const route = url.pathname; - if (route in this.routes) { - let res; - for (const handler of this.routes[route]) { - res = await handler(req, { - url, - state: {}, - }); - if (res) { - return res; + for (const [route, handlers] of this.routes.entries()) { + const pattern = new URLPattern({ pathname: route }); + const match = pattern.exec(req.url); + if (match) { + let res; + for (const handler of handlers) { + res = await handler(req, { + url, + state: {}, + params: match.pathname.groups, + }); + if (res) { + return res; + } } } } diff --git a/server/tags/getTagDir.ts b/server/tags/getTagDir.ts new file mode 100644 index 0000000..4880f9b --- /dev/null +++ b/server/tags/getTagDir.ts @@ -0,0 +1,14 @@ +import type { BearMetalStore } from "@bearmetal/store"; +import { getDirName } from "../util/packVersion.ts"; + +export async function getTagDir( + store: BearMetalStore, + namespace: string, + version: number, +) { + // const versionData = JSON.parse(Deno.readTextFileSync(installPath + "pack_versions/" + version + ".json")); + + const tagDir = await getDirName(version, "tags"); + + return `${store.get("packlocation")}/${namespace}/${tagDir}`; +} diff --git a/server/tags/routes.ts b/server/tags/routes.ts new file mode 100644 index 0000000..41dfa94 --- /dev/null +++ b/server/tags/routes.ts @@ -0,0 +1,31 @@ +import { BearMetalStore } from "@bearmetal/store"; +import { getPackVersion } from "../util/packVersion.ts"; +import type { Router } from "../router.ts"; +import { getTagDir } from "./getTagDir.ts"; + +export const createTagRoutes = (router: Router) => { + router.route("/api/pack/:namespace/tags") + .get(async (_, ctx) => { + if (!ctx.params.namespace) { + return new Response("somehow hit the tags endpoint without namespace", { + status: 500, + }); + } + using store = new BearMetalStore(); + + const version = getPackVersion(store); + + const tagDir = await getTagDir(store, ctx.params.namespace, version); + + try { + const tags = Array.from( + Deno.readDirSync( + tagDir, + ), + ); + return new Response(JSON.stringify(tags), { status: 200 }); + } catch { + return new Response("no tags found", { status: 404 }); + } + }); +}; diff --git a/server/util/packVersion.ts b/server/util/packVersion.ts new file mode 100644 index 0000000..482b8d0 --- /dev/null +++ b/server/util/packVersion.ts @@ -0,0 +1,34 @@ +import type { BearMetalStore } from "@bearmetal/store"; + +export function getPackVersion(store: BearMetalStore) { + const packMeta = Deno.readTextFileSync( + store.get("packlocation") + "/pack.mcmeta", + ); + const packMetaJson = JSON.parse(packMeta); + return packMetaJson.pack.pack_format as number; +} + +export async function getDirName(version: number, path: string) { + const { default: versionData } = await import( + "../../pack_versions/" + version + ".json", + { + with: { type: "json" }, + } + ); + + const singular = makeSingular(path); + const plural = makePlural(path); + + console.log("versionData", versionData); + + return versionData && versionData.schema.data[""][singular] || + versionData.schema.data[""][plural]; +} + +function makeSingular(word: string) { + return word.replace(/s$/, ""); +} + +function makePlural(word: string) { + return makeSingular(word) + "s"; +} diff --git a/types.ts b/types.ts index c8eb33d..63d60b0 100644 --- a/types.ts +++ b/types.ts @@ -2,5 +2,6 @@ declare global { interface Context { url: URL; state: Record; + params: Record; } }