Skip to main content
Module

x/fastro/core/handlers.ts

Fast and simple web application framework for deno
Go to Latest
File
import { Fastro, fastroError } from "../mod.ts";import { parse, v4 } from "../deps.ts";import { email_msg, handler_content, service_content, create_handler_content, docker_content, html_content, logo_content,} from "./messages.ts";
function errorHandler(err: Error) { if (err.name === "NotFound") { throw fastroError( "CREATE_SERVER_ERROR", new Error("file `app.json` not found"), ); } if (err.name === "SyntaxError") { throw fastroError( "CREATE_SERVER_ERROR", new Error("file `app.json` invalid"), ); } throw err;}
async function idxHandler() { const cwd = Deno.cwd(); const idx = cwd.concat("/public/index.html"); const file: string = await Deno.readTextFile(idx); return file;}
function checkFileExt(ext: string) { const extension = [ ".html", ".png", ".jpeg", ".js", ".jpg", ".gif", ".svg", ".ico", ".css", ".xml", ".json", ".txt", ]; const e = extension.filter((e) => ext.includes(e)); return e.length > 0;}
async function createServer() { try { const config = await Deno.readTextFile("app.json"); const { logger: loggerEnabled, static: staticEnabled, payload: payloadEnabled, cors: corsEnabled, } = JSON.parse(config); const serverOptions = { logger: loggerEnabled, static: staticEnabled, payload: payloadEnabled, cors: corsEnabled, }; const server = new Fastro(serverOptions);
const cwd = Deno.cwd(); const handlers: Handler[] = []; // deno-lint-ignore no-explicit-any type Handler = { path: string; file: any }; // deno-lint-ignore no-explicit-any const functionList: any[] = []; server .static("/", "./public") .use(async (req, done) => { if (req.url === "/") return req.send(await idxHandler()); if (checkFileExt(req.url)) return done();
const [prefixParamOrHandlerParam, handlerParam] = req.parameter; let fileImport = ""; if (prefixParamOrHandlerParam && !handlerParam) { fileImport = `file://${cwd}/handlers/${prefixParamOrHandlerParam}.ts`; } else if (prefixParamOrHandlerParam && handlerParam) { fileImport = `file://${cwd}/handlers/${prefixParamOrHandlerParam}/${handlerParam}.ts`; }
if (!functionList.includes(fileImport)) { const p = import(fileImport) .then((file) => { handlers.push({ path: fileImport, file }); functionList.push(fileImport); }) .catch((err) => { return req.send("handler not found", 404); }); await Promise.all([p]); } const [h] = handlers.filter((h) => h.path === fileImport); if (h) h.file.handler(req); }); return server; } catch (error) { throw errorHandler(error); }}
export async function serve(port?: number) { const server = await createServer(); const PORT = port ? port : 3000; await server.listen({ port: PORT }, (err) => { if (err) throw err; console.info(`Fastro listen on port`, PORT); });}
export async function createHandler(handlerName: string, prefix?: string) { try { const encoder = new TextEncoder(); const folder = prefix ? `handlers/${prefix}` : "handlers"; await Deno.mkdir(folder, { recursive: true }); const handler = encoder.encode(create_handler_content); const name = handlerName ? handlerName : "handler"; const handlerPath = `${folder}/${name}.ts`; await Deno.writeFile(handlerPath, handler); } catch (error) { console.error("INIT_ERROR", error.message); }}
export async function init(appName?: string) { try { const cwd = Deno.cwd().split("/"); const app = appName ? appName : cwd[cwd.length - 1]; const encoder = new TextEncoder(); const id = v4.generate(); const handlerFolder = "handlers"; const publicFolder = "public"; const serviceFolder = "services";
const config = { app, id, logger: true, static: true, payload: true, cors: true, }; await Deno.mkdir(handlerFolder, { recursive: true }); const data = encoder.encode(JSON.stringify(config, null, "\t")); await Deno.writeFile("app.json", data);
const docker = encoder.encode(docker_content); await Deno.writeFile("Dockerfile", docker);
const handler = encoder.encode(handler_content); const handlerPath = `${handlerFolder}/api.ts`; await Deno.writeFile(handlerPath, handler);
await Deno.mkdir(serviceFolder, { recursive: true }); const service = encoder.encode(service_content); const servicePath = `${serviceFolder}/message_service.ts`; await Deno.writeFile(servicePath, service);
await Deno.mkdir(publicFolder, { recursive: true }); const html = encoder.encode(html_content); const idxPath = `${publicFolder}/index.html`; await Deno.writeFile(idxPath, html);
const logo = encoder.encode(logo_content); const logoPath = `${publicFolder}/logo.svg`; await Deno.writeFile(logoPath, logo);
console.info(config); } catch (error) { console.error("INIT_ERROR", error.message); }}
async function getProjectId() { const p = Deno.run({ cmd: ["gcloud", "config", "list", "--format", "value(core.project)"], stdout: "piped", stderr: "piped", });
const { code } = await p.status(); let str; if (code === 0) { const rawOutput = await p.output(); str = new TextDecoder().decode(rawOutput); } else { const rawError = await p.stderrOutput(); str = new TextDecoder().decode(rawError); } str = str.trim(); return str;}
async function buildHandler(projectId: string) { const tag = `gcr.io/${projectId}/hellofastro`; const p = Deno.run({ cmd: ["gcloud", "builds", "submit", "--tag", tag], });
const { code } = await p.status(); if (code === 0) console.log({ message: "Build Finish" }); else console.error({ message: "Build error" });}
async function cloudRunDeployHandler(projectId: string) { const image = `gcr.io/${projectId}/hellofastro`; const p = Deno.run({ cmd: [ "gcloud", "run", "deploy", "hellofastro", "--image", image, "--platform", "managed", "--allow-unauthenticated", ], });
const { code } = await p.status(); if (code === 0) console.log({ message: "Deploy finish" }); else console.error({ message: "Deploy error" });}
export async function deployHandler() { const projectId = await getProjectId(); await buildHandler(projectId); await cloudRunDeployHandler(projectId);}
export async function getVersion() { const file = await import("../mod.ts"); console.log(file.version.fastro);}
function validateEmail(email: string) { var re = /\S+@\S+\.\S+/; return re.test(email);}
export async function register(email: string) { try { if (!email) return console.info(email_msg); if (!validateEmail(email)) { return console.error({ error: true, message: "invalid email." }); } const url = `${BASE_URL}/register`; const r = await fetch(url, { method: "POST", body: email, }); const res = await r.text(); const credential = JSON.parse(res); if (credential.message === "user already exist") { return console.error({ error: true, message: res }); } const encoder = new TextEncoder(); const data = encoder.encode(res); await Deno.writeFile("fastro.json", data); console.log(JSON.parse(res)); } catch (error) { console.log(error); console.error("ERROR_REGISTER:", error.message); }}
export let BASE_URL: string;
export function getArguments(args: string[]) { const { _: commands, email, port, help, version, app, env, otp, name, prefix, } = parse(args); BASE_URL = env === "local" ? "http://api.fastro.local" : "https://api.fastro.dev"; return { commands, email, port, help, version, app, otp, name, prefix };}