This commit is contained in:
Rizky 2023-10-19 16:51:57 +07:00
parent faed51c613
commit 64491439c3
9 changed files with 171 additions and 0 deletions

View File

@ -9,6 +9,7 @@
"@types/mime-types": "^2.1.2",
"esbuild": "^0.19.4",
"mime-types": "^2.1.35",
"msgpackr": "^1.9.9",
"radix3": "^1.1.0"
}
}

View File

@ -9,6 +9,7 @@ import { svLocal } from "./edit/action/sv-local";
import { svdiffRemote } from "./edit/action/svdiff-remote";
import { redo, undo } from "./edit/action/undo-redo";
import { eg } from "./edit/edit-global";
import { syncHandler } from "./sync/sync-handler";
eg.edit = {
site: {},
@ -21,6 +22,7 @@ const site = {
};
export const wsHandler: Record<string, WebSocketHandler<WSData>> = {
"/sync": syncHandler,
"/edit": {
open(ws) {
eg.edit.ws.set(ws, {

View File

@ -0,0 +1,40 @@
import { ServerWebSocket, WebSocketHandler } from "bun";
import { WSData } from "../../../../pkgs/core/server/create";
import { Packr } from "msgpackr";
import { createId } from "@paralleldrive/cuid2";
import { MSG_TO_SERVER } from "./type";
const packr = new Packr({ structuredClone: true });
const conns = new Map<
string,
{
ws: ServerWebSocket<WSData>;
msg: {
pending: Record<string, Promise<any>>;
resolve: Record<string, (result: any) => void>;
};
}
>();
const wconns = new WeakMap<ServerWebSocket<WSData>, string>();
export const syncHandler: WebSocketHandler<WSData> = {
open(ws) {
const id = createId();
conns.set(id, { ws, msg: { pending: {}, resolve: {} } });
wconns.set(ws, id);
ws.sendBinary(packr.pack({ type: "identify", id }));
},
message(ws, raw) {
const conn_id = wconns.get(ws);
if (conn_id) {
const conn = conns.get(conn_id);
if (conn) {
const msg = packr.unpack(Buffer.from(raw)) as MSG_TO_SERVER & {
msg_client_id: string;
};
switch (msg.action) {
}
}
}
},
};

23
app/srv/ws/sync/type.ts Normal file
View File

@ -0,0 +1,23 @@
export enum DType {
Site,
Comp,
Page,
}
export enum ServerAction {
Load,
}
export type MSG_TO_SERVER = {
action: ServerAction.Load;
type: DType;
id: string;
};
export enum ClientAction {
Identify,
}
export type MSG_TO_CLIENT = {
action: ClientAction.Identify;
id: string;
};

View File

@ -13,6 +13,7 @@
"@paralleldrive/cuid2": "2.2.2",
"@parcel/packager-wasm": "^2.10.0",
"@parcel/service-worker": "^2.10.0",
"msgpackr": "^1.9.9",
"@swc/wasm-web": "1.3.94-nightly-20231014.1",
"algoliasearch": "^4.20.0",
"date-fns": "^2.30.0",

View File

@ -0,0 +1,91 @@
import { Packr } from "msgpackr";
import {
ClientAction,
MSG_TO_CLIENT,
MSG_TO_SERVER,
ServerAction,
} from "../../../../srv/ws/sync/type";
import { SyncSite } from "./site";
import { createId } from "@paralleldrive/cuid2";
const packr = new Packr({ structuredClone: true });
export class SyncClient {
private id = "";
private ws: WebSocket;
private wsPending?: Promise<void>;
public connected = false;
public loaded = {
site: new Map<string, SyncSite>(),
};
public site = {
load: async (id: string) => {
this.loaded.site.set(id, new SyncSite(this, id));
},
};
public _internal = {
msg: {
pending: {} as Record<string, Promise<any>>,
resolve: {} as Record<string, (result: any) => void>,
},
send: async (msg: MSG_TO_SERVER) => {
const { resolve, pending } = this._internal.msg;
const msg_client_id = createId();
pending[msg_client_id] = new Promise((done) => {
resolve[msg_client_id] = done;
});
if (this.wsPending) {
await this.wsPending;
}
this.ws.send(packr.pack({ ...msg, msg_client_id: createId() }));
},
};
constructor(ws: WebSocket) {
this.ws = ws;
}
private static instance = null as SyncClient | null;
static connect() {
if (SyncClient.instance) return SyncClient.instance;
const url = new URL(location.href);
url.pathname = "/sync";
url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
const ws = new WebSocket(url.toString());
const client = new SyncClient(ws);
SyncClient.instance = client;
let promise = {
resolve: null as null | (() => void),
};
client.wsPending = new Promise((resolve) => {
promise.resolve = resolve;
});
ws.onopen = () => {
promise.resolve?.();
};
ws.onmessage = async (e) => {
const raw = e.data as Blob;
const msg = packr.unpack(
Buffer.from(await raw.arrayBuffer())
) as MSG_TO_CLIENT & {
msg_server_id: string;
};
if (!client.id) {
if (msg.action === ClientAction.Identify) {
client.id = msg.id;
client.connected = true;
}
} else {
}
};
return client;
}
}

View File

@ -0,0 +1,13 @@
import { DType, ServerAction } from "../../../../srv/ws/sync/type";
import { SyncClient } from "./client";
export class SyncSite {
private c: SyncClient;
private id = "";
public status = "loading" as "loading" | "ready";
constructor(c: SyncClient, id: string) {
this.c = c;
c._internal.send({ type: DType.Site, action: ServerAction.Load, id });
}
}

View File

BIN
bun.lockb

Binary file not shown.