Skip to content

Commit

Permalink
Implement cell-based sync + undo/redo
Browse files Browse the repository at this point in the history
  • Loading branch information
AriaMinaei committed Oct 8, 2023
1 parent 96f51ec commit 7d1473f
Show file tree
Hide file tree
Showing 47 changed files with 2,015 additions and 427 deletions.
172 changes: 172 additions & 0 deletions packages/saaz/src/__snapshots__/rogue.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Rogue merging defaults 1`] = `
{
"a": {
"aStep": 1,
"bStep": 1,
"foo": "setBy1",
"obj": {
"objA": "true",
"objB": "true",
},
},
}
`;

exports[`Rogue overriding an existing prop 1`] = `
[
{
"branchName": "base",
"path": [
[
"base",
"a",
],
],
"type": "SetBoxedValue",
"value": 2,
},
]
`;

exports[`Rogue setting a non-existing prop 1`] = `
[
{
"$branches": {
"base": {
"$mapProps": {
"a": {
"$branches": {
"base": {
"$boxedValue": 1,
},
},
"$type": [
"boxed",
"base",
],
},
},
},
},
"$type": [
"map",
"base",
],
},
[
{
"path": [
[
"base",
"a",
],
],
"type": "ChangeType",
"value": [
"boxed",
"base",
],
},
{
"branchName": "base",
"path": [
[
"base",
"a",
],
],
"type": "SetBoxedValue",
"value": 1,
},
],
]
`;

exports[`Rogue setting a non-existing prop to an object 1`] = `
[
{
"$branches": {
"base": {
"$mapProps": {
"a": {
"$branches": {
"base": {
"$mapProps": {
"b": {
"$branches": {
"base": {
"$boxedValue": 1,
},
},
"$type": [
"boxed",
"base",
],
},
},
},
},
"$type": [
"map",
"base",
],
},
},
},
},
"$type": [
"map",
"base",
],
},
[
{
"path": [
[
"base",
"a",
],
],
"type": "ChangeType",
"value": [
"map",
"base",
],
},
{
"path": [
[
"base",
"a",
],
[
"base",
"b",
],
],
"type": "ChangeType",
"value": [
"boxed",
"base",
],
},
{
"branchName": "base",
"path": [
[
"base",
"a",
],
[
"base",
"b",
],
],
"type": "SetBoxedValue",
"value": 1,
},
],
]
`;
24 changes: 14 additions & 10 deletions packages/saaz/src/back/SaazBack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,28 @@ import type {
PeerSubscribeCallback,
AllPeersPresenceState,
PeerPresenceState,
FullSnapshot,
} from '../types'
import {BackStorage} from './BackStorage'
import type {DebouncedFunc} from 'lodash-es'
import {cloneDeep, throttle} from 'lodash-es'
import {ensureStateIsUptodate} from '../shared/utils'
import {ensureStateIsUptodate as ensureOpStateIsUptodate} from '../shared/utils'
import {Atom} from '@theatre/dataverse'
import deepEqual from '@theatre/utils/deepEqual'

export default class SaazBack implements SaazBackInterface {
private _dbName: string
private _storage: BackStorage
private _readyDeferred = defer<void>()
private _dbState: {} = {}
private _dbState: FullSnapshot<$IntentionalAny> = {cell: {}, op: {}}
private _clock: number | null = null
private _peerStates: {
[peerId in string]?: {
lastIncorporatedPeerClock: number
}
} = {}
private _subsribers: Array<PeerSubscribeCallback> = []
private _schema: Schema<$IntentionalAny>
private _schema: Schema<{$schemaVersion: number}>
private _presenceState: Atom<AllPeersPresenceState> = new Atom({})
private _schedulePresenseUpdate: DebouncedFunc<() => void>

Expand Down Expand Up @@ -113,7 +114,10 @@ export default class SaazBack implements SaazBackInterface {
clock: this._clock ?? -1,
lastIncorporatedPeerClock:
this._peerStates[opts.peerId]?.lastIncorporatedPeerClock ?? null,
snapshot: {type: 'Snapshot', value: this._dbState},
snapshot: {
type: 'Snapshot',
value: this._dbState,
},
}
}

Expand Down Expand Up @@ -168,7 +172,7 @@ export default class SaazBack implements SaazBackInterface {
const peerState = this._peerStates[opts.peerId]!

const rebasing = opts.backendClock !== this._clock
let stateSoFar = ensureStateIsUptodate(this._dbState, this._schema)
let snapshotSoFar = ensureOpStateIsUptodate(this._dbState, this._schema)
let lastAcknowledgedClock = peerState.lastIncorporatedPeerClock
let backendClock = this._clock ?? -1
const updatesToIncorporate = []
Expand All @@ -178,20 +182,20 @@ export default class SaazBack implements SaazBackInterface {
continue
}

const before = stateSoFar
const [after] = applyOptimisticUpdateToState(
const snapshotBefore = snapshotSoFar
const [opSnapshotAfter] = applyOptimisticUpdateToState(
update,
before,
snapshotBefore,
this._schema,
true,
)
stateSoFar = after
snapshotSoFar = opSnapshotAfter
lastAcknowledgedClock = update.peerClock
backendClock++
}

if (lastAcknowledgedClock !== peerState.lastIncorporatedPeerClock) {
this._dbState = stateSoFar
this._dbState = snapshotSoFar
peerState.lastIncorporatedPeerClock = lastAcknowledgedClock
this._clock = backendClock
this._callSubscribersForBackendStateUpdate()
Expand Down
Loading

1 comment on commit 7d1473f

@vercel
Copy link

@vercel vercel bot commented on 7d1473f Oct 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.