Skip to content

Commit 4dae780

Browse files
committed
fix #7969 -- ghost cursor: if a user's clock is significantly off the first time they use cocalc they may see a ghost cursor
1 parent 62e3199 commit 4dae780

File tree

1 file changed

+25
-9
lines changed

1 file changed

+25
-9
lines changed

src/packages/sync/editor/generic/sync-doc.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,14 @@ export class SyncDoc extends EventEmitter {
582582
user_id: this.my_user_id,
583583
locs,
584584
};
585-
if (!side_effect) {
586-
x.time = this.client.server_time();
585+
const now = this.client.server_time();
586+
if (!side_effect || (x.time ?? now) >= now) {
587+
// the now comparison above is in case the cursor time
588+
// is in the future (due to clock issues) -- always fix that.
589+
x.time = now;
587590
}
588591
if (x.time != null) {
592+
// will actually always be non-null due to above
589593
this.cursor_last_time = x.time;
590594
}
591595
this.cursors_table.set(x, "none");
@@ -1904,18 +1908,30 @@ export class SyncDoc extends EventEmitter {
19041908
) {
19051909
map = map.delete(account_id);
19061910
}
1907-
if (maxAge) {
1908-
// Remove any old cursors, where "old" is by default more than 1 minute old, since
1909-
// old cursors are not useful
1910-
const now = Date.now();
1911-
for (const [client_id, value] of map as any) {
1912-
const time = value.get("time");
1911+
// Remove any old cursors, where "old" is by default more than maxAge old.
1912+
const now = Date.now();
1913+
for (const [client_id, value] of map as any) {
1914+
const time = value.get("time");
1915+
if (time == null) {
1916+
// this should always be set.
1917+
map = map.delete(client_id);
1918+
continue;
1919+
}
1920+
if (maxAge) {
19131921
// we use abs to implicitly exclude a bad value that is somehow in the future,
19141922
// if that were to happen.
1915-
if (time == null || Math.abs(now - time.valueOf()) >= maxAge) {
1923+
if (Math.abs(now - time.valueOf()) >= maxAge) {
19161924
map = map.delete(client_id);
1925+
continue;
19171926
}
19181927
}
1928+
if (time >= now + 10 * 1000) {
1929+
// We *always* delete any cursors more than 10 seconds in the future, since
1930+
// that can only happen if a client inserts invalid data (e.g., clock not
1931+
// yet synchronized). See https://github.com/sagemathinc/cocalc/issues/7969
1932+
map = map.delete(client_id);
1933+
continue;
1934+
}
19191935
}
19201936
return map;
19211937
};

0 commit comments

Comments
 (0)