import path from "node:path"; import { listFiles, downloadFile } from "@huggingface/hub"; import { sha256 } from "../utils/sha256"; import { Mod } from "./mod"; import { Server } from "../server/server"; import { ModMetadata } from "./mod-metadata"; export class ModManager { private server: Server; private bucketId = "buckets/NSMP/NSMP-Server-Storage"; private bucketFolder = "mods"; constructor(server: Server) { this.server = server; } public async createModEndpoints(): Promise { const mods: Mod[] = await this.getModList(); this.server.get("/mods/", (_req, res) => { res.send(JSON.stringify(mods)); }); this.server.get("/files/mods/:filename", async (req, res) => { try { const filename = req.params.filename; const mod = mods.find(m => m.filename === filename); if (!mod) { res.status(404).send("Mod not found in index"); return; } const blob = await downloadFile({ repo: this.bucketId, path: mod.path, accessToken: process.env.HF_TOKEN }); if (!blob) { res.status(404).send("Mod not found"); return; } const buffer = Buffer.from(await blob.arrayBuffer()); res.setHeader( "Content-Disposition", `attachment; filename="${filename}"` ); res.setHeader("Content-Type", "application/java-archive"); res.send(buffer); } catch (err) { console.error(err); res.status(500).send("Failed to fetch mod from bucket"); } }); } private async getModList(): Promise { const mods: Mod[] = []; for await (const item of listFiles({ repo: this.bucketId, path: this.bucketFolder, recursive: true, accessToken: process.env.HF_TOKEN })) { if (item.type !== "file" || !item.path.toLowerCase().endsWith(".jar")) { continue; } const jarPath = item.path; const jsonPath = `${jarPath}.json`; const [jarBlob, metadataBlob] = await Promise.all([ downloadFile({ repo: this.bucketId, path: jarPath }), downloadFile({ repo: this.bucketId, path: jsonPath }), ]); if (!jarBlob || !metadataBlob) { continue; } const jarBuffer = Buffer.from(await jarBlob.arrayBuffer()); const metadataContent = Buffer.from(await metadataBlob.arrayBuffer()).toString("utf-8"); const metadata = JSON.parse(metadataContent) as ModMetadata; const hash = sha256(jarBuffer); const filename = path.basename(jarPath); mods.push({ name: metadata.name, filename, path: jarPath, sha256: hash, url: `https://NSMP-NSMP-Server.hf.space/files/mods/${encodeURIComponent(filename)}`, }); } return mods; } }