First Commit of registry itself
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
133
registry/src/http/api.ts
Normal file
133
registry/src/http/api.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import { ABC, Path, Compress, FS } from "../deps.ts";
|
||||
|
||||
import bucket from "../s3.ts";
|
||||
import { isValidPackageName, basicauth, isValidFullVersion } from "../utils.ts";
|
||||
|
||||
import db, { IPackage } from "../db.ts";
|
||||
|
||||
import { v4 } from "https://deno.land/std/uuid/mod.ts";
|
||||
|
||||
export default function api(g: ABC.Group) {
|
||||
g.get("/", (ctx) => {
|
||||
return { version: "1" };
|
||||
});
|
||||
|
||||
g.post("/package/:name", uploadPackage, basicauth("api"));
|
||||
}
|
||||
|
||||
async function uploadPackage(ctx: ABC.Context) {
|
||||
const reqId = v4.generate();
|
||||
const filename = "./tmp/" + reqId + ".tar";
|
||||
const folder = "./tmp/" + reqId;
|
||||
|
||||
try {
|
||||
const packageName = ctx.params.name;
|
||||
|
||||
if (!isValidPackageName(packageName))
|
||||
throw new Error("Invalid package name");
|
||||
|
||||
console.log("Writing body to tmp file:", filename);
|
||||
const file = await Deno.open(filename, {
|
||||
write: true,
|
||||
create: true,
|
||||
});
|
||||
await Deno.copy(ctx.request.body, file);
|
||||
file.close();
|
||||
|
||||
console.log("Create unpacked folder");
|
||||
|
||||
await Deno.mkdir(folder);
|
||||
|
||||
console.log("Uncompressing tar");
|
||||
|
||||
await Compress.Tar.uncompress(filename, folder);
|
||||
|
||||
console.log("Reading meta.json");
|
||||
|
||||
const fileContent = await Deno.readFile(Path.join(folder, "meta.json"));
|
||||
|
||||
console.log("Parsing meta.json");
|
||||
|
||||
const meta = JSON.parse(new TextDecoder().decode(fileContent));
|
||||
|
||||
console.log("Checking meta.json");
|
||||
|
||||
if (!meta?.version) {
|
||||
throw new Error("No version available in meta.json");
|
||||
}
|
||||
|
||||
const packageVersion = meta.version;
|
||||
|
||||
console.log("Checking correct version");
|
||||
|
||||
if (!isValidFullVersion(packageVersion)) {
|
||||
throw new Error("Invalid version. Version must be in format: 0.0.0");
|
||||
}
|
||||
|
||||
console.log("Checking for previous uploads");
|
||||
|
||||
let packageMeta = await db.findOne({ name: packageName });
|
||||
|
||||
if (!packageMeta) {
|
||||
packageMeta = {
|
||||
name: packageName,
|
||||
versions: [],
|
||||
};
|
||||
|
||||
await db.insert(packageMeta);
|
||||
}
|
||||
|
||||
console.log("Check if version was uploaded before");
|
||||
|
||||
if (packageMeta.versions.find((e) => e === meta.version)) {
|
||||
throw new Error("Version was already uploaded!");
|
||||
}
|
||||
|
||||
const bucketBase = "packages/" + packageName + "/" + packageVersion + "/";
|
||||
|
||||
console.log("Uploading files to S3");
|
||||
|
||||
const walker = FS.walk(folder, {
|
||||
includeFiles: true,
|
||||
includeDirs: false,
|
||||
});
|
||||
|
||||
for await (const file of walker) {
|
||||
const relative = Path.relative(folder, file.path);
|
||||
|
||||
const bucketPath = (bucketBase + relative).replace(/@/g, "§");
|
||||
|
||||
console.log("Uploading file:", file.path, bucketPath, bucketBase);
|
||||
await bucket.putObject(
|
||||
bucketPath,
|
||||
await Deno.readAll(await Deno.open(file.path)),
|
||||
{}
|
||||
);
|
||||
}
|
||||
console.log("Setting new live version");
|
||||
|
||||
//TODO: Better option, since this could error whith multiple upload to the same package
|
||||
await db.update(
|
||||
{ name: packageName },
|
||||
{
|
||||
$set: { versions: [...packageMeta.versions, packageVersion] },
|
||||
}
|
||||
);
|
||||
|
||||
console.log("Finished successfully");
|
||||
} catch (err) {
|
||||
console.error("Error while processing newly uploaded package");
|
||||
console.error(err);
|
||||
return {
|
||||
success: false,
|
||||
message: err.message,
|
||||
};
|
||||
} finally {
|
||||
console.log("Cleanup");
|
||||
await Deno.remove(filename).catch(console.error);
|
||||
await Deno.remove(folder, { recursive: true }).catch(console.error);
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
53
registry/src/http/raw.ts
Normal file
53
registry/src/http/raw.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { ABC } from "../deps.ts";
|
||||
|
||||
import { sortVersions, extractPackagePath } from "../utils.ts";
|
||||
|
||||
import db, { IPackage } from "../db.ts";
|
||||
|
||||
import bucket from "../s3.ts";
|
||||
|
||||
export default function raw(g: ABC.Group) {
|
||||
g.get("/:package/*path", async (ctx) => {
|
||||
console.log(ctx.params, ctx.path);
|
||||
let [packageName, packageVersion] = extractPackagePath(
|
||||
ctx.params.package
|
||||
);
|
||||
|
||||
const meta = await db.findOne({ name: packageName });
|
||||
|
||||
console.log(packageName, await db.findOne({ name: packageName }));
|
||||
|
||||
const E404 = () => {
|
||||
ctx.response.status = 404;
|
||||
ctx.response.body = "Not found!";
|
||||
throw new Error("Not found!");
|
||||
};
|
||||
|
||||
if (!meta || meta.versions.length < 1) return E404();
|
||||
|
||||
const versions = meta.versions.sort(sortVersions).reverse();
|
||||
|
||||
if (!packageVersion) {
|
||||
packageVersion = versions[0];
|
||||
} else {
|
||||
const v = versions.filter((e) =>
|
||||
e.startsWith(packageVersion as string)
|
||||
);
|
||||
if (v.length < 1) return E404();
|
||||
packageVersion = v[0];
|
||||
}
|
||||
|
||||
const bucketPath = (
|
||||
"packages/" +
|
||||
packageName +
|
||||
"/" +
|
||||
packageVersion +
|
||||
"/" +
|
||||
ctx.params.path
|
||||
).replace(/@/g, "§");
|
||||
|
||||
console.log("Getting file from:", bucketPath);
|
||||
|
||||
return (await bucket.getObject(bucketPath))?.body;
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user