Compare commits

..

2 Commits

Author SHA1 Message Date
Fabian Stamm
f69e40ae9e Fixing cache control
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-02 16:42:05 +02:00
Fabian Stamm
cece103504 Enable E-Tags for GUI and RAW 2020-08-02 16:33:41 +02:00
7 changed files with 117 additions and 56 deletions

View File

@ -12,6 +12,7 @@ export * as Path from "https://deno.land/std@0.62.0/path/mod.ts";
export * as FS from "https://deno.land/std@0.62.0/fs/mod.ts"; export * as FS from "https://deno.land/std@0.62.0/fs/mod.ts";
export * as Base64 from "https://deno.land/std@0.62.0/encoding/base64.ts"; export * as Base64 from "https://deno.land/std@0.62.0/encoding/base64.ts";
export * as Hash from "https://deno.land/std@0.62.0/hash/mod.ts";
export * as Compress from "https://git.stamm.me/Deno/DenReg/raw/branch/master/tar/mod.ts"; export * as Compress from "https://git.stamm.me/Deno/DenReg/raw/branch/master/tar/mod.ts";
@ -24,6 +25,6 @@ export {
React, React,
jsx, jsx,
Fragment, Fragment,
} from "https://raw.githubusercontent.com/hibas123/jsx-html/master/mod.ts"; } from "https://raw.githubusercontent.com/apiel/jsx-html/master/mod.ts";
export const Datastore = DS; export const Datastore = DS;

View File

