diff --git a/app/web/src/base/page/all.tsx b/app/web/src/base/page/all.tsx
index 4f5797f9..6cb6e8e5 100644
--- a/app/web/src/base/page/all.tsx
+++ b/app/web/src/base/page/all.tsx
@@ -18,7 +18,7 @@ export default page({
} else {
navigate("/login");
}
- }, []);
+ });
return ;
},
diff --git a/app/web/src/base/page/ed.tsx b/app/web/src/base/page/ed.tsx
index cf88e154..86f6db4a 100644
--- a/app/web/src/base/page/ed.tsx
+++ b/app/web/src/base/page/ed.tsx
@@ -21,8 +21,12 @@ export default page({
user_id: session.data.user.id,
events: {
editor_start(e) {
- if (e.site_id && e.page_id) {
- navigate(`/ed/${e.site_id}/${e.page_id}`);
+ if (params.site_id !== "_" && params.page_id !== "_") {
+ p.render();
+ } else {
+ if (e.site_id && e.page_id) {
+ navigate(`/ed/${e.site_id}/${e.page_id}`);
+ }
}
},
},
diff --git a/app/web/src/index.tsx b/app/web/src/index.tsx
index b2fec886..d105f2fa 100644
--- a/app/web/src/index.tsx
+++ b/app/web/src/index.tsx
@@ -10,7 +10,7 @@ const start = async () => {
let react = {
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();
navigator.serviceWorker.addEventListener("message", (e) => {
if (react.root) {
@@ -125,9 +125,11 @@ const start = async () => {
const swc = navigator.serviceWorker.controller;
if (swc) {
- swc.postMessage({
- type: "add-cache",
- url: location.href,
+ [location.href, "", "/", "/ed", "/ed/_/_", "/login"].forEach((url) => {
+ swc.postMessage({
+ type: "add-cache",
+ url: url,
+ });
});
if (w.prasiApi && w.prasiApi[base] && w.prasiApi[base].apiEntry) {
const routes = Object.entries(w.prasiApi[base].apiEntry).map(
diff --git a/app/web/src/utils/sync/client.ts b/app/web/src/utils/sync/client.ts
index 9f8336dd..60c688a5 100644
--- a/app/web/src/utils/sync/client.ts
+++ b/app/web/src/utils/sync/client.ts
@@ -1,17 +1,19 @@
import { DeepProxy } from "@qiwi/deep-proxy";
import { xxhash32 } from "hash-wasm";
-import { UseStore, get } from "idb-keyval";
+import { UseStore, get, set } from "idb-keyval";
import { Packr } from "msgpackr";
import { stringify } from "safe-stable-stringify";
import { SyncActions } from "../../../../srv/ws/sync/actions";
import { SyncActionDefinition } from "../../../../srv/ws/sync/actions-def";
import { initIDB } from "./idb";
import { SyncType } from "../../../../srv/ws/sync/type";
+import { w } from "../types/general";
const packr = new Packr({ structuredClone: true });
const conf = {
ws: null as null | WebSocket,
client_id: "",
idb: null as null | UseStore,
+ event: null as null | ClientEventObject,
};
type User = {
@@ -48,7 +50,7 @@ export const clientStartSync = async (arg: {
if (path[0] === "then") path.shift();
return (...args: any[]) =>
new Promise((resolve) => {
- operation({
+ doAction({
path: path.join("."),
resolve,
args,
@@ -68,52 +70,95 @@ export const clientStartSync = async (arg: {
};
const connect = (user_id: string, event: ClientEventObject) => {
- return new Promise((resolve) => {
- if (!conf.ws) {
- const url = new URL(location.href);
- url.pathname = "/sync";
- url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
+ conf.event = event;
+ if (w.offline) {
+ return new Promise(async (resolve) => {
+ resolve();
+ const eventName = "editor_start";
+ const data = await loadOfflineMsg("ev", eventName);
- const ws = new WebSocket(url.toString());
- conf.ws = ws;
- ws.onopen = () => {
- ws.send(packr.pack({ type: SyncType.UserID, user_id }));
- };
+ if (event[eventName]) {
+ event[eventName](data);
+ }
+ });
+ } else {
+ return new Promise((resolve) => {
+ if (!conf.ws) {
+ const url = new URL(location.href);
+ url.pathname = "/sync";
+ url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
- ws.onmessage = async (e) => {
- const raw = e.data as Blob;
- const msg = packr.unpack(Buffer.from(await raw.arrayBuffer()));
- if (msg.type === SyncType.ClientID) {
- conf.client_id = msg.client_id;
- resolve(ws);
- } else if (msg.type === SyncType.Event) {
- const eventName = msg.event as keyof ClientEventObject;
- if (event[eventName]) {
- event[eventName](msg.data);
+ const ws = new WebSocket(url.toString());
+
+ ws.onopen = () => {
+ 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) => {
+ const raw = e.data as Blob;
+ const msg = packr.unpack(Buffer.from(await raw.arrayBuffer()));
+ if (msg.type === SyncType.ClientID) {
+ conf.client_id = msg.client_id;
+ resolve();
+ } else if (msg.type === SyncType.Event) {
+ const eventName = msg.event as ClientEvent;
+
+ if (event[eventName]) {
+ if (offlineEvents.includes(eventName)) {
+ saveOfflineMsg("ev", 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 = (arg: {
path: string;
resolve: (value: any) => void;
args: any[];
}) => {
- const ws = conf.ws;
- const idb = conf.idb;
- if (idb) {
- const sargs = stringify(arg.args);
- const hargs = await xxhash32(`${arg.path}-${sargs}`);
+ return new Promise(async (resolve) => {
+ const ws = conf.ws;
+ const idb = conf.idb;
+ if (idb) {
+ const sargs = stringify(arg.args);
+ const hargs = await xxhash32(`op-${arg.path}-${sargs}`);
- if (ws && ws.readyState === ws.OPEN) {
- // online
- } else {
- // offline
- const cache = await get(hargs, idb);
- console.log(cache);
+ if (w.offline || (ws && ws.readyState === ws.OPEN)) {
+ // online
+ } else {
+ // offline
+ const cache = await get(hargs, idb);
+ resolve(cache as T);
+ }
}
- }
+ });
};
diff --git a/pkgs/web-utils/src/define-window.ts b/pkgs/web-utils/src/define-window.ts
index e8552616..01b6191a 100644
--- a/pkgs/web-utils/src/define-window.ts
+++ b/pkgs/web-utils/src/define-window.ts
@@ -84,6 +84,13 @@ export const defineWindow = async (awaitServerUrl = true) => {
if (typeof window === "object") {
window.addEventListener("popstate", () => {
+ const sw = navigator.serviceWorker.controller;
+ if (sw) {
+ sw.postMessage({
+ type: "add-cache",
+ url: location.href,
+ });
+ }
if (w.preventPopRender) {
w.preventPopRender = false;
return;
diff --git a/undefined/lmdb/user-conf.lmdb-lock b/undefined/lmdb/user-conf.lmdb-lock
index aaf8fc45..1969be0b 100644
Binary files a/undefined/lmdb/user-conf.lmdb-lock and b/undefined/lmdb/user-conf.lmdb-lock differ