This commit is contained in:
Rizky 2023-10-20 16:14:32 +07:00
parent 8b35fa274e
commit 4de34a8a86
6 changed files with 104 additions and 46 deletions

View File

@ -18,7 +18,7 @@ export default page({
} else { } else {
navigate("/login"); navigate("/login");
} }
}, []); });
return <Loading />; return <Loading />;
}, },

View File

@ -21,9 +21,13 @@ export default page({
user_id: session.data.user.id, user_id: session.data.user.id,
events: { events: {
editor_start(e) { editor_start(e) {
if (params.site_id !== "_" && params.page_id !== "_") {
p.render();
} else {
if (e.site_id && e.page_id) { if (e.site_id && e.page_id) {
navigate(`/ed/${e.site_id}/${e.page_id}`); navigate(`/ed/${e.site_id}/${e.page_id}`);
} }
}
}, },
}, },
}); });

View File

@ -10,7 +10,7 @@ const start = async () => {
let react = { let react = {
root: null as null | ReactRoot, root: null as null | ReactRoot,
}; };
if (!["localhost", "127.0.0.1"].includes(location.hostname)) { if (true || !["localhost", "127.0.0.1"].includes(location.hostname)) {
const sw = await registerServiceWorker(); const sw = await registerServiceWorker();
navigator.serviceWorker.addEventListener("message", (e) => { navigator.serviceWorker.addEventListener("message", (e) => {
if (react.root) { if (react.root) {
@ -125,9 +125,11 @@ const start = async () => {
const swc = navigator.serviceWorker.controller; const swc = navigator.serviceWorker.controller;
if (swc) { if (swc) {
[location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach((url) => {
swc.postMessage({ swc.postMessage({
type: "add-cache", type: "add-cache",
url: location.href, url: url,
});
}); });
if (w.prasiApi && w.prasiApi[base] && w.prasiApi[base].apiEntry) { if (w.prasiApi && w.prasiApi[base] && w.prasiApi[base].apiEntry) {
const routes = Object.entries(w.prasiApi[base].apiEntry).map( const routes = Object.entries(w.prasiApi[base].apiEntry).map(

View File

@ -1,17 +1,19 @@
import { DeepProxy } from "@qiwi/deep-proxy"; import { DeepProxy } from "@qiwi/deep-proxy";
import { xxhash32 } from "hash-wasm"; import { xxhash32 } from "hash-wasm";
import { UseStore, get } from "idb-keyval"; import { UseStore, get, set } from "idb-keyval";
import { Packr } from "msgpackr"; import { Packr } from "msgpackr";
import { stringify } from "safe-stable-stringify"; import { stringify } from "safe-stable-stringify";
import { SyncActions } from "../../../../srv/ws/sync/actions"; import { SyncActions } from "../../../../srv/ws/sync/actions";
import { SyncActionDefinition } from "../../../../srv/ws/sync/actions-def"; import { SyncActionDefinition } from "../../../../srv/ws/sync/actions-def";
import { initIDB } from "./idb"; import { initIDB } from "./idb";
import { SyncType } from "../../../../srv/ws/sync/type"; import { SyncType } from "../../../../srv/ws/sync/type";
import { w } from "../types/general";
const packr = new Packr({ structuredClone: true }); const packr = new Packr({ structuredClone: true });
const conf = { const conf = {
ws: null as null | WebSocket, ws: null as null | WebSocket,
client_id: "", client_id: "",
idb: null as null | UseStore, idb: null as null | UseStore,
event: null as null | ClientEventObject,
}; };
type User = { type User = {
@ -48,7 +50,7 @@ export const clientStartSync = async (arg: {
if (path[0] === "then") path.shift(); if (path[0] === "then") path.shift();
return (...args: any[]) => return (...args: any[]) =>
new Promise((resolve) => { new Promise((resolve) => {
operation({ doAction({
path: path.join("."), path: path.join("."),
resolve, resolve,
args, args,
@ -68,52 +70,95 @@ export const clientStartSync = async (arg: {
}; };
const connect = (user_id: string, event: ClientEventObject) => { const connect = (user_id: string, event: ClientEventObject) => {
return new Promise<WebSocket>((resolve) => { conf.event = event;
if (w.offline) {
return new Promise<void>(async (resolve) => {
resolve();
const eventName = "editor_start";
const data = await loadOfflineMsg("ev", eventName);
if (event[eventName]) {
event[eventName](data);
}
});
} else {
return new Promise<void>((resolve) => {
if (!conf.ws) { if (!conf.ws) {
const url = new URL(location.href); const url = new URL(location.href);
url.pathname = "/sync"; url.pathname = "/sync";
url.protocol = url.protocol === "http:" ? "ws:" : "wss:"; url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
const ws = new WebSocket(url.toString()); const ws = new WebSocket(url.toString());
conf.ws = ws;
ws.onopen = () => { ws.onopen = () => {
ws.send(packr.pack({ type: SyncType.UserID, user_id })); ws.send(packr.pack({ type: SyncType.UserID, user_id }));
conf.ws = ws;
};
ws.onclose = async () => {
w.offline = true;
if (!conf.ws) {
await connect(user_id, event);
resolve();
}
}; };
ws.onmessage = async (e) => { ws.onmessage = async (e) => {
const raw = e.data as Blob; const raw = e.data as Blob;
const msg = packr.unpack(Buffer.from(await raw.arrayBuffer())); const msg = packr.unpack(Buffer.from(await raw.arrayBuffer()));
if (msg.type === SyncType.ClientID) { if (msg.type === SyncType.ClientID) {
conf.client_id = msg.client_id; conf.client_id = msg.client_id;
resolve(ws); resolve();
} else if (msg.type === SyncType.Event) { } else if (msg.type === SyncType.Event) {
const eventName = msg.event as keyof ClientEventObject; const eventName = msg.event as ClientEvent;
if (event[eventName]) { if (event[eventName]) {
if (offlineEvents.includes(eventName)) {
saveOfflineMsg("ev", eventName, msg.data);
}
event[eventName](msg.data); event[eventName](msg.data);
} }
} }
}; };
} }
}); });
}
}; };
const operation = async (arg: { const offlineEvents: ClientEvent[] = ["editor_start"];
const saveOfflineMsg = async (type: "ev", name: ClientEvent, data: any) => {
const idb = conf.idb;
if (idb) {
const hargs = await xxhash32(`${type}-${name}`);
await set(hargs, data, idb);
}
};
const loadOfflineMsg = async (type: "ev", name: ClientEvent) => {
const idb = conf.idb;
if (idb) {
const hargs = await xxhash32(`${type}-${name}`);
return await get(hargs, idb);
}
};
const doAction = <T>(arg: {
path: string; path: string;
resolve: (value: any) => void; resolve: (value: any) => void;
args: any[]; args: any[];
}) => { }) => {
return new Promise<T>(async (resolve) => {
const ws = conf.ws; const ws = conf.ws;
const idb = conf.idb; const idb = conf.idb;
if (idb) { if (idb) {
const sargs = stringify(arg.args); const sargs = stringify(arg.args);
const hargs = await xxhash32(`${arg.path}-${sargs}`); const hargs = await xxhash32(`op-${arg.path}-${sargs}`);
if (ws && ws.readyState === ws.OPEN) { if (w.offline || (ws && ws.readyState === ws.OPEN)) {
// online // online
} else { } else {
// offline // offline
const cache = await get(hargs, idb); const cache = await get(hargs, idb);
console.log(cache); resolve(cache as T);
} }
} }
});
}; };

View File

@ -84,6 +84,13 @@ export const defineWindow = async (awaitServerUrl = true) => {
if (typeof window === "object") { if (typeof window === "object") {
window.addEventListener("popstate", () => { window.addEventListener("popstate", () => {
const sw = navigator.serviceWorker.controller;
if (sw) {
sw.postMessage({
type: "add-cache",
url: location.href,
});
}
if (w.preventPopRender) { if (w.preventPopRender) {
w.preventPopRender = false; w.preventPopRender = false;
return; return;

Binary file not shown.