This commit is contained in:
Rizky 2024-02-09 13:31:03 +07:00
parent 25c860decd
commit 4396c3cd6e
10 changed files with 145 additions and 35 deletions

View File

@ -1,8 +1,12 @@
import { Server } from "bun";
import { site, user } from "dbgen"; import { site, user } from "dbgen";
import { ExecaChildProcess } from "execa"; import { ExecaChildProcess } from "execa";
import { g } from "utils/global";
declare global { declare global {
//@ts-ignore
const Y: typeof Y; const Y: typeof Y;
//@ts-ignore
const syncronize: typeof Y.syncronize; const syncronize: typeof Y.syncronize;
} }
@ -20,6 +24,8 @@ export const glb = global as unknown as {
>; >;
running: Record<string, ExecaChildProcess>; running: Record<string, ExecaChildProcess>;
}; };
server_hook?: typeof g.server_hook;
ws_hook?: typeof g.ws_hook;
npm: { npm: {
page: Record<string, null | { file: Buffer; etag: string }>; page: Record<string, null | { file: Buffer; etag: string }>;
site: Record<string, null | { file: Buffer; etag: string }>; site: Record<string, null | { file: Buffer; etag: string }>;

View File

@ -1,5 +1,32 @@
import { existsAsync } from "fs-jetpack";
import { glb } from "./global"; import { glb } from "./global";
import { code, server } from "./ws/sync/editor/code/util-code";
export const initSrv = async () => { glb.npm = { page: {}, site: {} };
glb.npm = { page: {}, site: {} };
glb.server_hook = async (arg) => {
const url = arg.url;
if (url.pathname.startsWith("/prod")) {
const arr = url.pathname.split("/");
const site_id = arr[2];
if (typeof server[site_id] === "undefined") {
const server_src_path = code.path(site_id, "server", "build", "index.js");
server[site_id] = null;
if (await existsAsync(server_src_path)) {
const svr = require(server_src_path);
if (svr && svr.server) {
server[site_id] = svr.server;
}
}
}
if (server[site_id]) {
try {
return await server[site_id]?.http(arg);
} catch (e) {}
}
}
if (arg.handle) return await arg.handle(arg.req);
}; };

View File

@ -104,7 +104,7 @@ export const code_action: SAction["code"]["action"] = async function (
); );
await Bun.write( await Bun.write(
Bun.file(path.join(dir, "global.d.ts")), Bun.file(path.join(dir, "global.d.ts")),
` `\
import prisma from "./prisma"; import prisma from "./prisma";
import type * as SRVAPI from "gen/srv/api/srv"; import type * as SRVAPI from "gen/srv/api/srv";

View File

@ -5,7 +5,7 @@ import { dirAsync, existsAsync, removeAsync, writeAsync } from "fs-jetpack";
import { DCode } from "../../../../../web/src/utils/types/root"; import { DCode } from "../../../../../web/src/utils/types/root";
import { readDirectoryRecursively } from "../../../../api/site-export"; import { readDirectoryRecursively } from "../../../../api/site-export";
import { docs } from "../../entity/docs"; import { docs } from "../../entity/docs";
import { CodeMode, code } from "./util-code"; import { code, server } from "./util-code";
export const codeBuild = async (id_site: any) => { export const codeBuild = async (id_site: any) => {
const src_path = code.path(id_site, "site", "src"); const src_path = code.path(id_site, "site", "src");
@ -17,7 +17,26 @@ export const codeBuild = async (id_site: any) => {
if (!code.esbuild[id_site].server) { if (!code.esbuild[id_site].server) {
const server_main = code.path(id_site, "site", "src", "server.ts"); const server_main = code.path(id_site, "site", "src", "server.ts");
if (!(await existsAsync(server_main))) { if (!(await existsAsync(server_main))) {
await writeAsync(server_main, ""); await writeAsync(
server_main,
`\
import { Server, WebSocketHandler } from "bun";
export const server: {
ws?: WebSocketHandler<{ url: string }>;
http: (arg: {
url: URL;
req: Request;
server: Server;
handle: (req: Request) => Promise<Response>;
}) => Promise<Response>;
} = {
async http({ req, handle, url, server }) {
return await handle(req);
},
};
`
);
const bun_types = Bun.spawn({ const bun_types = Bun.spawn({
cmd: ["npm", "i", "-D", "@types/bun"], cmd: ["npm", "i", "-D", "@types/bun"],
cwd: code.path(id_site, "site", "src"), cwd: code.path(id_site, "site", "src"),
@ -53,6 +72,21 @@ export const codeBuild = async (id_site: any) => {
type: "cjs", type: "cjs",
}, },
}), }),
{
name: "prasi",
setup(setup) {
setup.onEnd(async (res) => {
const server_src_path = code.path(id_site, "server", "build", "index.js");
server[id_site] = null;
if (await existsAsync(server_src_path)) {
const svr = require(server_src_path);
if (svr && svr.server) {
server[id_site] = svr.server;
}
}
});
},
},
], ],
}); });
const esbuild = code.esbuild[id_site].server; const esbuild = code.esbuild[id_site].server;

View File

@ -33,7 +33,7 @@ export const prepCodeSnapshot = async (id_site: string, mode: CodeMode) => {
if (dcode) { if (dcode) {
if (!dcode.build[mode]) { if (!dcode.build[mode]) {
const build_dir = code.path(id_site, mode, "build"); const build_dir = code.path(id_site, mode, "build");
await codeBuild(id_site, mode); await codeBuild(id_site);
dcode.build[mode] = codeLoad(id_site, build_dir); dcode.build[mode] = codeLoad(id_site, build_dir);
const doc = dcode.build[mode] as Doc; const doc = dcode.build[mode] as Doc;
if (doc) { if (doc) {

View File

@ -1,9 +1,22 @@
import { Server, WebSocketHandler } from "bun";
import { dir } from "dir"; import { dir } from "dir";
import { BuildContext } from "esbuild"; import { BuildContext } from "esbuild";
import { dirAsync, exists, existsAsync, writeAsync } from "fs-jetpack"; import { dirAsync, exists, existsAsync, writeAsync } from "fs-jetpack";
import { dirname } from "path"; import { dirname } from "path";
export type CodeMode = "site" | "server"; export type CodeMode = "site" | "server";
type PrasiServer = {
ws?: WebSocketHandler<{ url: string }>;
http: (arg: {
url: URL;
req: Request;
server: Server;
handle: (req: Request) => Promise<undefined | Response>;
}) => Promise<Response>;
};
export const server = {} as Record<string, null | PrasiServer>;
export const code = { export const code = {
path(id_site: string, mode: CodeMode, type: "src" | "build", path?: string) { path(id_site: string, mode: CodeMode, type: "src" | "build", path?: string) {
let file_path = ""; let file_path = "";
@ -15,6 +28,7 @@ export const code = {
package_deps: (path: string) => { package_deps: (path: string) => {
const file = Bun.file(path); const file = Bun.file(path);
}, },
server: {} as Record<string, {}>,
esbuild: {} as Record<string, Record<CodeMode, null | BuildContext>>, esbuild: {} as Record<string, Record<CodeMode, null | BuildContext>>,
prep(id_site: string, mode: CodeMode) { prep(id_site: string, mode: CodeMode) {
if (exists(dir.data(""))) { if (exists(dir.data(""))) {

View File

@ -1,23 +1,23 @@
import { createId } from "@paralleldrive/cuid2";
import { dir } from "dir";
import { writeAsync } from "fs-jetpack";
import { parcelBuild } from "utils/parcel"; import { parcelBuild } from "utils/parcel";
import { syncActionDefinition } from "utils/sync-def";
import { snapshot } from "../../app/srv/ws/sync/entity/snapshot";
import { user } from "../../app/srv/ws/sync/entity/user";
import { prepareApiRoutes } from "./server/api/api-scan";
import { watchApiRoutes } from "./server/api/api-watch";
import { prepareAPITypes } from "./server/api/prep-api-ts"; import { prepareAPITypes } from "./server/api/prep-api-ts";
import { startDevWatcher } from "./utils/dev-watcher"; import { startDevWatcher } from "./utils/dev-watcher";
import { ensureNotRunning } from "./utils/ensure"; import { ensureNotRunning } from "./utils/ensure";
import { g } from "./utils/global"; import { g } from "./utils/global";
import { createLogger } from "./utils/logger"; import { createLogger } from "./utils/logger";
import { preparePrisma } from "./utils/prisma"; import { preparePrisma } from "./utils/prisma";
import { syncActionDefinition } from "utils/sync-def";
import { user } from "../../app/srv/ws/sync/entity/user";
import { snapshot } from "../../app/srv/ws/sync/entity/snapshot";
import { initSrv } from "../../app/srv/init";
import { createId } from "@paralleldrive/cuid2";
import { prepareApiRoutes } from "./server/api/api-scan";
import { writeAsync } from "fs-jetpack";
import { dir } from "dir";
import { watchApiRoutes } from "./server/api/api-watch";
// import "../docker-prep"; // import "../docker-prep";
g.status = "init"; g.status = "init";
await writeAsync( await writeAsync(
dir.path("app/web/timestamp.ts"), dir.path("app/web/timestamp.ts"),
`export const version = "${createId().substring(0, 7)}";` `export const version = "${createId().substring(0, 7)}";`
@ -57,10 +57,10 @@ if (!db) {
}); });
} }
} }
await import("../../app/srv/init");
await prepareApiRoutes(); await prepareApiRoutes();
if (!g.apiPrepared) { if (!g.apiPrepared) {
await initSrv();
await syncActionDefinition(); await syncActionDefinition();
g.log.info("WS Action defined"); g.log.info("WS Action defined");
await prepareAPITypes(); await prepareAPITypes();

View File

@ -29,29 +29,37 @@ export const createServer = async () => {
async fetch(req, server) { async fetch(req, server) {
const url = new URL(req.url); const url = new URL(req.url);
if (wsHandler[url.pathname]) { const handle = async (req: Request) => {
if ( if (wsHandler[url.pathname]) {
server.upgrade(req, { if (
data: { server.upgrade(req, {
url: new URL(req.url), data: {
}, url: new URL(req.url),
}) },
) { })
return; ) {
return;
}
return new Response("Upgrade failed :(", { status: 500 });
}
if (serveStatic.exists(url)) {
return serveStatic.serve(url);
}
const api_response = await serveAPI.serve(url, req);
if (api_response) {
return api_response;
} }
return new Response("Upgrade failed :(", { status: 500 });
}
if (serveStatic.exists(url)) {
return serveStatic.serve(url); return serveStatic.serve(url);
} };
const api_response = await serveAPI.serve(url, req); if (g.server_hook) {
if (api_response) { return await g.server_hook({ url, req, server, handle });
return api_response; } else {
return await handle(req);
} }
return serveStatic.serve(url);
}, },
}); });

View File

@ -1,5 +1,6 @@
import { WebSocketHandler } from "bun"; import { WebSocketHandler } from "bun";
import { WSData } from "./create"; import { WSData } from "./create";
import { g } from "utils/global";
export const serveWS: ( export const serveWS: (
wsHandler: Record<string, WebSocketHandler<WSData>> wsHandler: Record<string, WebSocketHandler<WSData>>
@ -8,9 +9,15 @@ export const serveWS: (
maxPayloadLength: 9999999, maxPayloadLength: 9999999,
closeOnBackpressureLimit: true, closeOnBackpressureLimit: true,
drain(ws) { drain(ws) {
if (g.ws_hook && g.ws_hook.drain) {
return g.ws_hook.drain(ws);
}
// console.log("Backpressure relieved..."); // console.log("Backpressure relieved...");
}, },
close(ws, code, reason) { close(ws, code, reason) {
if (g.ws_hook && g.ws_hook.close) {
g.ws_hook.close(ws, code, reason);
}
const pathname = ws.data.url.pathname; const pathname = ws.data.url.pathname;
if (wsHandler[pathname]) { if (wsHandler[pathname]) {
const close = wsHandler[pathname].close; const close = wsHandler[pathname].close;
@ -20,6 +27,9 @@ export const serveWS: (
} }
}, },
message(ws, message) { message(ws, message) {
if (g.ws_hook && g.ws_hook.message) {
g.ws_hook.message(ws, message);
}
const pathname = ws.data.url.pathname; const pathname = ws.data.url.pathname;
if (wsHandler[pathname]) { if (wsHandler[pathname]) {
const msg = wsHandler[pathname].message; const msg = wsHandler[pathname].message;
@ -29,6 +39,9 @@ export const serveWS: (
} }
}, },
open(ws) { open(ws) {
if (g.ws_hook && g.ws_hook.open) {
g.ws_hook.open(ws);
}
const pathname = ws.data.url.pathname; const pathname = ws.data.url.pathname;
if (wsHandler[pathname]) { if (wsHandler[pathname]) {
const open = wsHandler[pathname].open; const open = wsHandler[pathname].open;

View File

@ -1,9 +1,10 @@
import { Server, Subprocess } from "bun"; import { Server, Subprocess, WebSocketHandler } from "bun";
import { Logger } from "pino"; import { Logger } from "pino";
import { RadixRouter } from "radix3"; import { RadixRouter } from "radix3";
import { syncronize } from "y-pojo"; import { syncronize } from "y-pojo";
import type * as Y from "yjs"; import type * as Y from "yjs";
import { PrismaClient } from "../../../app/db/db"; import { PrismaClient } from "../../../app/db/db";
import { WSData } from "../server/create";
type SingleRoute = { type SingleRoute = {
url: string; url: string;
@ -14,6 +15,13 @@ type SingleRoute = {
export const g = global as unknown as { export const g = global as unknown as {
status: "init" | "ready"; status: "init" | "ready";
server_hook?: (arg: {
url: URL;
req: Request;
server: Server;
handle: (req: Request) => Promise<Response | undefined>;
}) => Promise<Response | undefined>;
ws_hook?: WebSocketHandler<WSData>;
_db: PrismaClient; _db: PrismaClient;
dburl: string; dburl: string;
mode: "dev" | "prod"; mode: "dev" | "prod";