Skip to content

Instantly share code, notes, and snippets.

@mayankchoubey
Last active January 3, 2022 07:21
Show Gist options
  • Save mayankchoubey/a1f47524e0df95c4c573514f1ed04005 to your computer and use it in GitHub Desktop.
Save mayankchoubey/a1f47524e0df95c4c573514f1ed04005 to your computer and use it in GitHub Desktop.
Deno content server - Medium course - section 1
import { API_KEYS_PATH } from "./consts.ts";
let apiKeys: Array<string>=[];
try {
apiKeys=JSON.parse(Deno.readTextFileSync(API_KEYS_PATH));
} catch (e) {}
export function authorize(headers: Headers) {
const authorized=true, notAuthorized=false;
if (!apiKeys.length)
return authorized;
const authHeader=headers.get("Authorization");
if (!authHeader)
return notAuthorized;
const apiKey=authHeader.split(" ")[1];
if (!apiKey)
return notAuthorized;
return apiKeys.includes(apiKey);
}
{
"apiKeysPath": "./test/unit/data/apiKeys.json",
"servePath": "./test/unit/"
}
const cfg=JSON.parse(Deno.readTextFileSync("./cfg.json"));
export const API_KEYS_PATH=cfg.apiKeysPath;
export const SERVE_PATH=cfg.servePath;
export const CONTENT_TYPE_RAW="application/octet-stream";
export const EXTENSION_TO_CONTENT_TYPE: Record<string, string>={
".bin": "application/octet-stream",
".csv": "text/csv",
".doc": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".gz": "application/gzip",
".gif": "image/gif",
".htm": "text/html",
".html": "text/html",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".js": "text/javascript",
".json": "application/json",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".mpeg": "video/mpeg",
".png": "image/png",
".pdf": "application/pdf",
".ppt": "application/vnd.ms-powerpoint",
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".rar": "application/vnd.rar",
".svg": "image/svg+xml",
".tar": "application/x-tar",
".txt": "text/plain",
".wav": "audio/wav",
".xls": "application/vnd.ms-excel",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xml": "application/xml",
".zip": "application/zip",
};
import { authorize } from "./authService.ts";
import { getContent } from "./fileService.ts";
import { Status } from "https://deno.land/std/http/http_status.ts";
import { CONTENT_TYPE_RAW as rawCT, EXTENSION_TO_CONTENT_TYPE as getCT } from "./consts.ts";
import { extname as ext } from "https://deno.land/std/path/mod.ts";
export async function handleRequest(req: Request): Promise<Response> {
const relativePath=(new URL(req.url)).pathname;
if (!authorize(req.headers))
return new Response(null, {status: Status.Unauthorized});
try {
const {len, content}=await getContent(relativePath);
return new Response(content, {
status: 200,
headers: {
"content-length": len.toString(),
"content-type": getCT[ext(relativePath)] || rawCT,
},
});
} catch (err) {
if (err instanceof Deno.errors.NotFound)
return new Response(null, {status: Status.NotFound});
if (err instanceof Deno.errors.BadResource)
return new Response(null, {status: Status.UnprocessableEntity});
}
return new Response(null, {status: Status.InternalServerError});
}
import { readableStreamFromReader as makeStream } from "https://deno.land/std/streams/mod.ts";
import { SERVE_PATH } from "./consts.ts";
export async function getContent(relativePath: string) {
const filePath=SERVE_PATH+relativePath;
const fileData=await Deno.stat(filePath);
if (!fileData.isFile)
throw new Deno.errors.BadResource("Directories cannot be served");
const r=await Deno.open(filePath);
return {
len: fileData.size,
content: makeStream(r),
};
}
import { API_KEYS_PATH, SERVE_PATH } from "./consts.ts";
import { route } from "./router.ts";
import { serve } from "https://deno.land/std/http/mod.ts";
async function checkAccess() {
const servePath=Deno.args[0] || SERVE_PATH || "";
if (!servePath) {
console.error("Error: Serve path not specified in command line or config file");
Deno.exit(1);
}
if ((await Deno.permissions.query({name: "read", path: servePath})).state!=="granted") {
console.error("Error: Missing read permission to", servePath);
Deno.exit(1);
}
if ((await Deno.permissions.query({name: "read", path: API_KEYS_PATH})).state!=="granted") {
console.error("Error: Missing read permission to", API_KEYS_PATH);
Deno.exit(1);
}
}
await checkAccess();
console.log("Content server started...");
serve(route, { port: 8080 });
import { Status } from "https://deno.land/std/http/http_status.ts";
import { handleRequest } from "./controller.ts";
export async function route(req: Request): Promise<Response> {
if (req.method!=="GET")
return new Response(null, {status: Status.MethodNotAllowed});
return await handleRequest(req);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment