feat(nbstore): add doc sync frontend (#9070)

This commit is contained in:
EYHN
2024-12-11 07:53:25 +00:00
parent eee0ed45ee
commit 331e674e8b
8 changed files with 499 additions and 58 deletions
+15 -7
View File
@@ -4,6 +4,8 @@ import type { BlobStorage } from '../../storage';
import { MANUALLY_STOP, throwIfAborted } from '../../utils/throw-if-aborted';
export class BlobSyncEngine {
private abort: AbortController | null = null;
constructor(
readonly local: BlobStorage,
readonly remotes: BlobStorage[]
@@ -72,18 +74,24 @@ export class BlobSyncEngine {
}
}
async run(signal?: AbortSignal) {
if (signal?.aborted) {
return;
start() {
if (this.abort) {
this.abort.abort();
}
try {
await this.sync(signal);
} catch (error) {
const abort = new AbortController();
this.abort = abort;
this.sync(abort.signal).catch(error => {
if (error === MANUALLY_STOP) {
return;
}
console.error('sync blob error', error);
}
});
}
stop() {
this.abort?.abort();
this.abort = null;
}
}
+28 -8
View File
@@ -2,17 +2,37 @@ import type { DocStorage, SyncStorage } from '../../storage';
import { DocSyncPeer } from './peer';
export class DocSyncEngine {
private readonly peers: DocSyncPeer[];
private abort: AbortController | null = null;
constructor(
readonly local: DocStorage,
readonly sync: SyncStorage,
readonly peers: DocStorage[]
) {}
readonly remotes: DocStorage[]
) {
this.peers = remotes.map(remote => new DocSyncPeer(local, sync, remote));
}
async run(signal?: AbortSignal) {
await Promise.all(
this.peers.map(peer =>
new DocSyncPeer(this.local, this.sync, peer).mainLoop(signal)
)
);
start() {
if (this.abort) {
this.abort.abort();
}
const abort = new AbortController();
this.abort = abort;
Promise.allSettled(
this.peers.map(peer => peer.mainLoop(abort.signal))
).catch(error => {
console.error(error);
});
}
stop() {
this.abort?.abort();
this.abort = null;
}
addPriority(id: string, priority: number) {
const undo = this.peers.map(peer => peer.addPriority(id, priority));
return () => undo.forEach(fn => fn());
}
}
@@ -610,11 +610,6 @@ export class DocSyncPeer {
this.statusUpdatedSubject$.next(job.docId);
}
setPriority(docId: string, priority: number) {
this.prioritySettings.set(docId, priority);
return this.status.jobDocQueue.setPriority(docId, priority);
}
addPriority(id: string, priority: number) {
const oldPriority = this.prioritySettings.get(id) ?? 0;
this.prioritySettings.set(id, priority);
+33 -26
View File
@@ -3,37 +3,44 @@ import { BlobSyncEngine } from './blob';
import { DocSyncEngine } from './doc';
export class SyncEngine {
private readonly doc: DocSyncEngine | null;
private readonly blob: BlobSyncEngine | null;
constructor(
readonly local: SpaceStorage,
readonly peers: SpaceStorage[]
) {}
) {
const doc = local.tryGet('doc');
const blob = local.tryGet('blob');
const sync = local.tryGet('sync');
async run(signal?: AbortSignal) {
const doc = this.local.tryGet('doc');
const blob = this.local.tryGet('blob');
const sync = this.local.tryGet('sync');
await Promise.allSettled([
(async () => {
if (doc && sync) {
const peerDocs = this.peers
.map(peer => peer.tryGet('doc'))
.filter((v): v is DocStorage => !!v);
const engine = new DocSyncEngine(doc, sync, peerDocs);
await engine.run(signal);
}
})(),
(async () => {
if (blob) {
const peerBlobs = this.peers
this.doc =
doc && sync
? new DocSyncEngine(
doc,
sync,
peers
.map(peer => peer.tryGet('doc'))
.filter((v): v is DocStorage => !!v)
)
: null;
this.blob = blob
? new BlobSyncEngine(
blob,
peers
.map(peer => peer.tryGet('blob'))
.filter((v): v is BlobStorage => !!v);
.filter((v): v is BlobStorage => !!v)
)
: null;
}
const engine = new BlobSyncEngine(blob, peerBlobs);
await engine.run(signal);
}
})(),
]);
start() {
this.doc?.start();
this.blob?.start();
}
stop() {
this.doc?.stop();
this.blob?.stop();
}
}