prasi-api/pkgs/server/create.ts

168 lines
4.6 KiB
TypeScript

import { file } from "bun";
import { existsAsync, inspectAsync, listAsync } from "fs-jetpack";
import { join } from "path";
import { createRouter } from "radix3";
import { dir } from "../utils/dir";
import { g } from "../utils/global";
import { parseArgs } from "./parse-args";
import { serveAPI } from "./serve-api";
import { serveWeb } from "./serve-web";
export const createServer = async () => {
g.router = createRouter({ strictTrailingSlash: true });
g.api = {};
g.cache = {
br: {},
br_timeout: new Set(),
};
const scan = async (path: string, root?: string) => {
const apis = await listAsync(path);
if (apis) {
for (const filename of apis) {
const importPath = join(path, filename);
if (filename.endsWith(".ts")) {
try {
const api = await import(importPath);
let args: string[] = await parseArgs(importPath);
const route = {
url: api._.url,
args,
raw: !!api._.raw,
fn: api._.api,
path: importPath.substring((root || path).length + 1),
};
g.api[filename] = route;
g.router.insert(route.url, g.api[filename]);
} catch (e) {
g.log.warn(
`Failed to import app/srv/api${importPath.substring(
(root || path).length
)}`
);
const f = file(importPath);
if (f.size > 0) {
console.error(e);
} else {
g.log.warn(` ➨ file is empty`);
}
}
} else {
const dir = await inspectAsync(importPath);
if (dir?.type === "dir") {
await scan(importPath, path);
}
}
}
}
};
await scan(dir(`app/srv/api`));
await scan(dir(`pkgs/api`));
g.createServer = (arg) => {
return async (site_id: string) => {
return arg;
};
};
g.server = Bun.serve({
port: g.port,
maxRequestBodySize: 1024 * 1024 * 128,
async fetch(req) {
const url = new URL(req.url);
const handle = async (req: Request) => {
const api = await serveAPI(url, req);
if (api) {
return api;
}
if (g.deploy.index) {
if (g.deploy.router) {
const found = g.deploy.router.lookup(url.pathname);
if (found) {
return await serveWeb({
content: g.deploy.index.render(),
pathname: "index.html",
});
}
}
if (g.deploy.gz) {
const core = g.deploy.gz.code.core;
const site = g.deploy.gz.code.site;
let pathname = url.pathname;
if (url.pathname[0] === "/") pathname = pathname.substring(1);
if (
!pathname ||
pathname === "index.html" ||
pathname === "index.htm"
) {
return await serveWeb({
content: g.deploy.index.render(),
pathname: "index.html",
});
}
let content = "";
if (core[pathname]) content = core[pathname];
else if (site[pathname]) content = site[pathname];
if (content) {
return await serveWeb({ content, pathname });
}
}
}
return new Response(`404 Not Found`, {
status: 404,
statusText: "Not Found",
});
};
if (
!url.pathname.startsWith("/_deploy") &&
!url.pathname.startsWith("/_prasi")
) {
if (
!g.deploy.server &&
(await existsAsync(dir(`app/web/server/index.js`)))
) {
const res = require(dir(`app/web/server/index.js`));
if (res && res.server) {
if (typeof res.server === "function") {
g.deploy.server = await res.server();
} else {
g.deploy.server = res.server;
}
}
}
if (g.deploy.server && g.deploy.index) {
try {
return await g.deploy.server.http({
handle,
mode: "prod",
req,
server: g.server,
url: { pathname: url.pathname, raw: url },
index: g.deploy.index,
});
} catch (e) {
console.error(e);
}
}
}
return handle(req);
},
});
if (process.env.PRASI_MODE === "dev") {
g.log.info(`http://localhost:${g.server.port}`);
} else {
g.log.info(`Started at port: ${g.server.port}`);
}
};