@ -8,12 +8,21 @@ import db, { IPackage } from "../db.ts";
import { v4 } from "https://deno.land/std/uuid/mod.ts"; import { v4 } from "https://deno.land/std/uuid/mod.ts";
export default function api(g: ABC.Group) { export default function api(g: ABC.Group) {
g.get("/", (ctx) => { const cacheControl = (next) => (ctx) => {
return { version: "1" }; ctx.response.headers.set("cache-control", "private");
}); next(ctx);
};
g.get(
"/",
(ctx) => {
return { version: "1" };
},
cacheControl
);
// g.post("/getapikey", getApiKey, basicauth("api")); // g.post("/getapikey", getApiKey, basicauth("api"));
g.post("/package/:name", uploadPackage, basicauth("api")); g.post("/package/:name", uploadPackage, cacheControl, basicauth("api"));
} }
// async function getApiKey(ctx: ABC.Context) { // async function getApiKey(ctx: ABC.Context) {
@ -142,7 +151,7 @@ async function uploadPackage(ctx: ABC.Context) {
} }
console.log("Setting new live version"); console.log("Setting new live version");
//TODO: Better option, since this could error whith multiple upload to the same package //TODO: Better option, since this could error whith multiple uploads to the same package at the same time
await db.package.update( await db.package.update(
{ name: packageName }, { name: packageName },
{ {

View File

@ -1,6 +1,9 @@
import { ABC } from "../deps.ts"; import { ABC } from "../deps.ts";
import { extractPackagePath, getFile } from "../utils.ts"; import { extractPackagePath, getFile } from "../utils.ts";
const MAX_FIXED_CACHE_AGE = 60 * 60 * 24 * 365;
const MAX_FLOATING_CACHE_AGE = 60 * 30;
export default function raw(g: ABC.Group) { export default function raw(g: ABC.Group) {
g.get("/:package/*path", async (ctx) => { g.get("/:package/*path", async (ctx) => {
console.log(ctx.params, ctx.path); console.log(ctx.params, ctx.path);
@ -18,7 +21,22 @@ export default function raw(g: ABC.Group) {
packageVersion, packageVersion,
ctx.params.path ctx.params.path
); );
if (packageVersion && result) {
ctx.response.headers.set(
"cache-control",
"public, max-age=" + MAX_FIXED_CACHE_AGE
);
} else {
ctx.response.headers.set(
"cache-control",
"no-cache, max-age=" + MAX_FLOATING_CACHE_AGE
);
}
if (!result) return E404(); if (!result) return E404();
return result;
ctx.response.headers.set("e-tag", result.etag);
return result.data;
}); });
} }

View File

@ -1,29 +1,64 @@
import { ABC } from "../deps.ts"; import { ABC } from "../deps.ts";
import { basicauth, extractPackagePath } from "../utils.ts"; import { basicauth, extractPackagePath, sortVersions } from "../utils.ts";
import { Hash } from "../deps.ts";
import db, { IPackage } from "../db.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) { export default function views(g: ABC.Application) {
g.get( g.get("/", async (ctx) => {
"/", ctx.response.headers.set("cache-control", CACHE_CONTROL);
async (ctx) => {
return ctx.render("index", {
search: ctx.queryParams["q"],
});
// const render = await IndexView();
// console.log(render);
// ctx.response.body = render;
// ctx.response.status = 200;
},
basicauth("views")
);
g.get(
"/package/:package",
async (ctx) => {
let [packageName, packageVersion] = extractPackagePath(
ctx.params.package
);
return ctx.render("package", { packageName }); const search = ctx.queryParams.q;
},
basicauth("views") let packages: IPackage[] = [];
); if (search && search !== "") {
packages = await db.package.find({
name: RegExp(`${search}`),
});
} else {
packages = await db.package.find({});
}
ctx.render("index", {
packages,
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) => {
let [packageName, packageVersion] = extractPackagePath(
ctx.params.package
);
const pkg = await db.package.findOne({ name: packageName });
const etag =
"W/" +
Hash.createHash("sha3-256")
.update(`${packageName}:${packageVersion}`)
.toString("base64");
await ctx.render("package", { pkg });
ctx.response.headers.set("cache-control", CACHE_CONTROL);
ctx.response.headers.set("E-Tag", etag);
});
} }

View File

@ -95,7 +95,7 @@ export async function getFile(
pkgName: string, pkgName: string,
version: string | null | undefined, version: string | null | undefined,
file: string file: string
): Promise<Uint8Array | null | undefined> { ): Promise<{ etag: string; data: Uint8Array } | null | undefined> {
const meta = await db.package.findOne({ name: pkgName }); const meta = await db.package.findOne({ name: pkgName });
if (!meta || meta.versions.length < 1) return null; if (!meta || meta.versions.length < 1) return null;
@ -122,8 +122,12 @@ export async function getFile(
console.log("Getting file from:", bucketPath); console.log("Getting file from:", bucketPath);
try { try {
const data = (await bucket.getObject(bucketPath))?.body; const res = await bucket.getObject(bucketPath);
return data; if (!res) return undefined;
return {
etag: res.etag,
data: res.body,
};
} catch (err) { } catch (err) {
const msg = err.message as string; const msg = err.message as string;
if (msg.indexOf("404") >= 0) return null; if (msg.indexOf("404") >= 0) return null;

View File

@ -33,16 +33,13 @@ function Package({ pkg }: { pkg: IPackage }) {
import { Main, Menu } from "./_default.tsx"; import { Main, Menu } from "./_default.tsx";
export default async function index({ search }: any) { export default async function index({
let packages: IPackage[] = []; packages,
if (search && search !== "") { search,
packages = await DB.package.find({ }: {
name: RegExp(`${search}`), packages: IPackage[];
}); search: string;
} else { }) {
packages = await DB.package.find({});
}
return ( return (
<Base> <Base>
<Main> <Main>

View File

@ -30,9 +30,7 @@ import { sortVersions, getFile } from "../utils.ts";
import { Main, Menu } from "./_default.tsx"; import { Main, Menu } from "./_default.tsx";
export default async function index({ packageName }: any) { export default async function index({ pkg }: { pkg: IPackage }) {
const pkg = await DB.package.findOne({ name: packageName });
if (!pkg) if (!pkg)
return ( return (
<Base> <Base>
@ -40,15 +38,14 @@ export default async function index({ packageName }: any) {
</Base> </Base>
); );
const readmeContent = await getFile( const readmeContent = await getFile(pkg.name, undefined, "README.md").then(
packageName, (res) => {
undefined, if (res)
"README.md" return Marked.parse(new TextDecoder().decode(res.data))
).then((res) => { .content as string;
if (res) else return undefined;
return Marked.parse(new TextDecoder().decode(res)).content as string; }
else return undefined; );
});
return ( return (
<Base> <Base>