-
Notifications
You must be signed in to change notification settings - Fork 61
[DTP-954, DTP-956] Add support for applying incoming state operations outside of STATE_SYNC sequence #1897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
VeskeR
merged 11 commits into
integration/liveobjects
from
liveobjects/apply-incoming-operations
Nov 8, 2024
Merged
[DTP-954, DTP-956] Add support for applying incoming state operations outside of STATE_SYNC sequence #1897
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
8e31a6a
Add Timeserial class to LiveObjects plugin
VeskeR 692f6ed
Add ObjectId class to parse object id strings
VeskeR 131fc4e
Preparation for CRDT operations implementation
VeskeR 9b83e94
Implement support for applying incoming operations to LiveMap/LiveCou…
VeskeR 9f98ef6
Preparation for applying incoming state operations
VeskeR 0b646e2
Implement application of incoming state operation messages outside of…
VeskeR ef54890
Preparation for LiveObjects tests for applying incoming operations
VeskeR bda102c
Add LiveObjects tests for applying incoming operation messages outsid…
VeskeR 3960852
Update `moduleReport` config with latest bundle info
VeskeR 3ed285d
Add `zeroValue` static method to LiveMap and LiveCounter
VeskeR b988c35
Fix LiveObjects tests fail due to class name changes with static prop…
VeskeR File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,121 @@ | ||
| import { LiveObject, LiveObjectData } from './liveobject'; | ||
| import { LiveObjects } from './liveobjects'; | ||
| import { StateCounter, StateCounterOp, StateOperation, StateOperationAction } from './statemessage'; | ||
|
|
||
| export interface LiveCounterData extends LiveObjectData { | ||
| data: number; | ||
| } | ||
|
|
||
| export class LiveCounter extends LiveObject<LiveCounterData> { | ||
| constructor( | ||
| liveObjects: LiveObjects, | ||
| private _created: boolean, | ||
| initialData?: LiveCounterData | null, | ||
| objectId?: string, | ||
| ) { | ||
| super(liveObjects, initialData, objectId); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a {@link LiveCounter} instance with a 0 value. | ||
| * | ||
| * @internal | ||
| */ | ||
| static zeroValue(liveobjects: LiveObjects, isCreated: boolean, objectId?: string): LiveCounter { | ||
| return new LiveCounter(liveobjects, isCreated, null, objectId); | ||
| } | ||
|
|
||
| value(): number { | ||
| return this._dataRef.data; | ||
| } | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
| isCreated(): boolean { | ||
| return this._created; | ||
| } | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
| setCreated(created: boolean): void { | ||
| this._created = created; | ||
| } | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
| applyOperation(op: StateOperation): void { | ||
| if (op.objectId !== this.getObjectId()) { | ||
| throw new this._client.ErrorInfo( | ||
| `Cannot apply state operation with objectId=${op.objectId}, to this LiveCounter with objectId=${this.getObjectId()}`, | ||
| 50000, | ||
| 500, | ||
| ); | ||
| } | ||
|
|
||
| switch (op.action) { | ||
| case StateOperationAction.COUNTER_CREATE: | ||
| this._applyCounterCreate(op.counter); | ||
| break; | ||
|
|
||
| case StateOperationAction.COUNTER_INC: | ||
| if (this._client.Utils.isNil(op.counterOp)) { | ||
owenpearson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| this._throwNoPayloadError(op); | ||
| } else { | ||
| this._applyCounterInc(op.counterOp); | ||
| } | ||
| break; | ||
|
|
||
| default: | ||
| throw new this._client.ErrorInfo( | ||
| `Invalid ${op.action} op for LiveCounter objectId=${this.getObjectId()}`, | ||
| 50000, | ||
| 500, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| protected _getZeroValueData(): LiveCounterData { | ||
| return { data: 0 }; | ||
| } | ||
|
|
||
| private _throwNoPayloadError(op: StateOperation): void { | ||
| throw new this._client.ErrorInfo( | ||
| `No payload found for ${op.action} op for LiveCounter objectId=${this.getObjectId()}`, | ||
| 50000, | ||
| 500, | ||
| ); | ||
| } | ||
|
|
||
| private _applyCounterCreate(op: StateCounter | undefined): void { | ||
| if (this.isCreated()) { | ||
| // skip COUNTER_CREATE op if this counter is already created | ||
| this._client.Logger.logAction( | ||
| this._client.logger, | ||
| this._client.Logger.LOG_MICRO, | ||
| 'LiveCounter._applyCounterCreate()', | ||
| `skipping applying COUNTER_CREATE op on a counter instance as it is already created; objectId=${this._objectId}`, | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| if (this._client.Utils.isNil(op)) { | ||
| // if a counter object is missing for the COUNTER_CREATE op, the initial value is implicitly 0 in this case. | ||
| // we need to SUM the initial value to the current value due to the reasons below, but since it's a 0, we can skip addition operation | ||
| this.setCreated(true); | ||
| return; | ||
| } | ||
|
|
||
| // note that it is intentional to SUM the incoming count from the create op. | ||
| // if we get here, it means that current counter instance wasn't initialized from the COUNTER_CREATE op, | ||
| // so it is missing the initial value that we're going to add now. | ||
| this._dataRef.data += op.count ?? 0; | ||
VeskeR marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| this.setCreated(true); | ||
| } | ||
|
|
||
| private _applyCounterInc(op: StateCounterOp): void { | ||
| this._dataRef.data += op.amount; | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.