Skip to content

Commit 9320e6f

Browse files
add saving / saved indicator (#167)
1 parent 3ba21cb commit 9320e6f

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

src/components/RealtimeEditor/RealtimeEditor.tsx

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,38 @@ const WEBSOCKET_SERVER = SHOULD_USE_DEV_YJS_SERVER
2626
? 'ws://localhost:1234'
2727
: 'wss://yjs.usaco.guide:443';
2828

29+
const createWebsocketInterceptorClass = (
30+
onMessageSyncHandler: () => void,
31+
onSaveHandler: () => void
32+
) => {
33+
return class WebsocketInterceptor extends WebSocket {
34+
send(data: string | ArrayBuffer | Blob | ArrayBufferView) {
35+
const messageSync = 0; // defined in y-websocket
36+
if (
37+
data instanceof Uint8Array &&
38+
data.length > 0 &&
39+
data[0] === messageSync
40+
) {
41+
console.log(data);
42+
onMessageSyncHandler();
43+
}
44+
super.send(data);
45+
}
46+
47+
set onmessage(f: any) {
48+
const messageSaved = 100; // defined in ide-yjs
49+
super.onmessage = m => {
50+
const decoder = new Uint8Array(m.data);
51+
if (decoder.length > 0 && decoder[0] === messageSaved) {
52+
onSaveHandler();
53+
} else {
54+
f(m);
55+
}
56+
};
57+
}
58+
};
59+
};
60+
2961
const RealtimeEditor = ({
3062
defaultValue,
3163
yjsDocumentId,
@@ -43,7 +75,7 @@ const RealtimeEditor = ({
4375
} | null>(null);
4476

4577
const [connectionStatus, setConnectionStatus] = useState<
46-
'disconnected' | 'connecting' | 'connected'
78+
'disconnected' | 'connecting' | 'saved' | 'saving'
4779
>('disconnected');
4880
const [isSynced, setIsSynced] = useState<boolean>(false);
4981

@@ -58,10 +90,31 @@ const RealtimeEditor = ({
5890
const documentId = yjsDocumentId;
5991

6092
const ydocument = new Y.Doc();
93+
94+
let lastUpdate = 0;
95+
const CustomWebsocketInterceptor = createWebsocketInterceptorClass(
96+
() => {
97+
if (!provider._synced) {
98+
return;
99+
}
100+
101+
// As a sketchy hack, we'll assume every sync message sent
102+
// corresponds to an edit the user made.
103+
lastUpdate = Date.now();
104+
setConnectionStatus('saving');
105+
},
106+
() => {
107+
if (Date.now() - lastUpdate > 1000) {
108+
setConnectionStatus('saved');
109+
}
110+
}
111+
);
112+
61113
const provider = new WebsocketProvider(
62114
WEBSOCKET_SERVER,
63115
documentId,
64-
ydocument
116+
ydocument,
117+
{ WebSocketPolyfill: CustomWebsocketInterceptor }
65118
);
66119

67120
// Set the cursor color
@@ -118,7 +171,7 @@ const RealtimeEditor = ({
118171
provider.on(
119172
'status',
120173
({ status }: { status: 'disconnected' | 'connecting' | 'connected' }) => {
121-
setConnectionStatus(status);
174+
setConnectionStatus(status === 'connected' ? 'saved' : status);
122175
}
123176
);
124177
provider.on('sync', (isSynced: boolean) => {

src/components/editor/EditorConnectionStatusIndicator.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ export default function EditorConnectionStatusIndicator({
1010
connectionStatus,
1111
isSynced,
1212
}: {
13-
connectionStatus: 'disconnected' | 'connecting' | 'connected';
13+
connectionStatus: 'disconnected' | 'connecting' | 'saving' | 'saved';
1414
isSynced: boolean;
1515
}) {
1616
let connectionText;
1717
let statusIndicatorClass;
1818

1919
// for now, our editors are either connecting or connected.
20-
if (connectionStatus === 'connected' && isSynced) {
21-
connectionText = 'Connected';
20+
if (connectionStatus === 'saved' && isSynced) {
21+
connectionText = 'Saved';
2222
statusIndicatorClass = 'bg-green-500';
23+
} else if (connectionStatus == 'saving') {
24+
connectionText = 'Saving...';
25+
statusIndicatorClass = 'bg-yellow-500';
2326
} else {
2427
connectionText = 'Connecting...';
2528
statusIndicatorClass = 'bg-yellow-500';

0 commit comments

Comments
 (0)