NSMP-Server / src /mods /mods.ts
Franek-Le's picture
Use logger instead of console.log
a484614
Raw
History Blame Contribute Delete
4.46 kB
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 { Logger } from "../logger/logger";
export class ModManager {
private server: Server;
private logger: Logger;
private bucketId = "buckets/NSMP/NSMP-Server-Storage";
private bucketFolder = "mods";
private modCache: Mod[] = [];
private refreshIntervalMs = 60_000; // 1 minute
constructor(server: Server, logger: Logger) {
this.server = server;
this.logger = logger;
}
public async createModEndpoints(): Promise<void> {
await this.refreshModCache();
setInterval(() => {
this.refreshModCache().catch(err => {
this.logger.error("Failed to refresh mod cache:", err);
});
}, this.refreshIntervalMs);
this.server.get("/mods/", async (_req, res) => {
try {
res.send(JSON.stringify(this.modCache));
} catch (err) {
this.logger.error("Failed to list mods:", err);
res.status(500).send("Failed to list mods");
}
});
this.server.get("/files/mods/:filename", async (req, res) => {
try {
const filename = req.params.filename;
const mod = this.modCache.find(
m => m.filename === filename
);
if (!mod) {
res.status(404).send("Mod not found");
return;
}
this.logger.time(`download:${filename}`);
const blob = await downloadFile({
repo: this.bucketId,
path: mod.path,
accessToken: process.env.HF_TOKEN
});
this.logger.timeEnd(`download:${filename}`);
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) {
this.logger.error(err as string);
res.status(500).send("Failed to fetch mod from bucket");
}
});
}
private async refreshModCache(): Promise<void> {
this.logger.time("refreshModCache");
const existing = new Map(
this.modCache.map(mod => [mod.path, mod])
);
const updated: 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 cached = existing.get(item.path);
if (cached) {
updated.push(cached);
continue;
}
this.logger.info(`New mod detected: ${item.path}`);
const jarBlob = await downloadFile({
repo: this.bucketId,
path: item.path,
accessToken: process.env.HF_TOKEN
});
if (!jarBlob) {
continue;
}
const jarBuffer = Buffer.from(
await jarBlob.arrayBuffer()
);
const filename = path.basename(item.path);
updated.push({
name: filename.replace(/\.jar$/i, ""),
filename,
path: item.path,
sha256: sha256(jarBuffer),
url: `https://NSMP-NSMP-Server.hf.space/files/mods/${encodeURIComponent(
filename
)}`
});
}
this.modCache = updated;
this.logger.timeEnd("refreshModCache");
this.logger.info(`Cached ${this.modCache.length} mods`);
}
}