Skip to content

Commit

Permalink
feat(doc-storage): impl doc storages
Browse files Browse the repository at this point in the history
  • Loading branch information
forehalo committed Oct 21, 2024
1 parent 3ca052c commit 1b89fe3
Show file tree
Hide file tree
Showing 34 changed files with 2,300 additions and 541 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const allPackages = [
'packages/common/debug',
'packages/common/env',
'packages/common/infra',
'packages/common/theme',
'packages/common/doc-storage',
'tools/cli',
];

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ serde = "1"
serde_json = "1"
sha3 = "0.10"
sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "tls-rustls"] }
log = "0.4"
tiktoken-rs = "0.5"
tokio = "1.37"
uuid = "1.8"
Expand Down
29 changes: 29 additions & 0 deletions packages/backend/server/src/core/doc/storage/doc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
applyUpdate,
diffUpdate,
Doc,
encodeStateAsUpdate,
encodeStateVector,
encodeStateVectorFromUpdate,
mergeUpdates,
UndoManager,
} from 'yjs';
Expand All @@ -19,6 +21,12 @@ export interface DocRecord {
editor?: string;
}

export interface DocDiff {
missing: Uint8Array;
state: Uint8Array;
timestamp: number;
}

export interface DocUpdate {
bin: Uint8Array;
timestamp: number;
Expand Down Expand Up @@ -96,6 +104,27 @@ export abstract class DocStorageAdapter extends Connection {
return snapshot;
}

async getDocDiff(
spaceId: string,
docId: string,
stateVector?: Uint8Array
): Promise<DocDiff | null> {
const doc = await this.getDoc(spaceId, docId);

if (!doc) {
return null;
}

const missing = stateVector ? diffUpdate(doc.bin, stateVector) : doc.bin;
const state = encodeStateVectorFromUpdate(doc.bin);

return {
missing,
state,
timestamp: doc.timestamp,
};
}

abstract pushDocUpdates(
spaceId: string,
docId: string,
Expand Down
4 changes: 3 additions & 1 deletion packages/backend/server/src/core/doc/storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// TODO(@forehalo): share with frontend
// This is a totally copy of definitions in [@affine/doc-storage]
// because currently importing cross workspace package from [@affine/server] is not yet supported
// should be kept updated with the original definitions in [@affine/doc-storage]
import type { BlobStorageAdapter } from './blob';
import { Connection } from './connection';
import type { DocStorageAdapter } from './doc';
Expand Down
31 changes: 12 additions & 19 deletions packages/backend/server/src/core/sync/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
WebSocketGateway,
} from '@nestjs/websockets';
import { Socket } from 'socket.io';
import { diffUpdate, encodeStateVectorFromUpdate } from 'yjs';

import {
AlreadyInSpace,
Expand Down Expand Up @@ -233,31 +232,25 @@ export class SpaceSyncGateway
@MessageBody()
{ spaceType, spaceId, docId, stateVector }: LoadDocMessage
): Promise<
EventResponse<{ missing: string; state?: string; timestamp: number }>
EventResponse<{ missing: string; state: string; timestamp: number }>
> {
const adapter = this.selectAdapter(client, spaceType);
adapter.assertIn(spaceId);

const doc = await adapter.get(spaceId, docId);
const doc = await adapter.diff(
spaceId,
docId,
stateVector ? Buffer.from(stateVector, 'base64') : undefined
);

if (!doc) {
throw new DocNotFound({ spaceId, docId });
}

const missing = Buffer.from(
stateVector
? diffUpdate(doc.bin, Buffer.from(stateVector, 'base64'))
: doc.bin
).toString('base64');

const state = Buffer.from(encodeStateVectorFromUpdate(doc.bin)).toString(
'base64'
);

return {
data: {
missing,
state,
missing: Buffer.from(doc.missing).toString('base64'),
state: Buffer.from(doc.state).toString('base64'),
timestamp: doc.timestamp,
},
};
Expand Down Expand Up @@ -600,9 +593,9 @@ abstract class SyncSocketAdapter {
return this.storage.pushDocUpdates(spaceId, docId, updates, editorId);
}

get(spaceId: string, docId: string) {
diff(spaceId: string, docId: string, stateVector?: Uint8Array) {
this.assertIn(spaceId);
return this.storage.getDoc(spaceId, docId);
return this.storage.getDocDiff(spaceId, docId, stateVector);
}

getTimestamps(spaceId: string, timestamp?: number) {
Expand Down Expand Up @@ -630,9 +623,9 @@ class WorkspaceSyncAdapter extends SyncSocketAdapter {
return super.push(spaceId, id.guid, updates, editorId);
}

override get(spaceId: string, docId: string) {
override diff(spaceId: string, docId: string, stateVector?: Uint8Array) {
const id = new DocID(docId, spaceId);
return this.storage.getDoc(spaceId, id.guid);
return this.storage.getDocDiff(spaceId, id.guid, stateVector);
}

async assertAccessible(
Expand Down
22 changes: 22 additions & 0 deletions packages/common/doc-storage/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@affine/doc-storage",
"type": "module",
"version": "0.15.0",
"private": true,
"sideEffects": false,
"exports": {
".": "./index.ts",
"./impls/*": "./impls/*",
"./storage": "./storage/index.ts"
},
"dependencies": {
"@affine/native": "workspace:*",
"idb": "^8.0.0",
"lodash-es": "^4.17.21",
"socket.io-client": "^4.7.5",
"yjs": "patch:yjs@npm%3A13.6.18#~/.yarn/patches/yjs-npm-13.6.18-ad0d5f7c43.patch"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12"
}
}
Loading

0 comments on commit 1b89fe3

Please sign in to comment.