65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import { Application, Router } from "@oak/oak";
|
|
import { compressOps } from "./compression.ts";
|
|
import { Packet } from "./proto.ts";
|
|
import { CausalTree } from "./sync/ordt/causal-tree.ts";
|
|
import { PlainTextORDT } from "./sync/ordt/plain-text.ts";
|
|
|
|
const app = new Application();
|
|
const router = new Router();
|
|
|
|
const pt = new PlainTextORDT();
|
|
const sockets = new Set<WebSocket>();
|
|
|
|
// simple websocket broadcast
|
|
router.get("/api/connect", ctx => {
|
|
const socket = ctx.upgrade();
|
|
sockets.add(socket);
|
|
|
|
const connectionId = crypto.randomUUID();
|
|
|
|
socket.addEventListener("message", event => {
|
|
if (typeof event.data !== "string") return;
|
|
|
|
const op = JSON.parse(event.data);
|
|
op.at[0] = connectionId;
|
|
pt.apply(op); // mutates op to strong
|
|
const weakOp = CausalTree.toWeakOp(op);
|
|
|
|
for (const other of sockets) {
|
|
if (other === socket) continue;
|
|
other.send(JSON.stringify({ t: "op", op: weakOp }));
|
|
}
|
|
});
|
|
socket.addEventListener("close", () => {
|
|
sockets.delete(socket);
|
|
});
|
|
|
|
const onReady = () => {
|
|
socket.send(
|
|
JSON.stringify({
|
|
t: "init",
|
|
ops: compressOps(pt.operations),
|
|
you: connectionId,
|
|
} satisfies Packet),
|
|
);
|
|
};
|
|
if (socket.readyState === WebSocket.OPEN) {
|
|
onReady();
|
|
} else {
|
|
socket.addEventListener("open", () => onReady());
|
|
}
|
|
});
|
|
|
|
router.get("/:path*", async ctx => {
|
|
try {
|
|
await ctx.send({ root: "./client", index: "index.html" });
|
|
} catch {
|
|
// ignore
|
|
}
|
|
});
|
|
|
|
app.use(router.routes());
|
|
app.use(router.allowedMethods());
|
|
|
|
console.log("Listening at: http://127.0.0.1:3000/ ...");
|
|
app.listen({ port: 3000 });
|