import type { ABC } from "../deps.ts"; import { extractPackagePath, getFilePath, getFile, getOneOf, getAbsolutePackageVersion, sortVersions, } from "../utils.ts"; import { Hash, Path } from "../deps.ts"; import db, { IPackage } from "../db.ts"; import * as Storage from "../storage.ts"; const MAX_CACHE_AGE = 60 * 30; // 30 Minutes const CACHE_CONTROL = "public, max-age=" + MAX_CACHE_AGE; export default function views(g: ABC.Application) { g.get("/", async (ctx) => { ctx.response.headers.set("cache-control", CACHE_CONTROL); const search = ctx.queryParams.q; let packages: IPackage[] = []; if (search && search !== "") { packages = await db.package.find({ name: RegExp(`${search}`), }); } else { packages = await db.package.find({}); } await ctx.render("index", { packages: packages.reverse(), search, }); const etag = "W/" + Hash.createHash("sha3-256") .update( packages .map((e) => { const sorted = e.versions.sort(sortVersions).reverse(); return e.name + sorted[0]; }) .join(":") ) .toString("base64"); ctx.response.headers.set("cache-control", CACHE_CONTROL); ctx.response.headers.set("E-Tag", etag); }); g.get("/package/:package", async (ctx) => { const [packageName, packageVersion] = extractPackagePath( ctx.params.package ); const pkg = await db.package.findOne({ name: packageName }); if (!pkg) { ctx.response.status = 404; ctx.response.body = "// Package not found!"; return; } const readmeContentRaw = (await getOneOf( pkg.name, packageVersion || pkg.versions.sort(sortVersions).reverse()[0], [pkg.readme, "README.md", "readme.md", "Readme.md"] ))?.data; const readmeContent = readmeContentRaw ? new TextDecoder().decode(readmeContentRaw) : ""; const etag = "W/" + Hash.createHash("sha3-256") .update(`${packageName}:${packageVersion}`) .toString("base64"); await ctx.render("package", { pkg, version: packageVersion, readmeContent }); ctx.response.headers.set("cache-control", CACHE_CONTROL); ctx.response.headers.set("E-Tag", etag); }); async function handleBrowse(ctx: ABC.Context) { const E404 = () => { ctx.response.status = 404; ctx.response.body = "// Not found!"; }; let [packageName, packageVersion] = extractPackagePath( ctx.params.package ); const pkg = await db.package.findOne({ name: packageName }); packageVersion = getAbsolutePackageVersion(pkg, packageVersion); if (!packageVersion) return E404(); const path = ctx.params.path || ""; const fileContent = await getFile(packageName, packageVersion, path); if (fileContent) { await ctx.render("browse_file", { pkg, version: packageVersion, content: new TextDecoder().decode(fileContent.data), ext: Path.extname(path), path: `${packageName}@${packageVersion}/${path}`, }); } else { const filesPath = getFilePath( packageName, packageVersion, path ); if (!filesPath) return E404(); console.log(filesPath); const filesItr = Storage.walkFiles(filesPath); const files: { name: string; size: number }[] = []; const directories: Set<string> = new Set(); let readme: string | null = null; for await (const file of filesItr) { const relPath = Path.posix.relative(filesPath, file.path || ""); console.log({ file, relPath, filesPath }); if (relPath.indexOf("/") >= 0) { directories.add(relPath.split("/")[0]); } else { files.push({ name: relPath, size: -1 }); //TODO: Size is not implemented yet if (relPath.toLowerCase() === "readme.md") { const readmeCont = await getFile( packageName, packageVersion, Path.posix.join(path, relPath) ); if (readmeCont) { readme = new TextDecoder().decode(readmeCont?.data); } } } } await ctx.render("browse_folder", { pkg, version: packageVersion, readme, files, directories: Array.from(directories.values()).map((e) => ({ name: e, })), path: `${packageName}@${packageVersion}/${path}`, }); } } g.get("/browse/:package", handleBrowse); g.get("/browse/:package/*path", handleBrowse); }