1
0
silverbullet/server/server.ts
Zef Hemel 9b1b950c41 Work
2022-03-01 16:57:20 +01:00

134 lines
3.8 KiB
TypeScript

import * as path from "https://deno.land/std@0.125.0/path/mod.ts";
import FileInfo = Deno.FileInfo;
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import { oakCors } from "https://deno.land/x/cors@v1.2.0/mod.ts";
import { readAll } from "https://deno.land/std@0.126.0/streams/mod.ts";
import { exists } from "https://deno.land/std@0.126.0/fs/mod.ts";
import { recursiveReaddir } from "https://deno.land/x/recursive_readdir@v2.0.0/mod.ts";
type PageMeta = {
name: string;
lastModified: number;
};
const fsPrefix = "/fs";
const pagesPath = "../pages";
const fsRouter = new Router();
fsRouter.use(oakCors({ methods: ["OPTIONS", "GET", "PUT", "POST", "DELETE"] }));
fsRouter.get("/", async (context) => {
const localPath = pagesPath;
let fileNames: PageMeta[] = [];
const markdownFiles = (await recursiveReaddir(localPath)).filter(
(file: string) => path.extname(file) === ".md"
);
for (const p of markdownFiles) {
const stat = await Deno.stat(p);
fileNames.push({
name: p.substring(
localPath.length + 1,
p.length - path.extname(p).length
),
lastModified: stat.mtime?.getTime()!,
});
}
context.response.body = JSON.stringify(fileNames);
});
fsRouter.get("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
try {
const stat = await Deno.stat(localPath);
const text = await Deno.readTextFile(localPath);
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
context.response.body = text;
} catch (e) {
context.response.status = 404;
context.response.body = "";
}
});
fsRouter.options("/:page(.*)", async (context) => {
const localPath = `${pagesPath}/${context.params.page}.md`;
try {
const stat = await Deno.stat(localPath);
context.response.headers.set("Content-length", `${stat.size}`);
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
} catch (e) {
// For CORS
context.response.status = 200;
context.response.body = "";
}
});
fsRouter.put("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
const existingPage = await exists(localPath);
let dirName = path.dirname(localPath);
if (!(await exists(dirName))) {
await Deno.mkdir(dirName, {
recursive: true,
});
}
let file;
try {
file = await Deno.create(localPath);
} catch (e) {
console.error("Error opening file for writing", localPath, e);
context.response.status = 500;
context.response.body = e.message;
return;
}
const result = context.request.body({ type: "reader" });
const text = await readAll(result.value);
file.write(text);
file.close();
console.log("Wrote to", localPath);
const stat = await Deno.stat(localPath);
context.response.status = existingPage ? 200 : 201;
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
context.response.body = "OK";
});
fsRouter.delete("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
try {
await Deno.remove(localPath);
} catch (e) {
console.error("Error deleting file", localPath, e);
context.response.status = 500;
context.response.body = e.message;
return;
}
console.log("Deleted", localPath);
context.response.body = "OK";
});
const app = new Application();
app.use(
new Router()
.use(fsPrefix, fsRouter.routes(), fsRouter.allowedMethods())
.routes()
);
app.use(async (context, next) => {
try {
await context.send({
root: "../webapp/dist",
index: "index.html",
});
} catch {
await context.send({ root: "../webapp/dist", path: "index.html" });
// next();
}
});
await app.listen({ port: 2222 });