CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/chat/sync.ts
Views: 687
1
import { Map as iMap, fromJS } from "immutable";
2
import type { ChatMessage } from "./types";
3
4
export function initFromSyncDB({ syncdb, store }) {
5
const v = {};
6
for (let x of syncdb.get().toJS()) {
7
x = processSyncDBObj(x);
8
if (x != null) {
9
v[x.date.valueOf()] = x;
10
}
11
}
12
store.setState({
13
messages: fromJS(v),
14
});
15
}
16
17
export function handleSyncDBChange({ syncdb, store, changes }) {
18
if (syncdb == null || store == null || changes == null) {
19
console.warn("handleSyncDBChange: inputs should not be null");
20
return;
21
}
22
changes.map((obj) => {
23
obj = obj.toJS();
24
switch (obj.event) {
25
case "draft": {
26
let drafts = store.get("drafts") ?? (fromJS({}) as any);
27
// used to show that another user is editing a message.
28
const record = syncdb.get_one(obj);
29
if (record == null) {
30
drafts = drafts.delete(obj.sender_id);
31
} else {
32
const sender_id = record.get("sender_id");
33
drafts = drafts.set(sender_id, record);
34
}
35
store.setState({ drafts });
36
return;
37
}
38
39
case "chat": {
40
let changed: boolean = false;
41
let messages = store.get("messages") ?? iMap();
42
obj.date = new Date(obj.date);
43
const record = syncdb.get_one(obj);
44
let x = record?.toJS();
45
if (x == null) {
46
// delete
47
messages = messages.delete(`${obj.date.valueOf()}`);
48
changed = true;
49
} else {
50
x = processSyncDBObj(x);
51
if (x != null) {
52
messages = messages.set(`${x.date.valueOf()}`, fromJS(x));
53
changed = true;
54
}
55
}
56
if (changed) {
57
store.setState({ messages });
58
}
59
return;
60
}
61
62
default:
63
console.warn("unknown chat event: ", obj.event);
64
}
65
});
66
}
67
68
// NOTE: x must be already a plain JS object (.toJS()).
69
// This function mutates x.
70
export function processSyncDBObj(x: ChatMessage): ChatMessage | undefined {
71
if (x.event !== "chat") {
72
// Event used to be used for video chat, etc...; but we have a better approach now, so
73
// all events we care about are chat.
74
return;
75
}
76
if ((x as any).video_chat?.is_video_chat) {
77
// discard/ignore anything else related to the old old video chat approach
78
return;
79
}
80
x.date = new Date(x.date);
81
if ((x.history?.length ?? 0) > 0) {
82
// nontrivial history -- nothing to do
83
} else if ((x as any).payload != null) {
84
// for old chats with payload: content (2014-2016)... plus the script @hsy wrote in the work project ;-(
85
x.history = [];
86
x.history.push({
87
content: (x as any).payload.content,
88
author_id: x.sender_id,
89
date: new Date(x.date).toISOString(),
90
});
91
delete (x as any).payload;
92
} else if ((x as any).mesg != null) {
93
// for old chats with mesg: content (up to 2014)
94
x.history = [];
95
x.history.push({
96
content: (x as any).mesg.content,
97
author_id: x.sender_id,
98
date: new Date(x.date).toISOString(),
99
});
100
delete (x as any).mesg;
101
}
102
if (x.history == null) {
103
x.history = [];
104
}
105
if (!x.editing) {
106
x.editing = {};
107
}
108
x.folding ??= [];
109
x.feedback ??= {};
110
return x;
111
}
112
113