y-socket.io
Version:
Socket IO Connector for Yjs (Inspired by y-websocket)
146 lines (141 loc) • 6.15 kB
JavaScript
"use strict";
var C = Object.create;
var y = Object.defineProperty;
var Y = Object.getOwnPropertyDescriptor;
var _ = Object.getOwnPropertyNames;
var L = Object.getPrototypeOf, N = Object.prototype.hasOwnProperty;
var E = (s, i, e, t) => {
if (i && typeof i == "object" || typeof i == "function")
for (let n of _(i))
!N.call(s, n) && n !== e && y(s, n, { get: () => i[n], enumerable: !(t = Y(i, n)) || t.enumerable });
return s;
};
var p = (s, i, e) => (e = s != null ? C(L(s)) : {}, E(
i || !s || !s.__esModule ? y(e, "default", { value: s, enumerable: !0 }) : e,
s
));
// src/server/server.ts
var U = p(require("http")), D = require("socket.io");
// src/server/y-socket-io.ts
var o = p(require("yjs")), m = p(require("y-protocols/awareness")), v = require("y-leveldb");
// src/server/document.ts
var w = p(require("yjs")), u = p(require("y-protocols/awareness")), O = process.env.GC !== "false" && process.env.GC !== "0", d = class extends w.Doc {
constructor(e, t, n) {
super({ gc: O });
this.onUpdateDoc = (e) => {
var t;
if (((t = this.callbacks) == null ? void 0 : t.onUpdate) != null)
try {
this.callbacks.onUpdate(this, e);
} catch (n) {
console.warn(n);
}
this.namespace.emit("sync-update", e);
};
this.onUpdateAwareness = ({ added: e, updated: t, removed: n }, a) => {
var c;
let l = e.concat(t, n), r = u.encodeAwarenessUpdate(this.awareness, l);
if (((c = this.callbacks) == null ? void 0 : c.onChangeAwareness) != null)
try {
this.callbacks.onChangeAwareness(this, r);
} catch (P) {
console.warn(P);
}
this.namespace.emit("awareness-update", r);
};
this.name = e, this.namespace = t, this.awareness = new u.Awareness(this), this.awareness.setLocalState(null), this.callbacks = n, this.awareness.on("update", this.onUpdateAwareness), this.on("update", this.onUpdateDoc);
}
async destroy() {
var e;
if (((e = this.callbacks) == null ? void 0 : e.onDestroy) != null)
try {
await this.callbacks.onDestroy(this);
} catch (t) {
console.warn(t);
}
this.awareness.off("update", this.onUpdateAwareness), this.off("update", this.onUpdateDoc), this.namespace.disconnectSockets(), super.destroy();
}
};
// src/server/y-socket-io.ts
var S = require("lib0/observable"), h = class extends S.Observable {
constructor(e, t) {
var n;
super();
this._documents = /* @__PURE__ */ new Map();
this._levelPersistenceDir = null;
this.persistence = null;
this.nsp = null;
this.initSyncListeners = (e, t) => {
e.on("sync-step-1", (n, a) => {
a(o.encodeStateAsUpdate(t, new Uint8Array(n)));
}), e.on("sync-update", (n) => {
o.applyUpdate(t, n, null);
});
};
this.initAwarenessListeners = (e, t) => {
e.on("awareness-update", (n) => {
m.applyAwarenessUpdate(t.awareness, new Uint8Array(n), e);
});
};
this.initSocketListeners = (e, t) => {
e.on("disconnect", async () => {
(await e.nsp.allSockets()).size === 0 && (this.emit("all-document-connections-closed", [t]), this.persistence != null && (await this.persistence.writeState(t.name, t), await t.destroy()));
});
};
this.startSynchronization = (e, t) => {
e.emit("sync-step-1", o.encodeStateVector(t), (n) => {
o.applyUpdate(t, new Uint8Array(n), this);
}), e.emit("awareness-update", m.encodeAwarenessUpdate(t.awareness, Array.from(t.awareness.getStates().keys())));
};
this.io = e, this._levelPersistenceDir = (n = t == null ? void 0 : t.levelPersistenceDir) != null ? n : process.env.YPERSISTENCE, this._levelPersistenceDir != null && this.initLevelDB(this._levelPersistenceDir), this.configuration = t;
}
initialize() {
this.nsp = this.io.of(/^\/yjs\|.*$/), this.nsp.use(async (e, t) => {
var n;
return ((n = this.configuration) == null ? void 0 : n.authenticate) == null || await this.configuration.authenticate(e.handshake) ? t() : t(new Error("Unauthorized"));
}), this.nsp.on("connection", async (e) => {
var a;
let t = e.nsp.name.replace(/\/yjs\|/, ""), n = await this.initDocument(t, e.nsp, (a = this.configuration) == null ? void 0 : a.gcEnabled);
this.initSyncListeners(e, n), this.initAwarenessListeners(e, n), this.initSocketListeners(e, n), this.startSynchronization(e, n);
});
}
get documents() {
return this._documents;
}
async initDocument(e, t, n = !0) {
var l;
let a = (l = this._documents.get(e)) != null ? l : new d(e, t, {
onUpdate: (r, c) => this.emit("document-update", [r, c]),
onChangeAwareness: (r, c) => this.emit("awareness-update", [r, c]),
onDestroy: async (r) => {
this._documents.delete(r.name), this.emit("document-destroy", [r]);
}
});
return a.gc = n, this._documents.has(e) || (this.persistence != null && await this.persistence.bindState(e, a), this._documents.set(e, a), this.emit("document-loaded", [a])), a;
}
initLevelDB(e) {
let t = new v.LeveldbPersistence(e);
this.persistence = {
provider: t,
bindState: async (n, a) => {
let l = await t.getYDoc(n), r = o.encodeStateAsUpdate(a);
await t.storeUpdate(n, r), o.applyUpdate(a, o.encodeStateAsUpdate(l)), a.on("update", async (c) => await t.storeUpdate(n, c));
},
writeState: async (n, a) => {
}
};
}
};
// src/server/server.ts
var g, z = (g = process.env.HOST) != null ? g : "localhost", A, f = parseInt(`${(A = process.env.PORT) != null ? A : 1234}`), b = U.default.createServer((s, i) => {
i.writeHead(200, { "Content-Type": "application/json" }), i.end(JSON.stringify({ ok: !0 }));
}), k = new D.Server(b), x = new h(k, {});
x.initialize();
k.on("connection", (s) => {
console.log(`[connection] Connected with user: ${s.id}`), s.on("disconnect", () => {
console.log(`[disconnect] Disconnected with user: ${s.id}`);
});
});
b.listen(f, z, void 0, () => console.log(`Server running on port ${f}`));
//# sourceMappingURL=server.js.map