DenReg/registry/src/http/api.ts

173 lines
4.5 KiB
TypeScript
Raw Normal View History

2020-07-28 12:39:54 +00:00
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("/getapikey", getApiKey, basicauth("api"));
2020-07-28 12:39:54 +00:00
g.post("/package/:name", uploadPackage, basicauth("api"));
}
// async function getApiKey(ctx: ABC.Context) {
// const key = v4.generate();
// await db.api_key.insert({
// user: ctx.customContext.user,
// key,
// createdAt: new Date(),
// lastAccess: undefined,
// lastIP: undefined,
// });
// return {
// key,
// };
// }
2020-07-28 12:39:54 +00:00
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.toLowerCase();
2020-07-28 12:39:54 +00:00
if (!isValidPackageName(packageName)) {
return {
success: false,
message: "Invalid package name",
};
}
2020-07-28 12:39:54 +00:00
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) {
return {
success: false,
message: "No version available in meta.json",
};
2020-07-28 12:39:54 +00:00
}
const packageVersion = meta.version;
console.log("Checking correct version");
if (!isValidFullVersion(packageVersion)) {
return {
success: false,
message: "Invalid version. Version must be in format: 0.0.0",
};
return;
2020-07-28 12:39:54 +00:00
}
console.log("Checking for previous uploads");
let packageMeta = await db.package.findOne({ name: packageName });
console.log(meta, packageMeta);
2020-07-28 12:39:54 +00:00
if (!packageMeta) {
packageMeta = {
name: packageName,
author: meta.author,
description: meta.description,
2020-07-28 12:39:54 +00:00
versions: [],
};
await db.package.insert(packageMeta);
2020-07-28 12:39:54 +00:00
}
console.log("Check if version was uploaded before");
if (packageMeta.versions.find((e) => e === meta.version)) {
return {
success: false,
message: "Version was already uploaded!",
};
2020-07-28 12:39:54 +00:00
}
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.package.update(
2020-07-28 12:39:54 +00:00
{ name: packageName },
{
$set: {
versions: [...packageMeta.versions, packageVersion],
author: meta.author || packageMeta.author,
description: meta.description || packageMeta.description,
},
2020-07-28 12:39:54 +00:00
}
);
console.log("Finished successfully");
return {
success: true,
};
2020-07-28 12:39:54 +00:00
} 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);
}
}