@univerjs-pro/collaboration-client 1.1.0 → 1.3.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/README.md +2 -0
- package/lib/cjs/facade.js +1 -1
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/locale/ar-SA.js +1 -1
- package/lib/cjs/locale/ca-ES.js +1 -1
- package/lib/cjs/locale/de-DE.js +1 -1
- package/lib/cjs/locale/en-US.js +1 -1
- package/lib/cjs/locale/es-ES.js +1 -1
- package/lib/cjs/locale/fa-IR.js +1 -1
- package/lib/cjs/locale/fr-FR.js +1 -1
- package/lib/cjs/locale/id-ID.js +1 -1
- package/lib/cjs/locale/it-IT.js +1 -1
- package/lib/cjs/locale/ja-JP.js +1 -1
- package/lib/cjs/locale/ko-KR.js +1 -1
- package/lib/cjs/locale/pl-PL.js +1 -1
- package/lib/cjs/locale/pt-BR.js +1 -1
- package/lib/cjs/locale/ru-RU.js +1 -1
- package/lib/cjs/locale/sk-SK.js +1 -1
- package/lib/cjs/locale/vi-VN.js +1 -1
- package/lib/cjs/locale/zh-CN.js +1 -1
- package/lib/cjs/locale/zh-HK.js +1 -1
- package/lib/cjs/locale/zh-TW.js +1 -1
- package/lib/es/facade.js +1 -1
- package/lib/es/index.js +1 -1
- package/lib/es/locale/ar-SA.js +1 -1
- package/lib/es/locale/ca-ES.js +1 -1
- package/lib/es/locale/de-DE.js +1 -1
- package/lib/es/locale/en-US.js +1 -1
- package/lib/es/locale/es-ES.js +1 -1
- package/lib/es/locale/fa-IR.js +1 -1
- package/lib/es/locale/fr-FR.js +1 -1
- package/lib/es/locale/id-ID.js +1 -1
- package/lib/es/locale/it-IT.js +1 -1
- package/lib/es/locale/ja-JP.js +1 -1
- package/lib/es/locale/ko-KR.js +1 -1
- package/lib/es/locale/pl-PL.js +1 -1
- package/lib/es/locale/pt-BR.js +1 -1
- package/lib/es/locale/ru-RU.js +1 -1
- package/lib/es/locale/sk-SK.js +1 -1
- package/lib/es/locale/vi-VN.js +1 -1
- package/lib/es/locale/zh-CN.js +1 -1
- package/lib/es/locale/zh-HK.js +1 -1
- package/lib/es/locale/zh-TW.js +1 -1
- package/lib/facade.js +1 -1
- package/lib/index.js +1 -1
- package/lib/locale/ar-SA.js +1 -1
- package/lib/locale/ca-ES.js +1 -1
- package/lib/locale/de-DE.js +1 -1
- package/lib/locale/en-US.js +1 -1
- package/lib/locale/es-ES.js +1 -1
- package/lib/locale/fa-IR.js +1 -1
- package/lib/locale/fr-FR.js +1 -1
- package/lib/locale/id-ID.js +1 -1
- package/lib/locale/it-IT.js +1 -1
- package/lib/locale/ja-JP.js +1 -1
- package/lib/locale/ko-KR.js +1 -1
- package/lib/locale/pl-PL.js +1 -1
- package/lib/locale/pt-BR.js +1 -1
- package/lib/locale/ru-RU.js +1 -1
- package/lib/locale/sk-SK.js +1 -1
- package/lib/locale/vi-VN.js +1 -1
- package/lib/locale/zh-CN.js +1 -1
- package/lib/locale/zh-HK.js +1 -1
- package/lib/locale/zh-TW.js +1 -1
- package/lib/types/config/config.d.ts +19 -0
- package/lib/types/controllers/collaboration/changeset-submitter.d.ts +132 -0
- package/lib/types/controllers/collaboration/collaboration-entity.d.ts +29 -2
- package/lib/types/controllers/collaboration/collaboration-state.d.ts +181 -87
- package/lib/types/controllers/collaboration/collaboration.controller.d.ts +7 -0
- package/lib/types/controllers/collaboration/utils/changeset-utils.d.ts +7 -3
- package/lib/types/facade/f-collaboration.d.ts +17 -0
- package/lib/types/facade/f-event.d.ts +89 -2
- package/lib/types/index.d.ts +5 -3
- package/lib/types/services/collaboration-session/collaboration-session.d.ts +4 -8
- package/lib/types/services/collaboration-session/collaboration-session.service.d.ts +2 -1
- package/lib/types/services/collaboration-ui-event/collaboration-ui-event.d.ts +10 -0
- package/lib/types/services/socket/collaboration-socket.service.d.ts +10 -2
- package/lib/types/services/undoredo/collaborative-undoredo.service.d.ts +5 -0
- package/lib/umd/facade.js +1 -1
- package/lib/umd/index.js +1 -1
- package/lib/umd/locale/ar-SA.js +1 -1
- package/lib/umd/locale/ca-ES.js +1 -1
- package/lib/umd/locale/de-DE.js +1 -1
- package/lib/umd/locale/en-US.js +1 -1
- package/lib/umd/locale/es-ES.js +1 -1
- package/lib/umd/locale/fa-IR.js +1 -1
- package/lib/umd/locale/fr-FR.js +1 -1
- package/lib/umd/locale/id-ID.js +1 -1
- package/lib/umd/locale/it-IT.js +1 -1
- package/lib/umd/locale/ja-JP.js +1 -1
- package/lib/umd/locale/ko-KR.js +1 -1
- package/lib/umd/locale/pl-PL.js +1 -1
- package/lib/umd/locale/pt-BR.js +1 -1
- package/lib/umd/locale/ru-RU.js +1 -1
- package/lib/umd/locale/sk-SK.js +1 -1
- package/lib/umd/locale/vi-VN.js +1 -1
- package/lib/umd/locale/zh-CN.js +1 -1
- package/lib/umd/locale/zh-HK.js +1 -1
- package/lib/umd/locale/zh-TW.js +1 -1
- package/package.json +15 -15
|
@@ -28,7 +28,26 @@ export interface IUniverCollaborationClientConfig {
|
|
|
28
28
|
* Override internal modules with custom implementations.
|
|
29
29
|
*/
|
|
30
30
|
override?: DependencyOverride;
|
|
31
|
+
/**
|
|
32
|
+
* How long local edits are batched before they are sent as one changeset, in milliseconds. Edits made within
|
|
33
|
+
* this window after the first one go into the same changeset. This is a batching delay, not a network timeout;
|
|
34
|
+
* for the acknowledgement timeout see `changesetAckTimeout`.
|
|
35
|
+
* @default 2000
|
|
36
|
+
*/
|
|
31
37
|
sendChangesetTimeout?: number;
|
|
38
|
+
/**
|
|
39
|
+
* How long to wait for the server's acknowledgement of a changeset before sending it again, in milliseconds.
|
|
40
|
+
* Later resends wait twice as long each time, up to `maxChangesetAckTimeout`. The request that submits the
|
|
41
|
+
* changeset is given the same timeout.
|
|
42
|
+
* @default 20000
|
|
43
|
+
*/
|
|
44
|
+
changesetAckTimeout?: number;
|
|
45
|
+
/**
|
|
46
|
+
* The longest wait between two resends of an unacknowledged changeset, in milliseconds. Set it equal to
|
|
47
|
+
* `changesetAckTimeout` for a constant interval.
|
|
48
|
+
* @default 120000
|
|
49
|
+
*/
|
|
50
|
+
maxChangesetAckTimeout?: number;
|
|
32
51
|
snapshotServerUrl?: string;
|
|
33
52
|
collabSubmitChangesetUrl?: string;
|
|
34
53
|
collabWebSocketUrl?: string;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { IChangeset } from '@univerjs-pro/collaboration';
|
|
2
|
+
import type { ICollaborationSendOptions } from '../../services/socket/collaboration-socket.service';
|
|
3
|
+
/** Why the awaiting changeset was sent again. */
|
|
4
|
+
export type ChangesetResendReason = 'ack_timeout' | 'should_retry' | 'reconnect' | 'request_failed' | 'license_editing_connections_exceeded';
|
|
5
|
+
/** Emitted every time an awaiting changeset is sent again. The first send is not an event. */
|
|
6
|
+
export interface IChangesetResendEvent {
|
|
7
|
+
unitID: string;
|
|
8
|
+
reqId: number;
|
|
9
|
+
reason: ChangesetResendReason;
|
|
10
|
+
/** How many times the changeset has been resent, counting this one. */
|
|
11
|
+
attempt: number;
|
|
12
|
+
/** Milliseconds since the changeset was first sent. */
|
|
13
|
+
elapsedMs: number;
|
|
14
|
+
/** Mutations in the awaiting changeset plus pending mutations not yet sent. */
|
|
15
|
+
unsyncedMutationCount: number;
|
|
16
|
+
/** Milliseconds until the next resend if nothing is heard from the server. */
|
|
17
|
+
nextDelayMs: number;
|
|
18
|
+
}
|
|
19
|
+
export type ChangesetResendInfo = Omit<IChangesetResendEvent, 'unitID'>;
|
|
20
|
+
/** The first wait for an acknowledgement before the awaiting changeset is resent. */
|
|
21
|
+
export declare const DEFAULT_ACK_TIMEOUT = 20000;
|
|
22
|
+
/** The longest wait for an acknowledgement between two resends. */
|
|
23
|
+
export declare const MAX_ACK_TIMEOUT = 120000;
|
|
24
|
+
/** The longest backoff between two resends requested by the server or caused by a failed request. */
|
|
25
|
+
export declare const MAX_RETRY_TIMEOUT = 20000;
|
|
26
|
+
/**
|
|
27
|
+
* Hands a changeset to the transport. `options.timeout` is how long the transport may wait for the server to
|
|
28
|
+
* answer: it equals the wait for the acknowledgement, so a request that is still unanswered when the changeset is
|
|
29
|
+
* sent again is given up at the same moment. The returned promise, when there is one, rejects when the request
|
|
30
|
+
* failed; its resolution is not used.
|
|
31
|
+
*/
|
|
32
|
+
export type SendChangeset = (changeset: IChangeset, options: ICollaborationSendOptions) => void | Promise<void>;
|
|
33
|
+
/** What the bound state provides for a resend: the awaiting changeset as it currently is, and the unsynced count. */
|
|
34
|
+
export interface IChangesetSubmitterSource {
|
|
35
|
+
changeset: IChangeset;
|
|
36
|
+
/** Mutations in the awaiting changeset plus pending mutations not yet sent. */
|
|
37
|
+
unsyncedMutationCount: number;
|
|
38
|
+
}
|
|
39
|
+
export interface IChangesetSubmitterOptions {
|
|
40
|
+
/** The first wait for an acknowledgement. Defaults to `DEFAULT_ACK_TIMEOUT`. */
|
|
41
|
+
ackTimeout?: number;
|
|
42
|
+
/** The longest wait between two resends. Defaults to `MAX_ACK_TIMEOUT`, and never less than `ackTimeout`. */
|
|
43
|
+
maxAckTimeout?: number;
|
|
44
|
+
onResend?: (info: ChangesetResendInfo) => void;
|
|
45
|
+
now?: () => number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Submits one changeset and sends it again until the server acknowledges it.
|
|
49
|
+
*
|
|
50
|
+
* It is created when the changeset is first sent and handed from one state to the next while the
|
|
51
|
+
* changeset is kept, so the pending timer, the intervals and the attempt count survive state transitions.
|
|
52
|
+
* The states only tell it to `submit`, `requestRetry` and `dispose`; everything about delivery (timers, backoff,
|
|
53
|
+
* attempt counting) stays here. There is at most one timer at a time: every trigger replaces the previous one.
|
|
54
|
+
*
|
|
55
|
+
* - After every send, an acknowledgement timeout is armed (`ackTimeout`, then doubled up to `maxAckTimeout`).
|
|
56
|
+
* The request itself is given the same timeout, so an unanswered request is cancelled when the changeset is
|
|
57
|
+
* sent again.
|
|
58
|
+
* - A `changeset_should_retry` from the server replaces the timer with a short backoff (0, 1s, 2s, ... up to
|
|
59
|
+
* `MAX_RETRY_TIMEOUT`). A request that fails for a transient reason (network error, 408, 429, 5xx) does the
|
|
60
|
+
* same; other failures and the request timeout leave the timer alone. The two intervals are counted
|
|
61
|
+
* independently.
|
|
62
|
+
* - A timer that fires while no state is bound (e.g. while missing changesets are fetched) is remembered and
|
|
63
|
+
* runs as soon as the next awaiting state binds.
|
|
64
|
+
*/
|
|
65
|
+
export declare class ChangesetSubmitter {
|
|
66
|
+
private readonly _send;
|
|
67
|
+
private readonly _options;
|
|
68
|
+
private _attempt;
|
|
69
|
+
private readonly _firstSentAt;
|
|
70
|
+
private _ackTimeout;
|
|
71
|
+
private readonly _maxAckTimeout;
|
|
72
|
+
private _retryBackoff;
|
|
73
|
+
private _nextDelay;
|
|
74
|
+
private _timer;
|
|
75
|
+
private _pendingReason;
|
|
76
|
+
private _source;
|
|
77
|
+
/** Identifies the latest send; the outcome of an earlier send is ignored. */
|
|
78
|
+
private _sendToken;
|
|
79
|
+
private _disposed;
|
|
80
|
+
private readonly _now;
|
|
81
|
+
private _reqId;
|
|
82
|
+
constructor(reqId: number, _send: SendChangeset, _options?: IChangesetSubmitterOptions);
|
|
83
|
+
/** The request id of the changeset. It is assigned by the transport on the first send and read back then. */
|
|
84
|
+
get reqId(): number;
|
|
85
|
+
get attempt(): number;
|
|
86
|
+
get nextDelayMs(): number;
|
|
87
|
+
get elapsedMs(): number;
|
|
88
|
+
/**
|
|
89
|
+
* Bind the state that owns the awaiting changeset. `source` returns the changeset as it currently is (it may
|
|
90
|
+
* have been transformed since the last send) and the number of unsynced mutations. A resend that came due
|
|
91
|
+
* while nothing was bound runs now.
|
|
92
|
+
*/
|
|
93
|
+
bind(source: () => IChangesetSubmitterSource): void;
|
|
94
|
+
/** Detach the current state while the changeset is handed to the next one. Timers keep running. */
|
|
95
|
+
unbind(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Send the changeset and wait for its acknowledgement.
|
|
98
|
+
*
|
|
99
|
+
* Without `reason` this is the first send of the changeset, which is not reported as a resend. With `reason`
|
|
100
|
+
* it is a resend triggered outside this submitter (e.g. after a reconnect): it counts as an attempt and
|
|
101
|
+
* notifies the listener.
|
|
102
|
+
*/
|
|
103
|
+
submit(changeset: IChangeset, unsyncedMutationCount: number, reason?: ChangesetResendReason): void;
|
|
104
|
+
/**
|
|
105
|
+
* Wait for the acknowledgement of a send that happened outside this submitter, e.g. a changeset restored
|
|
106
|
+
* from the cache that the entity resends itself.
|
|
107
|
+
*/
|
|
108
|
+
armAckTimeout(): void;
|
|
109
|
+
/** The server asked for the changeset to be resent: replace the current timer with the short backoff. */
|
|
110
|
+
requestRetry(reason?: ChangesetResendReason): void;
|
|
111
|
+
/** The changeset was acknowledged, rejected or dropped. */
|
|
112
|
+
dispose(): void;
|
|
113
|
+
private _deliver;
|
|
114
|
+
/**
|
|
115
|
+
* The request did not reach the server. A transient failure brings the next send forward to the short
|
|
116
|
+
* backoff; the acknowledgement timeout keeps its own count. A request that ran into its timeout is ignored:
|
|
117
|
+
* the changeset is being sent again at that very moment. So is the failure of a request that a later send
|
|
118
|
+
* superseded, e.g. when the server asked for a retry before the request was answered.
|
|
119
|
+
*/
|
|
120
|
+
private _onRequestFailed;
|
|
121
|
+
private _schedule;
|
|
122
|
+
private _resend;
|
|
123
|
+
/** Count a resend and move the interval it belongs to; the request timeout follows the new interval. */
|
|
124
|
+
private _countResend;
|
|
125
|
+
private _notifyResend;
|
|
126
|
+
private _clearTimer;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* How long to wait before sending again after a failed request, or `null` when the failure should not bring
|
|
130
|
+
* the next send forward.
|
|
131
|
+
*/
|
|
132
|
+
export declare function getRetryDelay(error: unknown, backoff: number): number | null;
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import type { IDisposable, IMutationInfo, Nullable, UniverInstanceType } from '@univerjs/core';
|
|
2
2
|
import type { Observable } from 'rxjs';
|
|
3
|
-
import type { CollaborationSession } from '../../services/collaboration-session/collaboration-session';
|
|
4
|
-
import type { CollaborationState, ICollaborationStateHandler, PrepareTransformSelectionsHandler, SyncEditingCollabCursorHandler, TransformIMEHandler, TransformRemoteChangesetByIMECache, TransformRemoteChangesetByStateCache, TransformSelectionsHandler, TransformStateHandler } from './collaboration-state';
|
|
5
3
|
import { CompressMutationService, RevisionService } from '@univerjs-pro/collaboration';
|
|
6
4
|
import { ICommandService, ILogService, Injector, IPermissionService, IUniverInstanceService, LocaleService, RxDisposable } from '@univerjs/core';
|
|
7
5
|
import { DocStateChangeManagerService } from '@univerjs/docs';
|
|
8
6
|
import { BehaviorSubject } from 'rxjs';
|
|
7
|
+
import type { CollaborationSession } from '../../services/collaboration-session/collaboration-session';
|
|
8
|
+
import type { IUnitCacheData } from '../../services/local-cache/local-cache.service';
|
|
9
|
+
import type { IChangesetResendEvent } from './changeset-submitter';
|
|
10
|
+
import type { CollaborationState, ICollaborationStateHandler, IConflictInfo, PrepareTransformSelectionsHandler, SyncEditingCollabCursorHandler, TransformIMEHandler, TransformRemoteChangesetByIMECache, TransformRemoteChangesetByStateCache, TransformSelectionsHandler, TransformStateHandler } from './collaboration-state';
|
|
9
11
|
import { CollaborationUIEventService } from '../../services/collaboration-ui-event/collaboration-ui-event';
|
|
10
12
|
import { ILocalCacheService } from '../../services/local-cache/local-cache.service';
|
|
11
13
|
import { SheetTransformSelectionsService } from '../../services/range-selection/sheet-transform-selections.service';
|
|
12
14
|
import { ISingleActiveUnitService } from '../../services/single-active-unit/single-active-unit.service';
|
|
13
15
|
import { CollaborationStatus } from './collaboration-state';
|
|
16
|
+
/**
|
|
17
|
+
* Emitted once when a unit enters the conflict state, after its offline cache has been cleared. Carries
|
|
18
|
+
* `IConflictInfo` and the local edits the server has not acknowledged.
|
|
19
|
+
*/
|
|
20
|
+
export interface ICollaborationConflictEvent extends IConflictInfo {
|
|
21
|
+
unitID: string;
|
|
22
|
+
/**
|
|
23
|
+
* The local edits the server has not acknowledged, in the format of the offline cache, or `null` when there are
|
|
24
|
+
* none. `awaitingChangeset` has been sent; whether the server applied it is unknown.
|
|
25
|
+
*/
|
|
26
|
+
localChanges: IUnitCacheData | null;
|
|
27
|
+
/** Whether the offline cache of the unit was cleared. When `false`, a page reload replays the cached edits. */
|
|
28
|
+
cacheCleared: boolean;
|
|
29
|
+
}
|
|
14
30
|
/**
|
|
15
31
|
* Each univer document instance would map to an `CollaborationEntity` to handle collaborated editing events.
|
|
16
32
|
*/
|
|
@@ -37,6 +53,12 @@ export declare abstract class CollaborationEntity extends RxDisposable {
|
|
|
37
53
|
protected _changesetSessionId: string;
|
|
38
54
|
protected _changesetReqId: number;
|
|
39
55
|
readonly status$: Observable<CollaborationStatus>;
|
|
56
|
+
private readonly _changesetResend$;
|
|
57
|
+
/** Emits every time the awaiting changeset is sent again because it was not acknowledged. */
|
|
58
|
+
readonly changesetResend$: Observable<IChangesetResendEvent>;
|
|
59
|
+
private readonly _conflict$;
|
|
60
|
+
/** Emits once when the unit enters the conflict state, after its offline cache has been cleared. */
|
|
61
|
+
readonly conflict$: Observable<ICollaborationConflictEvent>;
|
|
40
62
|
constructor(unitID: string, session: CollaborationSession, _type: UniverInstanceType, _injector: Injector, _compressMutationService: CompressMutationService, _localeService: LocaleService, _revisionService: RevisionService, _eventService: CollaborationUIEventService, _univerInstanceService: IUniverInstanceService, _logService: ILogService, _commandService: ICommandService, _permissionService: IPermissionService, _singleActiveUnitService?: ISingleActiveUnitService | undefined, _localCacheService?: ILocalCacheService | undefined);
|
|
41
63
|
init(): Promise<void>;
|
|
42
64
|
/**
|
|
@@ -45,6 +67,9 @@ export declare abstract class CollaborationEntity extends RxDisposable {
|
|
|
45
67
|
*/
|
|
46
68
|
pauseCollaboration(): IDisposable;
|
|
47
69
|
onLocalMutation(command: IMutationInfo): void;
|
|
70
|
+
/** Whether there are local mutations that the server has not acknowledged yet. */
|
|
71
|
+
hasWritePending(): boolean;
|
|
72
|
+
dispose(): void;
|
|
48
73
|
private _updateState;
|
|
49
74
|
protected _init(): Promise<CollaborationState>;
|
|
50
75
|
/**
|
|
@@ -53,6 +78,8 @@ export declare abstract class CollaborationEntity extends RxDisposable {
|
|
|
53
78
|
private _transitionLocked;
|
|
54
79
|
private _unlockTransition;
|
|
55
80
|
private _lockTransition;
|
|
81
|
+
/** Run one transition under the lock. The lock is released even when the state throws, so the next event can be handled. */
|
|
82
|
+
private _transit;
|
|
56
83
|
protected _onLocalMutation(command: IMutationInfo): void;
|
|
57
84
|
private _remoteChangesetQueue;
|
|
58
85
|
private _onRemoteChangeset;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { IAcknowledgedChangeset, IChangeset } from '@univerjs-pro/collaboration';
|
|
2
2
|
import type { IMutationInfo, Nullable } from '@univerjs/core';
|
|
3
|
-
import type { Observable } from 'rxjs';
|
|
4
|
-
import type { ICollaborativeUndoRedoService } from '../../services/undoredo/collaborative-undoredo.service';
|
|
5
3
|
import { ITransformService, RevisionService } from '@univerjs-pro/collaboration';
|
|
6
|
-
import { ICommandService, IConfigService, ILogService, Injector, IPermissionService, IUniverInstanceService,
|
|
4
|
+
import { ICommandService, IConfigService, ILogService, Injector, IPermissionService, IUniverInstanceService, UniverInstanceType, UserManagerService } from '@univerjs/core';
|
|
5
|
+
import type { IUnitCacheData } from '../../services/local-cache/local-cache.service';
|
|
6
|
+
import type { ICollaborationSendOptions } from '../../services/socket/collaboration-socket.service';
|
|
7
|
+
import type { ICollaborativeUndoRedoService } from '../../services/undoredo/collaborative-undoredo.service';
|
|
8
|
+
import type { ChangesetResendInfo, ChangesetResendReason } from './changeset-submitter';
|
|
7
9
|
import { CollaborationUIEventService } from '../../services/collaboration-ui-event/collaboration-ui-event';
|
|
8
10
|
import { ILocalCacheService } from '../../services/local-cache/local-cache.service';
|
|
11
|
+
import { ChangesetSubmitter } from './changeset-submitter';
|
|
9
12
|
/** Provide both states when and after changing, so the parent could examine if state transition is correct. */
|
|
10
13
|
export type StateChangeHandler = (before: CollaborationState, after: CollaborationState) => void;
|
|
11
14
|
/** A network interface to send changeset and */
|
|
12
|
-
export type SendChangesetHandler = (changeset: IChangeset) => void
|
|
15
|
+
export type SendChangesetHandler = (changeset: IChangeset, options: ICollaborationSendOptions) => void | Promise<void>;
|
|
13
16
|
export type MissingChangesetsHandler = (params: {
|
|
14
17
|
from: number;
|
|
15
18
|
to: number;
|
|
@@ -36,7 +39,67 @@ export interface ICollaborationStateHandler {
|
|
|
36
39
|
onSyncEditingCollabCursor?: SyncEditingCollabCursorHandler;
|
|
37
40
|
onTransformRemoteChangesetByIMECache?: TransformRemoteChangesetByIMECache;
|
|
38
41
|
onTransformRemoteChangesetByStateCache?: TransformRemoteChangesetByStateCache;
|
|
42
|
+
/** The awaiting changeset was sent again. */
|
|
43
|
+
onChangesetResend?: (info: ChangesetResendInfo) => void;
|
|
44
|
+
/**
|
|
45
|
+
* The unit entered `ConflictState` and its recovery preparation is done: the unacknowledged local edits are backed
|
|
46
|
+
* up and the offline cache is cleared (`cacheCleared` tells whether that succeeded). Called once per conflict.
|
|
47
|
+
*/
|
|
48
|
+
onConflict?: (info: IConflictInfo, localChanges: IUnitCacheData | null, cacheCleared: boolean) => void;
|
|
49
|
+
/** How long to wait for an acknowledgement before resending; see `IUniverCollaborationClientConfig`. */
|
|
50
|
+
resendTimeouts?: {
|
|
51
|
+
ackTimeout?: number;
|
|
52
|
+
maxAckTimeout?: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** What the server sent with a `changeset_rej` or `permission_rej` event. */
|
|
56
|
+
export interface IRemoteRejection {
|
|
57
|
+
isPermissionRej: boolean;
|
|
58
|
+
/** The reason in words, when the server gave one. */
|
|
59
|
+
reason?: string;
|
|
60
|
+
/** The protocol error code, when the server gave one. */
|
|
61
|
+
code?: number;
|
|
62
|
+
}
|
|
63
|
+
/** Why a unit entered `ConflictState`. */
|
|
64
|
+
export type ConflictReason =
|
|
65
|
+
/** A remote changeset could not be transformed against the local edits. */
|
|
66
|
+
'transform_failed'
|
|
67
|
+
/** A remote changeset was transformed but one of its mutations failed to execute. */
|
|
68
|
+
| 'apply_failed'
|
|
69
|
+
/** The server rejected the local changeset. */
|
|
70
|
+
| 'changeset_rejected'
|
|
71
|
+
/** The server rejected the local changeset for lack of permission. */
|
|
72
|
+
| 'permission_rejected'
|
|
73
|
+
/** The server's License does not cover collaboration on this document type. */
|
|
74
|
+
| 'license_unit_type_rejected'
|
|
75
|
+
/** Another collaborator reverted the unit to a historical revision. */
|
|
76
|
+
| 'remote_revert';
|
|
77
|
+
/** The remote revert that caused a `remote_revert` conflict. */
|
|
78
|
+
export interface IRemoteRevertInfo {
|
|
79
|
+
/** The revision that was restored. */
|
|
80
|
+
revision: number;
|
|
81
|
+
/** The member ID of the collaborator who restored it. */
|
|
82
|
+
memberId: string;
|
|
83
|
+
/** The user ID of the collaborator who restored it. */
|
|
84
|
+
userId: string;
|
|
39
85
|
}
|
|
86
|
+
/** Why a unit entered `ConflictState`. */
|
|
87
|
+
export interface IConflictInfo {
|
|
88
|
+
reason: ConflictReason;
|
|
89
|
+
/** The error message, when the conflict was caused by an error. */
|
|
90
|
+
message?: string;
|
|
91
|
+
/** Present when `reason` is `remote_revert`. */
|
|
92
|
+
revert?: IRemoteRevertInfo;
|
|
93
|
+
}
|
|
94
|
+
/** A remote changeset was transformed successfully but executing its mutations failed. */
|
|
95
|
+
export declare class RemoteChangesetApplyError extends Error {
|
|
96
|
+
readonly applyError: unknown;
|
|
97
|
+
constructor(applyError: unknown);
|
|
98
|
+
}
|
|
99
|
+
/** How a remote changeset relates to the local copy, see `CollaborationState._classifyRemoteChangeset`. */
|
|
100
|
+
export type RemoteChangesetKind = 'echo' | 'remote_revert' | 'applied' | 'missing' | 'apply';
|
|
101
|
+
/** How an acknowledgement relates to the local copy, see `CollaborationState._classifyAck`. */
|
|
102
|
+
export type RemoteAckKind = 'ack_of_awaiting' | 'stale' | 'missing' | 'next';
|
|
40
103
|
export declare enum CollaborationStatus {
|
|
41
104
|
NOT_COLLAB = "not_collab",
|
|
42
105
|
SYNCED = "synced",
|
|
@@ -47,20 +110,6 @@ export declare enum CollaborationStatus {
|
|
|
47
110
|
CONFLICT = "conflict",
|
|
48
111
|
OFFLINE = "offline"
|
|
49
112
|
}
|
|
50
|
-
/**
|
|
51
|
-
* The retry of an awaiting changeset. It is handed from one state to the next while the awaiting changeset is
|
|
52
|
-
* kept, so the pending timer, the backoff and the total retry time survive state transitions.
|
|
53
|
-
*/
|
|
54
|
-
export interface IResendSchedule {
|
|
55
|
-
/** The pending retry. `undefined` once it has fired and the awaiting changeset was resent. */
|
|
56
|
-
timer: Observable<{
|
|
57
|
-
reqId: number;
|
|
58
|
-
}> | undefined;
|
|
59
|
-
/** The backoff before the next retry. */
|
|
60
|
-
timeout: number;
|
|
61
|
-
/** The total backoff spent on this awaiting changeset, bounded by `MAX_RETRY_TOTAL_TIMEOUT`. */
|
|
62
|
-
total: number;
|
|
63
|
-
}
|
|
64
113
|
/**
|
|
65
114
|
* Use state machine to manage syncing states.
|
|
66
115
|
* An explanation to how these states are transformed to each other.
|
|
@@ -82,7 +131,18 @@ export declare abstract class CollaborationState {
|
|
|
82
131
|
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: Nullable<IChangeset>, pendingMutations: IMutationInfo[],
|
|
83
132
|
/** State may change internally. Parent module should provide a callback to handle this event. */
|
|
84
133
|
_handler: ICollaborationStateHandler, _commandService: ICommandService, _undoRedoService: ICollaborativeUndoRedoService, _revisionService: RevisionService, _localCacheService?: ILocalCacheService | undefined);
|
|
85
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Send the awaiting changeset again. Only states that keep an awaiting changeset implement it.
|
|
136
|
+
* @param reason Why the changeset is resent. Defaults to `reconnect`.
|
|
137
|
+
*/
|
|
138
|
+
abstract resend(reason?: ChangesetResendReason): void;
|
|
139
|
+
/** Whether there are local mutations that the server has not acknowledged yet. */
|
|
140
|
+
hasLocalChanges(): boolean;
|
|
141
|
+
/** Release timers held by the state. Called when the entity is disposed while the state is current. */
|
|
142
|
+
dispose(): void;
|
|
143
|
+
/** Mutations in the awaiting changeset plus the pending mutations. */
|
|
144
|
+
protected _unsyncedMutationCount(): number;
|
|
145
|
+
protected _createChangesetSubmitter(changeset: IChangeset): ChangesetSubmitter;
|
|
86
146
|
/**
|
|
87
147
|
* Append a location mutation to collaboration queue.
|
|
88
148
|
*
|
|
@@ -101,23 +161,56 @@ export declare abstract class CollaborationState {
|
|
|
101
161
|
/**
|
|
102
162
|
* Received a rejection from the server, meaning that conflict could be resolved by the algorithm.
|
|
103
163
|
*/
|
|
104
|
-
abstract onRemoteRej(config?:
|
|
105
|
-
isPermissionRej: boolean;
|
|
106
|
-
}): CollaborationState;
|
|
164
|
+
abstract onRemoteRej(config?: IRemoteRejection): CollaborationState;
|
|
107
165
|
/**
|
|
108
166
|
* Received a retry message from the server, meaning that some unexpected error occurred in server.
|
|
109
167
|
*/
|
|
110
|
-
abstract onRemoteRetry(changeset: IChangeset): CollaborationState;
|
|
168
|
+
abstract onRemoteRetry(changeset: IChangeset, code?: number): CollaborationState;
|
|
111
169
|
abstract toggleOffline(): CollaborationState;
|
|
112
170
|
abstract toggleOnline(): CollaborationState;
|
|
113
171
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
172
|
+
* Classify a remote changeset against the local copy. Pure: nothing is requested from the server.
|
|
173
|
+
*
|
|
174
|
+
* - `echo`: the awaiting changeset came back as a broadcast, e.g. when the request was committed after the client
|
|
175
|
+
* reconnected with another member id. It acknowledges the awaiting changeset even when the loaded snapshot
|
|
176
|
+
* already contains its revision, so it is checked first.
|
|
177
|
+
* - `applied`: servers may deliver a changeset more than once or out of order, e.g. when several server nodes
|
|
178
|
+
* relay changesets, or after the snapshot used to join already contains it. Applied revisions are ignored.
|
|
179
|
+
* - `missing`: there is a gap before this changeset. The missing changesets have to be fetched first.
|
|
180
|
+
* - `apply`: the changeset is the next revision and can be transformed and applied.
|
|
181
|
+
*/
|
|
182
|
+
protected _classifyRemoteChangeset(changeset: IChangeset): RemoteChangesetKind;
|
|
183
|
+
/**
|
|
184
|
+
* Classify an acknowledgement against the local copy. Pure: nothing is requested from the server.
|
|
116
185
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
186
|
+
* - `ack_of_awaiting`: the revision is already applied but sid/reqId match the awaiting changeset, i.e. the
|
|
187
|
+
* changeset was committed before the loaded snapshot, which already contains it.
|
|
188
|
+
* - `stale`: the revision is already applied and belongs to an earlier changeset.
|
|
189
|
+
* - `missing`: there is a gap before the acknowledged revision. The missing changesets have to be fetched first.
|
|
190
|
+
* - `next`: the acknowledged revision is the next one.
|
|
119
191
|
*/
|
|
120
|
-
protected
|
|
192
|
+
protected _classifyAck(ack: IAcknowledgedChangeset): RemoteAckKind;
|
|
193
|
+
/**
|
|
194
|
+
* Handle a remote changeset the way every online state does: an echo acknowledges the awaiting changeset, an
|
|
195
|
+
* applied revision is ignored, a gap is requested from the server before `onMissing` transits to
|
|
196
|
+
* `FetchingMissState`, and the next revision is handed to `onApply`.
|
|
197
|
+
*/
|
|
198
|
+
protected _dispatchRemoteChangeset(changeset: IChangeset, handlers: {
|
|
199
|
+
onMissing: (changeset: IChangeset) => CollaborationState;
|
|
200
|
+
onApply: (changeset: IChangeset) => CollaborationState;
|
|
201
|
+
/** The unit was reverted on the server: enter `ConflictState` with `_remoteRevertInfo(changeset)`. */
|
|
202
|
+
onRemoteRevert: (changeset: IChangeset) => CollaborationState;
|
|
203
|
+
}): CollaborationState;
|
|
204
|
+
/** The conflict info of a remote changeset that reverts this unit. */
|
|
205
|
+
protected _remoteRevertInfo(changeset: IChangeset): IConflictInfo;
|
|
206
|
+
/** The conflict info of an error thrown while transforming or applying a remote changeset. */
|
|
207
|
+
protected _conflictInfoFromError(error: unknown): IConflictInfo;
|
|
208
|
+
/** The conflict info of a rejection from the server. */
|
|
209
|
+
protected _rejectionInfo(config?: IRemoteRejection): IConflictInfo;
|
|
210
|
+
/** The resend reason for a `changeset_should_retry`, by the code the server attached to it. */
|
|
211
|
+
protected _retryReason(code?: number): ChangesetResendReason;
|
|
212
|
+
/** Request the changesets after the current revision up to `revision`: left open, right closed. */
|
|
213
|
+
protected _requestMissingChangesets(revision: number): void;
|
|
121
214
|
/** Transform undo redo mutations in the undo redo stack. */
|
|
122
215
|
protected _transformUndoredo(changeset: IChangeset): void;
|
|
123
216
|
/** Transform selections by calling the selection manager service. */
|
|
@@ -129,15 +222,7 @@ export declare abstract class CollaborationState {
|
|
|
129
222
|
protected _transformRemoteChangesetByStateCache(changeset: IChangeset): IChangeset;
|
|
130
223
|
protected _syncEditingCollabCursor(changeset: IChangeset): void;
|
|
131
224
|
protected _getCurrentRevision(): number;
|
|
132
|
-
/**
|
|
133
|
-
* Servers may deliver a changeset more than once or out of order, e.g. when several server nodes relay
|
|
134
|
-
* changesets, or after the snapshot used to join already contains it. Revisions already applied are ignored.
|
|
135
|
-
*/
|
|
136
|
-
protected _isAppliedRevision(changeset: IChangeset): boolean;
|
|
137
|
-
/**
|
|
138
|
-
* The awaiting changeset may come back as a broadcast instead of an acknowledgement, e.g. when the request
|
|
139
|
-
* was committed after the client reconnected with another member id.
|
|
140
|
-
*/
|
|
225
|
+
/** The awaiting changeset came back as a broadcast instead of an acknowledgement. */
|
|
141
226
|
protected _isEchoedAwaitingChangeset(remoteChangeset: IChangeset): boolean;
|
|
142
227
|
/**
|
|
143
228
|
* The acknowledgement echoes the committed changeset, so it can be matched to the awaiting changeset by sid/reqId
|
|
@@ -160,6 +245,7 @@ export declare class SyncedState extends CollaborationState {
|
|
|
160
245
|
constructor(unitID: string, type: UniverInstanceType, handler: ICollaborationStateHandler, revisionService: RevisionService, _injector: Injector, undoRedoService: ICollaborativeUndoRedoService, commandService: ICommandService, _logService: ILogService, _transformService: ITransformService, localCacheService?: ILocalCacheService | undefined);
|
|
161
246
|
appendMutation(mutation: IMutationInfo): CollaborationState;
|
|
162
247
|
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
248
|
+
private _transformAndApply;
|
|
163
249
|
private _onConflict;
|
|
164
250
|
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
165
251
|
onRemoteRej(): CollaborationState;
|
|
@@ -187,6 +273,7 @@ export declare class PendingState extends CollaborationState {
|
|
|
187
273
|
constructor(unitID: string, type: UniverInstanceType, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, _injector: Injector, _revisionService: RevisionService, _userManagerService: UserManagerService, _logService: ILogService, commandService: ICommandService, _configService: IConfigService, _transformService: ITransformService, _univerInstanceService: IUniverInstanceService, _undoRedoService: ICollaborativeUndoRedoService, _localCacheService?: ILocalCacheService);
|
|
188
274
|
appendMutation(mutation: IMutationInfo): CollaborationState;
|
|
189
275
|
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
276
|
+
private _transformAndApply;
|
|
190
277
|
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
191
278
|
onRemoteRej(): CollaborationState;
|
|
192
279
|
onRemoteRetry(): CollaborationState;
|
|
@@ -195,6 +282,7 @@ export declare class PendingState extends CollaborationState {
|
|
|
195
282
|
private _getSendChangesetTimeout;
|
|
196
283
|
resend(): void;
|
|
197
284
|
private _clearScheduledTask;
|
|
285
|
+
dispose(): void;
|
|
198
286
|
private _onConflict;
|
|
199
287
|
}
|
|
200
288
|
/**
|
|
@@ -205,27 +293,23 @@ export declare class AwaitingState extends CollaborationState {
|
|
|
205
293
|
private readonly _logService;
|
|
206
294
|
private readonly _transformService;
|
|
207
295
|
readonly status = CollaborationStatus.AWAITING;
|
|
208
|
-
|
|
209
|
-
private
|
|
210
|
-
|
|
211
|
-
private _sender;
|
|
212
|
-
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: IChangeset, handler: ICollaborationStateHandler, schedule: IResendSchedule | undefined, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, _logService: ILogService, _transformService: ITransformService, undoRedoService: ICollaborativeUndoRedoService, localCacheService?: ILocalCacheService);
|
|
296
|
+
/** Resends the awaiting changeset until it is acknowledged. Handed to the next state that keeps the changeset. */
|
|
297
|
+
private readonly _submitter;
|
|
298
|
+
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: IChangeset, handler: ICollaborationStateHandler, submitter: ChangesetSubmitter | undefined, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, _logService: ILogService, _transformService: ITransformService, undoRedoService: ICollaborativeUndoRedoService, localCacheService?: ILocalCacheService);
|
|
213
299
|
appendMutation(mutation: IMutationInfo): CollaborationState;
|
|
214
300
|
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
301
|
+
private _transformAndApply;
|
|
215
302
|
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
onRemoteRetry(changeset: IChangeset): CollaborationState;
|
|
303
|
+
private _toSynced;
|
|
304
|
+
onRemoteRej(config?: IRemoteRejection): CollaborationState;
|
|
305
|
+
onRemoteRetry(changeset: IChangeset, code?: number): CollaborationState;
|
|
220
306
|
toggleOffline(): CollaborationState;
|
|
221
307
|
toggleOnline(): CollaborationState;
|
|
222
|
-
resend(): void;
|
|
308
|
+
resend(reason?: ChangesetResendReason): void;
|
|
223
309
|
private _onConflict;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
private _resendSchedule;
|
|
228
|
-
private _clearScheduledTask;
|
|
310
|
+
dispose(): void;
|
|
311
|
+
/** Detach from the submitter before the awaiting changeset is handed to the next state. */
|
|
312
|
+
private _detachSubmitter;
|
|
229
313
|
}
|
|
230
314
|
/**
|
|
231
315
|
* Some local mutations are sent to the server and waiting for acknowledgement, yet still some local mutations
|
|
@@ -237,44 +321,49 @@ export declare class AwaitingWithPendingState extends CollaborationState {
|
|
|
237
321
|
private readonly _transformService;
|
|
238
322
|
private readonly localCacheService?;
|
|
239
323
|
readonly status = CollaborationStatus.AWAITING_WITH_PENDING;
|
|
240
|
-
|
|
241
|
-
private
|
|
242
|
-
|
|
243
|
-
private _sender;
|
|
244
|
-
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: IChangeset, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, schedule: IResendSchedule | undefined, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, _logService: ILogService, _transformService: ITransformService, undoRedoService: ICollaborativeUndoRedoService, localCacheService?: ILocalCacheService | undefined);
|
|
324
|
+
/** Resends the awaiting changeset until it is acknowledged. Handed to the next state that keeps the changeset. */
|
|
325
|
+
private readonly _submitter;
|
|
326
|
+
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: IChangeset, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, submitter: ChangesetSubmitter | undefined, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, _logService: ILogService, _transformService: ITransformService, undoRedoService: ICollaborativeUndoRedoService, localCacheService?: ILocalCacheService | undefined);
|
|
245
327
|
appendMutation(mutation: IMutationInfo): CollaborationState;
|
|
246
328
|
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
329
|
+
private _transformAndApply;
|
|
247
330
|
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
onRemoteRetry(changeset: IChangeset): CollaborationState;
|
|
331
|
+
/** Transit to `PendingState` to schedule another sending task. */
|
|
332
|
+
private _toPending;
|
|
333
|
+
onRemoteRej(config?: IRemoteRejection): CollaborationState;
|
|
334
|
+
onRemoteRetry(changeset: IChangeset, code?: number): CollaborationState;
|
|
252
335
|
toggleOffline(): CollaborationState;
|
|
253
336
|
toggleOnline(): CollaborationState;
|
|
254
|
-
resend(): void;
|
|
337
|
+
resend(reason?: ChangesetResendReason): void;
|
|
255
338
|
private _onConflict;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
private _resendSchedule;
|
|
260
|
-
private _clearScheduledTask;
|
|
339
|
+
dispose(): void;
|
|
340
|
+
/** Detach from the submitter before the awaiting changeset is handed to the next state. */
|
|
341
|
+
private _detachSubmitter;
|
|
261
342
|
}
|
|
262
343
|
/**
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* `ConflictState` is a dead end state. It cannot transit to any other state. User could only reload the page to
|
|
266
|
-
* reload the document.
|
|
344
|
+
* A dead end state: the unit can no longer follow the server. Editing is disabled. `info` says why and `localChanges`
|
|
345
|
+
* holds the local edits the server has not acknowledged. Reported once through `CollaborationEntity.conflict$`.
|
|
267
346
|
*/
|
|
268
347
|
export declare class ConflictState extends CollaborationState {
|
|
269
|
-
|
|
348
|
+
readonly info: IConflictInfo;
|
|
270
349
|
private readonly _permissionService;
|
|
271
|
-
private readonly _localeService;
|
|
272
350
|
private readonly _userManagerService;
|
|
273
351
|
private readonly _logService;
|
|
274
352
|
private readonly _collaborationUIEventService;
|
|
275
353
|
private readonly localCacheService?;
|
|
276
354
|
readonly status = CollaborationStatus.CONFLICT;
|
|
277
|
-
|
|
355
|
+
/**
|
|
356
|
+
* The local edits the server has not acknowledged, in the format of the offline cache, or `null` when there are
|
|
357
|
+
* none. `awaitingChangeset` has been sent; whether the server applied it is unknown.
|
|
358
|
+
*/
|
|
359
|
+
readonly localChanges: IUnitCacheData | null;
|
|
360
|
+
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: Nullable<IChangeset>, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, info: IConflictInfo, _permissionService: IPermissionService, commandService: ICommandService, undoRedoService: ICollaborativeUndoRedoService, revisionService: RevisionService, _userManagerService: UserManagerService, _logService: ILogService, _collaborationUIEventService: CollaborationUIEventService, localCacheService?: ILocalCacheService | undefined);
|
|
361
|
+
/**
|
|
362
|
+
* Back up the unacknowledged local edits, then clear the offline cache so that the next load does not replay them
|
|
363
|
+
* (a cache with pending edits would also make the loader fetch the cached revision). Only then is the conflict
|
|
364
|
+
* reported, so that the handler may reload the page safely.
|
|
365
|
+
*/
|
|
366
|
+
private _prepareConflictRecovery;
|
|
278
367
|
appendMutation(): CollaborationState;
|
|
279
368
|
onRemoteChangeset(): CollaborationState;
|
|
280
369
|
onRemoteAck(): CollaborationState;
|
|
@@ -283,18 +372,17 @@ export declare class ConflictState extends CollaborationState {
|
|
|
283
372
|
toggleOffline(): CollaborationState;
|
|
284
373
|
toggleOnline(): CollaborationState;
|
|
285
374
|
resend(): void;
|
|
286
|
-
private _prepareConflictRecovery;
|
|
287
375
|
private _showConflictProcessingNotification;
|
|
288
|
-
private _showConflictNotification;
|
|
289
376
|
private _disableEditing;
|
|
290
377
|
}
|
|
291
378
|
export declare class OfflineState extends CollaborationState {
|
|
292
379
|
private readonly _injector;
|
|
380
|
+
private readonly _logService;
|
|
293
381
|
readonly status = CollaborationStatus.OFFLINE;
|
|
294
|
-
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: Nullable<IChangeset>, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, undoRedoService: ICollaborativeUndoRedoService, localCacheService?: ILocalCacheService);
|
|
382
|
+
constructor(unitID: string, type: UniverInstanceType, awaitingChangeset: Nullable<IChangeset>, pendingMutations: IMutationInfo[], handler: ICollaborationStateHandler, _injector: Injector, revisionService: RevisionService, commandService: ICommandService, undoRedoService: ICollaborativeUndoRedoService, _logService: ILogService, localCacheService?: ILocalCacheService);
|
|
295
383
|
appendMutation(mutation: IMutationInfo): CollaborationState;
|
|
296
|
-
onRemoteChangeset(
|
|
297
|
-
onRemoteAck(): CollaborationState;
|
|
384
|
+
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
385
|
+
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
298
386
|
onRemoteRej(): CollaborationState;
|
|
299
387
|
onRemoteRetry(): CollaborationState;
|
|
300
388
|
toggleOffline(): CollaborationState;
|
|
@@ -315,8 +403,11 @@ export declare class FetchingMissState extends CollaborationState {
|
|
|
315
403
|
*/
|
|
316
404
|
private _acknowledgedAwaitingRevision;
|
|
317
405
|
private _queuedRemoteChangesets;
|
|
318
|
-
/**
|
|
319
|
-
|
|
406
|
+
/**
|
|
407
|
+
* The resends of the awaiting changeset. It is not bound while the gap is fetched: a resend that comes due
|
|
408
|
+
* meanwhile runs once the next awaiting state binds it.
|
|
409
|
+
*/
|
|
410
|
+
private _submitter;
|
|
320
411
|
private readonly _injector;
|
|
321
412
|
private readonly _logService;
|
|
322
413
|
private readonly _transformService;
|
|
@@ -329,8 +420,11 @@ export declare class FetchingMissState extends CollaborationState {
|
|
|
329
420
|
* the acknowledged server revision here.
|
|
330
421
|
*/
|
|
331
422
|
_acknowledgedAwaitingRevision: Nullable<number>, _queuedRemoteChangesets: IChangeset[], handler: ICollaborationStateHandler,
|
|
332
|
-
/**
|
|
333
|
-
|
|
423
|
+
/**
|
|
424
|
+
* The resends of the awaiting changeset. It is not bound while the gap is fetched: a resend that comes due
|
|
425
|
+
* meanwhile runs once the next awaiting state binds it.
|
|
426
|
+
*/
|
|
427
|
+
_submitter: ChangesetSubmitter | undefined, _injector: Injector, revisionService: RevisionService, _logService: ILogService, commandService: ICommandService, undoRedoService: ICollaborativeUndoRedoService, _transformService: ITransformService, localCacheService?: ILocalCacheService | undefined);
|
|
334
428
|
onMissedChangesetFetched(changesets: IChangeset[]): CollaborationState;
|
|
335
429
|
private _handleRemoteChangesets;
|
|
336
430
|
private _transformAndApplyRemoteChangeset;
|
|
@@ -338,14 +432,14 @@ export declare class FetchingMissState extends CollaborationState {
|
|
|
338
432
|
private _acknowledgeAwaiting;
|
|
339
433
|
/** The awaiting changeset was committed before the loaded snapshot, so there is no new revision to count. */
|
|
340
434
|
private _dropAcknowledgedAwaiting;
|
|
435
|
+
private _disposeSubmitter;
|
|
436
|
+
dispose(): void;
|
|
341
437
|
resend(): void;
|
|
342
438
|
appendMutation(mutation: IMutationInfo<object>): CollaborationState;
|
|
343
439
|
onRemoteChangeset(changeset: IChangeset): CollaborationState;
|
|
344
440
|
onRemoteAck(changeset: IAcknowledgedChangeset): CollaborationState;
|
|
345
|
-
onRemoteRej(config?:
|
|
346
|
-
|
|
347
|
-
}): CollaborationState;
|
|
348
|
-
onRemoteRetry(changeset: IChangeset): CollaborationState;
|
|
441
|
+
onRemoteRej(config?: IRemoteRejection): CollaborationState;
|
|
442
|
+
onRemoteRetry(changeset: IChangeset, code?: number): CollaborationState;
|
|
349
443
|
toggleOffline(): CollaborationState;
|
|
350
444
|
toggleOnline(): CollaborationState;
|
|
351
445
|
private _onConflict;
|