import { createRouter, RadixRouter } from "radix3"; import { compress, decompress } from "wasm-gzip"; import { deepClone } from "web-utils"; import * as Y from "yjs"; import { registerSiteTypings } from "../../../utils/script/typings"; import { clientStartSync } from "../../../utils/sync/ws-client"; import { w } from "../../../utils/types/general"; import { Loading } from "../../../utils/ui/loading"; import { loadFrontEnd, loadTypings } from "./code-loader"; import { updateComponentMeta } from "./comp/load"; import { EmptySite, PG } from "./ed-global"; import { reloadPage } from "./ed-route"; import { loadSite } from "./ed-site"; import { treeRebuild } from "./tree/build"; import { format } from "date-fns"; const decoder = new TextDecoder(); const page = { list: [] as { id: string; url: string }[], route: null as null | RadixRouter<{ id: string; url: string }>, }; export const loadSession = (p: PG) => { const session = JSON.parse( localStorage.getItem("prasi-session") || "null" ) as { data: { user: { id: string; username: string } } }; if (!session && location.pathname.startsWith("/ed/")) { location.href = "/login"; return ; } if (session?.data?.user) { p.user.id = session.data.user.id; p.user.username = session.data.user.username; } else { p.user.id = "ab1390f5-40d5-448e-a8c3-84b0fb600930"; p.user.username = "anonymous"; } }; export const edInitSync = (p: PG) => { loadSession(p); if (location.pathname.startsWith("/vi/")) { if (page.list.length === 0) { _db.page .findMany({ where: { id_site: params.site_id, is_deleted: false, is_default_layout: false, }, select: { id: true, url: true, }, }) .then((list) => { page.list = list; edInitSync(p); }); return; } if (!page.route) { page.route = createRouter(); for (const e of page.list) { page.route.insert(e.url, e); } } const arrpath = location.pathname.split("/"); const pathname = "/" + arrpath.slice(3).join("/"); if (!params.page_id) { const res = page.route.lookup(pathname); if (res) { params.page_id = res.id; if (res.params) { for (const [k, v] of Object.entries(res.params)) { if (!["site_id", "page_id"].includes(k)) { params[k] = v; } } } } } } if (p.sync) { if (p.site.id === "--loading--") return false; if (params.site_id !== p.site.id) { p.site = deepClone(EmptySite); p.site.id = "--loading--"; p.ui.popup.code.init = false; p.sync.site.load(params.site_id).then(async (site) => { if (site) { await loadSite(p, site, "from-sync"); p.render(); } else { alert("Site not found. redirecting..."); location.href = `/ed/`; } return; }); return false; } if ( !p.page.cur.id && !params.page_id && params.site_id && location.pathname.startsWith("/ed/") ) { _db.page .findFirst({ where: { is_deleted: false, is_default_layout: false, id_site: params.site_id, }, select: { id: true }, }) .then((e) => { if (params.site_id === "_") { alert("asdsa"); return; } if (e) location.href = `/ed/${params.site_id}/${e.id}`; }); return false; } } if (!p.sync && !p.sync_assigned) { p.sync_assigned = true; p.site = deepClone(EmptySite); clientStartSync({ user_id: p.user.id, site_id: params.site_id, page_id: params.page_id, events: { opened() { if (w.offline) { console.log("reconnected!"); w.offline = false; p.ui.syncing = true; p.render(); } else { w.offline = false; p.render(); } }, shakehand(client_id) { p.user.client_id = client_id; console.log(`Prasi connected: ${client_id}`); }, disconnected() { console.log("offline, reconnecting..."); w.offline = true; p.render(); return { reconnect: true, }; }, async editor_start(e) { if (params.site_id !== e.site_id || params.page_id !== e.page_id) { if (!p.page.cur.id) { p.site.id = e.site_id; p.page.cur.id = e.page_id; if (location.pathname.startsWith("/ed/")) { location.href = `/ed/${e.site_id}/${e.page_id}`; } } } else { p.site.id = e.site_id; p.page.cur.id = e.page_id; p.render(); } }, site_updated(site) { for (const [k, v] of Object.entries(site)) { if (k === "js" || k === "js_compiled") { p.site[k] = decoder.decode(decompress(v as any)); } else { (p.site as any)[k] = v; } } p.render(); }, async code_changes({ ts, mode, status }) { if (mode === "frontend") { if (status === "ok") { console.clear(); console.log( `${format(Date.now(), "HH:mm:ss")} 🚧 Code updated from vscode ` ); await loadFrontEnd(p, ts); } else if (status === "building") { console.log( `${format( Date.now(), "HH:mm:ss" )} ⏳ Code changed from vscode, rebuilding...` ); } } else { await loadTypings(p); if (p.ui.monaco) { registerSiteTypings(p.ui.monaco, p); } } await treeRebuild(p); p.render(); }, async remote_svlocal(data) { let doc = null as any; if (data.type === "page" && p.page.cur.id === data.id) { doc = p.page.doc as Y.Doc; } else if (data.type === "comp" && p.comp.list[data.id]) { doc = p.comp.list[data.id].doc; } if (doc && p.sync) { const diff_remote = Y.encodeStateAsUpdate( doc, decompress(data.sv_local) ); const sv_remote = Y.encodeStateVector(doc); const sv = Buffer.from(compress(sv_remote)); const diff = Buffer.from(compress(diff_remote)); const res = await p.sync.yjs.sv_remote( data.type, data.id, sv, diff ); if (res) { Y.applyUpdate(doc, decompress(res.diff), "sv_remote"); if (data.type === "page") { delete p.preview.meta_cache[data.id]; await treeRebuild(p, { note: "sv_remote" }); } else if (data.type === "comp") { const updated = await updateComponentMeta(p, doc, data.id); if (updated) { p.comp.list[data.id].meta = updated.meta; p.comp.list[data.id].tree = updated.tree; } await treeRebuild(p, { note: "sv_remote" }); } p.render(); } } }, }, }).then((e) => { p.sync = e; }); return false; } else { if ( params.page_id !== p.page.cur.id && location.pathname.startsWith("/ed") ) { reloadPage(p, params.page_id, "change page"); return false; } } return true; };