-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
103 lines (77 loc) · 2.45 KB
/
server.js
File metadata and controls
103 lines (77 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const path = require("path");
const crypto = require("crypto");
const serverId = crypto.randomUUID();
const redis = require("redis");
const pub = redis.createClient();
const sub = redis.createClient();
pub.connect();
sub.connect();
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
const { applyOperation } = require("./ot/transform");
const connectDB = require("./db/connect");
connectDB();
app.use(express.static(path.join(__dirname, "public")));
io.on("connection", (socket) => {
console.log("New client connected:", socket.id);
const Document = require("./models/Document");
socket.on("join_doc", async (docId) => {
console.log(docId)
socket.join(docId);
socket.docId = docId;
let doc = await Document.findOne({ docId });
if (!doc) {
doc = await Document.create({ docId, content: "", version: 0 });
}
socket.emit("load_doc", {
content: doc.content,
version: doc.version,
});
});
socket.on("text_change", async (incomingOp) => {
const docId = socket.docId;
if (!docId) return;
const doc = await Document.findOne({ docId });
if (!doc) return;
const serverVersion = doc.version;
const clientVersion = incomingOp.version;
if (clientVersion !== serverVersion) {
console.log(
`Version mismatch (client: ${clientVersion}, server: ${serverVersion}) — ignoring op`
);
return;
}
const updatedContent = applyOperation(doc.content, incomingOp);
doc.content = updatedContent;
doc.version += 1;
await doc.save();
const opWithVersion = {
op: incomingOp.op,
pos: incomingOp.pos,
char: incomingOp.char,
version: doc.version,
};
socket.to(docId).emit("receive_op", opWithVersion);
await pub.publish("doc_changes", JSON.stringify({
docId,
op: opWithVersion,
source: serverId, // tag this server as the source
}));
});
socket.on("disconnect", () => {
console.log("Client disconnected:", socket.id);
});
});
sub.subscribe("doc_changes", (message) => {
const { docId, op, source } = JSON.parse(message);
if (source === serverId) return;
io.to(docId).emit("receive_op", op);
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});