mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 20:38:52 +00:00
feat: sync client versioning (#5645)
after this pr, server will only accept client that have some major version the client version <0.12 will be rejected by the server, >= 0.12 can receive outdated messages and notify users
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
export enum SyncEngineStep {
|
||||
// error
|
||||
Rejected = -1,
|
||||
// in progress
|
||||
Stopped = 0,
|
||||
Syncing = 1,
|
||||
// finished
|
||||
Synced = 2,
|
||||
}
|
||||
|
||||
export enum SyncPeerStep {
|
||||
// error
|
||||
VersionRejected = -1,
|
||||
// in progress
|
||||
Stopped = 0,
|
||||
Retrying = 1,
|
||||
LoadingRootDoc = 2,
|
||||
LoadingSubDoc = 3,
|
||||
Loaded = 4.5,
|
||||
Syncing = 5,
|
||||
// finished
|
||||
Synced = 6,
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface SyncEngineStatus {
|
||||
step: SyncEngineStep;
|
||||
local: SyncPeerStatus | null;
|
||||
remotes: (SyncPeerStatus | null)[];
|
||||
error: string | null;
|
||||
retrying: boolean;
|
||||
}
|
||||
|
||||
@@ -82,6 +83,7 @@ export class SyncEngine {
|
||||
step: SyncEngineStep.Stopped,
|
||||
local: null,
|
||||
remotes: remotes.map(() => null),
|
||||
error: null,
|
||||
retrying: false,
|
||||
};
|
||||
}
|
||||
@@ -130,6 +132,7 @@ export class SyncEngine {
|
||||
step: SyncEngineStep.Stopped,
|
||||
local: null,
|
||||
remotes: this.remotes.map(() => null),
|
||||
error: 'Sync progress manually stopped',
|
||||
retrying: false,
|
||||
};
|
||||
}
|
||||
@@ -209,10 +212,18 @@ export class SyncEngine {
|
||||
|
||||
updateSyncingState(local: SyncPeer | null, remotes: (SyncPeer | null)[]) {
|
||||
let step = SyncEngineStep.Synced;
|
||||
let error = null;
|
||||
const allPeer = [local, ...remotes];
|
||||
for (const peer of allPeer) {
|
||||
if (!peer || peer.status.step !== SyncPeerStep.Synced) {
|
||||
step = SyncEngineStep.Syncing;
|
||||
if (peer && peer.status.step <= 0) {
|
||||
// step < 0 means reject connection by server with some reason
|
||||
// so the data may be out of date
|
||||
step = SyncEngineStep.Rejected;
|
||||
error = peer.status.lastError;
|
||||
} else {
|
||||
step = SyncEngineStep.Syncing;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -220,6 +231,7 @@ export class SyncEngine {
|
||||
step,
|
||||
local: local?.status ?? null,
|
||||
remotes: remotes.map(peer => peer?.status ?? null),
|
||||
error,
|
||||
retrying: allPeer.some(
|
||||
peer => peer?.status.step === SyncPeerStep.Retrying
|
||||
),
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface SyncPeerStatus {
|
||||
loadedDocs: number;
|
||||
pendingPullUpdates: number;
|
||||
pendingPushUpdates: number;
|
||||
lastError: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,7 @@ export class SyncPeer {
|
||||
loadedDocs: 0,
|
||||
pendingPullUpdates: 0,
|
||||
pendingPushUpdates: 0,
|
||||
lastError: null,
|
||||
};
|
||||
onStatusChange = new Slot<SyncPeerStatus>();
|
||||
readonly abort = new AbortController();
|
||||
@@ -119,6 +121,7 @@ export class SyncPeer {
|
||||
loadedDocs: 0,
|
||||
pendingPullUpdates: 0,
|
||||
pendingPushUpdates: 0,
|
||||
lastError: 'Retrying sync after 5 seconds',
|
||||
};
|
||||
await Promise.race([
|
||||
new Promise<void>(resolve => {
|
||||
@@ -199,6 +202,7 @@ export class SyncPeer {
|
||||
abortInner.abort('subscribe disconnect:' + reason);
|
||||
}
|
||||
);
|
||||
|
||||
throwIfAborted(abortInner.signal);
|
||||
|
||||
// Step 1: load root doc
|
||||
@@ -368,7 +372,11 @@ export class SyncPeer {
|
||||
|
||||
reportSyncStatus() {
|
||||
let step;
|
||||
if (this.state.connectedDocs.size === 0) {
|
||||
let lastError = null;
|
||||
if (this.storage.errorMessage?.type === 'outdated') {
|
||||
step = SyncPeerStep.VersionRejected;
|
||||
lastError = this.storage.errorMessage.message.reason;
|
||||
} else if (this.state.connectedDocs.size === 0) {
|
||||
step = SyncPeerStep.LoadingRootDoc;
|
||||
} else if (this.state.subdocsLoadQueue.length || this.state.subdocLoading) {
|
||||
step = SyncPeerStep.LoadingSubDoc;
|
||||
@@ -391,6 +399,7 @@ export class SyncPeer {
|
||||
this.state.pullUpdatesQueue.length + (this.state.subdocLoading ? 1 : 0),
|
||||
pendingPushUpdates:
|
||||
this.state.pushUpdatesQueue.length + (this.state.pushingUpdate ? 1 : 0),
|
||||
lastError,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
export type RejectByVersion = {
|
||||
currVersion: string;
|
||||
requiredVersion: string;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
export type SyncErrorMessage = {
|
||||
type: 'outdated';
|
||||
message: RejectByVersion;
|
||||
};
|
||||
|
||||
export interface SyncStorage {
|
||||
/**
|
||||
* for debug
|
||||
*/
|
||||
name: string;
|
||||
|
||||
errorMessage?: SyncErrorMessage;
|
||||
|
||||
pull(
|
||||
docId: string,
|
||||
state: Uint8Array
|
||||
|
||||
Reference in New Issue
Block a user