diff --git a/app/web/src/nova/ed/logic/ed-init.ts b/app/web/src/nova/ed/logic/ed-init.ts index 7c42a191..cf458806 100644 --- a/app/web/src/nova/ed/logic/ed-init.ts +++ b/app/web/src/nova/ed/logic/ed-init.ts @@ -1,10 +1,16 @@ import init from "wasm-gzip"; import { jscript } from "../../../utils/script/jscript"; +import { dbClient } from "../../vi/load/db/client-db"; import { PG } from "./ed-global"; +let w = window as unknown as { db: ReturnType }; + export const edInit = async (p: PG) => { p.status = "ready"; + const cur = new URL(location.href); + w.db = dbClient("prasi", `${cur.protocol}//${cur.host}`); + await init(); jscript.init(p.render); diff --git a/app/web/src/nova/vi/load/db/client-db.tsx b/app/web/src/nova/vi/load/db/client-db.tsx new file mode 100644 index 00000000..003df0f1 --- /dev/null +++ b/app/web/src/nova/vi/load/db/client-db.tsx @@ -0,0 +1,111 @@ +import hash_sum from "hash-sum"; +import { fetchViaProxy } from "../proxy"; + +export const dbClient = (name: string, dburl: string) => { + return new Proxy( + {}, + { + get(_, table: string) { + if (table === "_tables") { + return () => { + return fetchSendDb( + name, + { + name, + action: "definition", + table: "*", + }, + dburl + ); + }; + } + + if (table === "_definition") { + return (table: string) => { + return fetchSendDb( + name, + { + name, + action: "definition", + table, + }, + dburl + ); + }; + } + + if (table.startsWith("$")) { + return (...params: any[]) => { + return fetchSendDb( + name, + { + name, + action: "query", + table, + params, + }, + dburl + ); + }; + } + + return new Proxy( + {}, + { + get(_, action: string) { + return (...params: any[]) => { + if (table === "query") { + table = action; + action = "query"; + } + return fetchSendDb( + name, + { + name, + action, + table, + params, + }, + dburl + ); + }; + }, + } + ); + }, + } + ); +}; + +const cachedQueryResult: Record< + string, + { timestamp: number; result: any; promise: Promise } +> = {}; + +export const fetchSendDb = async (name: string, params: any, dburl: string) => { + const base = new URL(dburl); + base.pathname = `/_dbs/${name}`; + if (params.table) { + base.pathname += `/${params.table}`; + } + const url = base.toString(); + + const hsum = hash_sum(params); + const cached = cachedQueryResult[hsum]; + + if (!cached || (cached && Date.now() - cached.timestamp > 1000)) { + cachedQueryResult[hsum] = { + timestamp: Date.now(), + promise: fetchViaProxy(url, params, { + "content-type": "application/json", + }), + result: null, + }; + + const result = await cachedQueryResult[hsum].promise; + cachedQueryResult[hsum].result = result; + return result; + } + + return await cached.promise; +}; diff --git a/app/web/src/nova/vi/load/load-legacy.tsx b/app/web/src/nova/vi/load/load-legacy.tsx index 66896705..d27cc06e 100644 --- a/app/web/src/nova/vi/load/load-legacy.tsx +++ b/app/web/src/nova/vi/load/load-legacy.tsx @@ -1,5 +1,5 @@ import importModule from "../../../render/editor/tools/dynamic-import"; -import { createAPI, createDB, initApi } from "../../../utils/script/init-api"; +import { initApi } from "../../../utils/script/init-api"; export const viLoadLegacy = async (vi: { site: { @@ -43,10 +43,8 @@ export const viLoadLegacy = async (vi: { const path = `/npm/site/${vi.site.id}/site.js`; await importModule(path); if (!vi.site.db.get()) { - vi.site.db.set(createDB(api_url)); } if (!vi.site.api.get()) { - vi.site.api.set(createAPI(api_url)); } const w = window as any; diff --git a/app/web/src/nova/vi/load/proxy.ts b/app/web/src/nova/vi/load/proxy.ts new file mode 100644 index 00000000..c3ea2924 --- /dev/null +++ b/app/web/src/nova/vi/load/proxy.ts @@ -0,0 +1,68 @@ +(BigInt.prototype as any).toJSON = function (): string { + return `BigInt::` + this.toString(); +}; +let w = window; + +export const fetchViaProxy = async ( + url: string, + data?: any, + _headers?: any +) => { + const headers = { ..._headers }; + + let body = data; + let isFile = false; + + const formatSingle = async (data: any) => { + if (!(data instanceof w.FormData || data instanceof w.File)) { + headers["content-type"] = "application/json"; + } else { + if (data instanceof w.File) { + isFile = true; + let ab = await new Promise((resolve) => { + const reader = new FileReader(); + reader.addEventListener("load", (e) => { + resolve(e.target?.result as ArrayBuffer); + }); + reader.readAsArrayBuffer(data); + }); + if (ab) { + data = new File([ab], data.name); + } + } + } + + return data; + }; + + if (Array.isArray(data)) { + body = await Promise.all(data.map((e) => formatSingle(e))); + } else { + body = await formatSingle(data); + } + if (!isFile) { + body = JSON.stringify(body); + } + + const cur = new URL(location.href); + const base = new URL(url); + if (cur.host === base.host) { + const res = await fetch(base.pathname, { + method: "POST", + body, + headers, + }); + return res.json(); + } else { + const res = await fetch(`/_proxy`, { + method: "POST", + body: JSON.stringify({ + url, + body, + headers, + }), + headers: { "content-type": "application/json" }, + }); + return res.json(); + } +}; diff --git a/pkgs/core/api/_proxy.ts b/pkgs/core/api/_proxy.ts new file mode 100644 index 00000000..6ae3541a --- /dev/null +++ b/pkgs/core/api/_proxy.ts @@ -0,0 +1,18 @@ +import { g } from "utils/global"; + +export const _ = { + url: "/_proxy/*", + async api(arg: { + url: string; + method: "POST" | "GET"; + headers: any; + body: any; + }) { + const res = await fetch(arg.url, { + method: arg.method, + headers: arg.headers, + body: arg.body, + }); + return res as any; + }, +};