@hereugo/open-collaboration-monaco 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hereugo/open-collaboration-monaco",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "description": "Connect a single Monaco Editor to an Open Collaboration Tools session",
6
6
  "files": [
@@ -40,6 +40,8 @@ export class CollaborationInstance implements Disposable {
40
40
  protected readonly documentDisposables = new Map<string, DisposableCollection>();
41
41
  protected readonly peers = new Map<string, DisposablePeer>();
42
42
  protected readonly throttles = new Map<string, () => void>();
43
+ protected readonly resyncTimestamps = new Map<string, number>();
44
+ protected resyncCooldownMs = 1500;
43
45
  protected readonly decorations = new Map<DisposablePeer, monaco.editor.IEditorDecorationsCollection>();
44
46
  protected readonly usersChangedCallbacks: UsersChangeEvent[] = [];
45
47
  protected readonly fileNameChangeCallbacks: FileNameChangeEvent[] = [];
@@ -113,6 +115,15 @@ export class CollaborationInstance implements Disposable {
113
115
  resyncTimer: 10_000
114
116
  });
115
117
  this.yjsProvider.connect();
118
+ this.connection.onReconnect(() => {
119
+ this.yjsProvider.connect();
120
+ if (!this.isHost && this.options.editor) {
121
+ const model = this.options.editor.getModel();
122
+ if (model) {
123
+ void this.resyncActiveDocument(model);
124
+ }
125
+ }
126
+ });
116
127
 
117
128
  this._fileName = 'myFile.txt';
118
129
  this._workspaceName = this.roomId;
@@ -444,6 +455,12 @@ export class CollaborationInstance implements Disposable {
444
455
  ytextContent = yjsText.toString();
445
456
  } else {
446
457
  ytextContent = await this.readFile();
458
+ if (yjsText.toString() !== ytextContent) {
459
+ this.yjs.transact(() => {
460
+ yjsText.delete(0, yjsText.length);
461
+ yjsText.insert(0, ytextContent);
462
+ });
463
+ }
447
464
  if (this._fileName !== this.previousFileName) {
448
465
  this.previousFileName = this._fileName;
449
466
  this.notifyFileNameChanged(this._fileName);
@@ -451,13 +468,45 @@ export class CollaborationInstance implements Disposable {
451
468
  }
452
469
  if (text !== ytextContent) {
453
470
  this.yjsMutex(() => {
471
+ this.stopPropagation = true;
454
472
  document.setValue(ytextContent);
473
+ this.stopPropagation = false;
455
474
  });
456
475
  }
457
476
  this.registerTextObserver(path, document, yjsText);
458
477
  }
459
478
  }
460
479
 
480
+ private async resyncActiveDocument(document: monaco.editor.ITextModel): Promise<void> {
481
+ if (this.isHost) {
482
+ return;
483
+ }
484
+ const path = this.currentPath ?? this.getProtocolPath(this.getResourceUri(`${this._workspaceName}/${this._fileName}`));
485
+ if (!path) {
486
+ return;
487
+ }
488
+ const now = Date.now();
489
+ const lastResync = this.resyncTimestamps.get(path) ?? 0;
490
+ if (now - lastResync < this.resyncCooldownMs) {
491
+ return;
492
+ }
493
+ this.resyncTimestamps.set(path, now);
494
+ this.currentPath = path;
495
+ const yjsText = this.yjs.getText(path);
496
+ const hostContent = await this.readFile();
497
+ if (yjsText.toString() !== hostContent) {
498
+ this.yjs.transact(() => {
499
+ yjsText.delete(0, yjsText.length);
500
+ yjsText.insert(0, hostContent);
501
+ });
502
+ }
503
+ if (document.getValue() !== hostContent) {
504
+ this.stopPropagation = true;
505
+ document.setValue(hostContent);
506
+ this.stopPropagation = false;
507
+ }
508
+ }
509
+
461
510
  protected registerTextObserver(path: string, document: monaco.editor.ITextModel, yjsText: Y.Text): void {
462
511
  const textObserver = this.documentDisposables.get(path);
463
512
  if (textObserver) {
@@ -525,6 +574,10 @@ export class CollaborationInstance implements Disposable {
525
574
  const yjsText = this.yjs.getText(path);
526
575
  const newContent = yjsText.toString();
527
576
  if (newContent !== document.getValue()) {
577
+ if (!this.isHost) {
578
+ void this.resyncActiveDocument(document);
579
+ return;
580
+ }
528
581
  this.updateDocumentContent(document, newContent);
529
582
  }
530
583
  });