feat(nbstore): better doc sync logic (#9037)

This commit is contained in:
EYHN
2024-12-10 06:49:21 +00:00
parent 0a7a2c3083
commit 35edf389b5
10 changed files with 305 additions and 99 deletions

View File

@@ -4,19 +4,37 @@ import {
type DocClocks,
type DocRecord,
DocStorage,
type DocStorageOptions,
type DocUpdate,
} from '../../storage';
import { IDBConnection } from './db';
import { IndexedDBLocker } from './lock';
interface ChannelMessage {
type: 'update';
update: DocRecord;
origin?: string;
}
export class IndexedDBDocStorage extends DocStorage {
readonly connection = share(new IDBConnection(this.options));
get db() {
return this.connection.inner;
return this.connection.inner.db;
}
get channel() {
return this.connection.inner.channel;
}
override locker = new IndexedDBLocker(this.connection);
private _lastTimestamp = new Date(0);
constructor(options: DocStorageOptions) {
super(options);
}
private generateTimestamp() {
const timestamp = new Date();
if (timestamp.getTime() <= this._lastTimestamp.getTime()) {
@@ -47,6 +65,17 @@ export class IndexedDBDocStorage extends DocStorage {
origin
);
this.channel.postMessage({
type: 'update',
update: {
docId: update.docId,
bin: update.bin,
timestamp,
editor: update.editor,
},
origin,
} satisfies ChannelMessage);
return { docId: update.docId, timestamp };
}
@@ -144,4 +173,31 @@ export class IndexedDBDocStorage extends DocStorage {
trx.commit();
return updates.length;
}
private docUpdateListener = 0;
override subscribeDocUpdate(
callback: (update: DocRecord, origin?: string) => void
): () => void {
if (this.docUpdateListener === 0) {
this.channel.addEventListener('message', this.handleChannelMessage);
}
this.docUpdateListener++;
const dispose = super.subscribeDocUpdate(callback);
return () => {
dispose();
this.docUpdateListener--;
if (this.docUpdateListener === 0) {
this.channel.removeEventListener('message', this.handleChannelMessage);
}
};
}
handleChannelMessage(event: MessageEvent<ChannelMessage>) {
if (event.data.type === 'update') {
this.emit('update', event.data.update, event.data.origin);
}
}
}