Skip to content

Commit

Permalink
integrate storage
Browse files Browse the repository at this point in the history
  • Loading branch information
nikgraf committed Jun 6, 2024
1 parent 9305996 commit b3f48d5
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 2 deletions.
48 changes: 46 additions & 2 deletions apps/app/src/app/list/[listId].tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useLocalSearchParams } from "expo-router";
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { View } from "react-native";
import sodium, { KeyPair } from "react-native-libsodium";
import { useYjsSync } from "secsync-react-yjs";
Expand All @@ -9,6 +9,12 @@ import { Input } from "~/components/ui/input";
import { Text } from "~/components/ui/text";
import { useLocker } from "../../hooks/useLocker";
import { useYArray } from "../../hooks/useYArray";
import { deserialize } from "../../utils/deserialize";
import {
documentPendingChangesStorage,
documentStorage,
} from "../../utils/documentStorage";
import { serialize } from "../../utils/serialize";

const websocketEndpoint =
process.env.NODE_ENV === "development"
Expand All @@ -27,15 +33,53 @@ const List: React.FC<Props> = () => {
return sodium.crypto_sign_keypair();
});

const yDocRef = useRef<Yjs.Doc>(new Yjs.Doc());
// load initial data
const [initialData] = useState(() => {
const yDoc = new Yjs.Doc();
// load full document
const serializedDoc = documentStorage.getString(documentId);
if (serializedDoc) {
Yjs.applyUpdateV2(yDoc, deserialize(serializedDoc));
}

// loads the pendingChanges
const pendingChanges = documentPendingChangesStorage.getString(documentId);

return {
yDoc,
pendingChanges: pendingChanges ? deserialize(pendingChanges) : [],
};
});

const yDocRef = useRef<Yjs.Doc>(initialData.yDoc);

// update the document after every change (could be debounced)
useEffect(() => {
const onUpdate = (update: any) => {
const fullYDoc = Yjs.encodeStateAsUpdateV2(yDocRef.current);
documentStorage.set(documentId, serialize(fullYDoc));
};
yDocRef.current.on("updateV2", onUpdate);

return () => {
yDocRef.current.off("updateV2", onUpdate);
};
}, []);

const yTodos: Yjs.Array<string> = yDocRef.current.getArray("todos");
const todos = useYArray(yTodos);
const [newTodoText, setNewTodoText] = useState("");

const { content } = useLocker();
const documentKey = sodium.from_base64(content[`document:${documentId}`]);

const [state, send] = useYjsSync({
yDoc: yDocRef.current,
pendingChanges: initialData.pendingChanges,
// callback to store the pending changes in
onPendingChangesUpdated: (allChanges) => {
documentPendingChangesStorage.set(documentId, serialize(allChanges));
},
documentId,
signatureKeyPair: authorKeyPair,
websocketEndpoint,
Expand Down
12 changes: 12 additions & 0 deletions apps/app/src/utils/deserialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const deserialize = (data: string) => {
return JSON.parse(data, (key, value) => {
if (
typeof value === "object" &&
value !== null &&
value.type === "Uint8Array"
) {
return new Uint8Array(value.data);
}
return value;
});
};
9 changes: 9 additions & 0 deletions apps/app/src/utils/documentStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { MMKV } from "react-native-mmkv";

export const documentStorage = new MMKV({
id: `document-storage`,
});

export const documentPendingChangesStorage = new MMKV({
id: `document-pending-changes-storage`,
});
8 changes: 8 additions & 0 deletions apps/app/src/utils/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const serialize = (data: any) => {
return JSON.stringify(data, (key, value) => {
if (value instanceof Uint8Array) {
return { type: "Uint8Array", data: Array.from(value) };
}
return value;
});
};

0 comments on commit b3f48d5

Please sign in to comment.