File size: 2,138 Bytes
8f9c4ef | 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 | import * as Y from 'yjs';
import { Socket } from 'socket.io-client';
export class YjsBinding {
public doc: Y.Doc;
public text: Y.Text;
private socket: Socket;
private fileId: string;
private isLocalUpdate = false;
constructor(socket: Socket, fileId: string) {
this.socket = socket;
this.fileId = fileId;
this.doc = new Y.Doc();
this.text = this.doc.getText('content');
// Broadcast local changes
this.doc.on('update', (update: Uint8Array, origin: any) => {
if (origin !== 'remote') {
this.socket.emit('doc:update', { update: Array.from(update), fileId: this.fileId });
}
});
// Apply remote changes
this.socket.on('doc:sync', (data: { update: number[]; fileId: string }) => {
if (data.fileId !== this.fileId) return;
this.isLocalUpdate = true;
Y.applyUpdate(this.doc, new Uint8Array(data.update), 'remote');
this.isLocalUpdate = false;
});
this.socket.on('doc:state', (data: { state: number[]; fileId: string }) => {
if (data.fileId !== this.fileId) return;
if (data.state.length > 0) {
this.isLocalUpdate = true;
Y.applyUpdate(this.doc, new Uint8Array(data.state), 'remote');
this.isLocalUpdate = false;
}
});
}
requestState(): void { this.socket.emit('doc:request-state', { fileId: this.fileId }); }
getText(): string { return this.text.toString(); }
isRemoteUpdate(): boolean { return this.isLocalUpdate; }
applyMonacoChanges(changes: Array<{ rangeOffset: number; rangeLength: number; text: string }>): void {
this.doc.transact(() => {
const sorted = [...changes].sort((a, b) => b.rangeOffset - a.rangeOffset);
for (const change of sorted) {
if (change.rangeLength > 0) this.text.delete(change.rangeOffset, change.rangeLength);
if (change.text) this.text.insert(change.rangeOffset, change.text);
}
});
}
observe(callback: (event: Y.YTextEvent) => void): void { this.text.observe(callback); }
destroy(): void {
this.doc.destroy();
this.socket.off('doc:sync');
this.socket.off('doc:state');
}
}
export { Y };
|