Skip to content

Commit

Permalink
Merge branch 'dev' into publish-alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
eswarclynn committed May 17, 2024
2 parents 4a92fdb + 8b8bad0 commit 4d8a5b3
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 68 deletions.
32 changes: 8 additions & 24 deletions packages/hms-whiteboard/src/hooks/StoreClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { GrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport';
import { Value_Type } from '../grpc/sessionstore';
import { StoreClient } from '../grpc/sessionstore.client';
import { OPEN_WAIT_TIMEOUT } from '../utils';

interface OpenCallbacks<T> {
handleOpen: (values: T[]) => void;
Expand Down Expand Up @@ -31,28 +32,23 @@ export class SessionStore<T> {
},
{ abort: this.abortController.signal },
);
/**
* on open, get key count to call handleOpen with the pre-existing values from the store
* retry if getKeysCount is called before open call is completed
*/
const keyCount = await this.retryForOpen(this.getKeysCount.bind(this));
const initialValues: T[] = [];
let initialised = false;

if (!keyCount) {
handleOpen([]);
}
// on open, wait to call handleOpen with the pre-existing values from the store
setTimeout(() => {
handleOpen(initialValues);
initialised = true;
}, OPEN_WAIT_TIMEOUT);

call.responses.onMessage(message => {
if (message.value) {
if (message.value?.data.oneofKind === 'str') {
const record = JSON.parse(message.value.data.str) as T;
if (initialValues.length === keyCount) {
if (initialised) {
handleChange(message.key, record);
} else {
initialValues.push(record);
if (initialValues.length === keyCount) {
handleOpen(initialValues);
}
}
}
} else {
Expand Down Expand Up @@ -103,16 +99,4 @@ export class SessionStore<T> {
delete(key: string) {
return this.storeClient.delete({ key });
}

private async retryForOpen<T>(fn: () => Promise<T>, retries = 3): Promise<T> {
try {
return await fn();
} catch (error) {
const shouldRetry = (error as Error).message.includes('peer not found') && retries > 0;
if (!shouldRetry) {
return Promise.reject(error);
}
return await this.retryForOpen(fn, retries - 1);
}
}
}
92 changes: 49 additions & 43 deletions packages/hms-whiteboard/src/hooks/useCollaboration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { DEFAULT_STORE } from './default_store';
import { useSessionStore } from './useSessionStore';
import { useSetEditorPermissions } from './useSetEditorPermissions';
import { CURRENT_PAGE_KEY, OPEN_DELAY, PAGES_DEBOUNCE_TIME, SHAPES_THROTTLE_TIME } from '../utils';
import { CURRENT_PAGE_KEY, PAGES_DEBOUNCE_TIME, SHAPES_THROTTLE_TIME } from '../utils';

// mandatory record types required for initialisation of the whiteboard and for a full remote sync
const FULL_SYNC_REQUIRED_RECORD_TYPES: TLRecord['typeName'][] = [
Expand Down Expand Up @@ -63,37 +63,14 @@ export function useCollaboration({
}, []);

const sessionStore = useSessionStore({ token, endpoint, handleError });
const permissions = useSetEditorPermissions({ token, editor, zoomToContent, handleError });

useSetEditorPermissions({ token, editor, zoomToContent, handleError });

useEffect(() => {
if (!sessionStore) return;

setStoreWithStatus({ status: 'loading' });

const unsubs: (() => void)[] = [];

// 1.
// Connect store to yjs store and vis versa, for both the document and awareness

/* -------------------- Document -------------------- */

const handleChange = (key: string, value?: TLRecord) => {
// put / remove the records in the store
store.mergeRemoteChanges(() => {
if (!value) {
return store.remove([key as TLRecord['id']]);
}
if (key === CURRENT_PAGE_KEY) {
setCurrentPage(value as TLPage);
} else {
store.put([value]);
}
});
};
const handleOpen = useCallback(
(initialRecords: TLRecord[]) => {
if (!sessionStore) {
return;
}

const handleOpen = (initialRecords: TLRecord[]) => {
// 2.
// Initialize the tldraw store with the session store server records—or, if the session store
// is empty, initialize the session store server with the default tldraw store records.
const shouldUseServerRecords = FULL_SYNC_REQUIRED_RECORD_TYPES.every(
Expand All @@ -118,20 +95,49 @@ export function useCollaboration({
status: 'synced-remote',
connectionStatus: 'online',
});
};
},
[store, sessionStore],
);

const handleChange = useCallback(
(key: string, value?: TLRecord) => {
// put / remove the records in the store
store.mergeRemoteChanges(() => {
if (!value) {
return store.remove([key as TLRecord['id']]);
}
if (key === CURRENT_PAGE_KEY) {
setCurrentPage(value as TLPage);
} else {
transact(() => {
store.put([value]);
if (key === TLINSTANCE_ID) {
store.put([
{ ...value, canMoveCamera: !!zoomToContent, isReadonly: !permissions.includes('write') } as TLInstance,
]);
}
});
}
});
},
[store, permissions, zoomToContent],
);

useEffect(() => {
if (!sessionStore) return;

setStoreWithStatus({ status: 'loading' });

const unsubs: (() => void)[] = [];

// Open session and sync the session store changes to the store
// On opening, closing and reopening whiteboard with no delay(in case of role change), the session store server needs time to cleanup on the close before opening again
// so there is a delay here before opening the connection
setTimeout(() => {
sessionStore
.open({
handleOpen,
handleChange,
handleError,
})
.then(unsub => unsubs.push(unsub));
}, OPEN_DELAY);
sessionStore
.open({
handleOpen,
handleChange,
handleError,
})
.then(unsub => unsubs.push(unsub));

// Sync store changes to the yjs doc
unsubs.push(
Expand Down Expand Up @@ -187,7 +193,7 @@ export function useCollaboration({
unsubs.forEach(fn => fn());
unsubs.length = 0;
};
}, [store, sessionStore, handleError]);
}, [store, sessionStore, handleChange, handleOpen, handleError]);

useEffect(() => {
if (!editor || !sessionStore) return;
Expand Down
2 changes: 2 additions & 0 deletions packages/hms-whiteboard/src/hooks/useSetEditorPermissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ export const useSetEditorPermissions = ({
const isReadonly = !permissions.includes('write');
editor?.updateInstanceState({ isReadonly });
}, [permissions, zoomToContent, editor]);

return permissions;
};
2 changes: 1 addition & 1 deletion packages/hms-whiteboard/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export default function decodeJWT(token?: string) {
export const CURRENT_PAGE_KEY = 'currentPage';
export const SHAPES_THROTTLE_TIME = 11;
export const PAGES_DEBOUNCE_TIME = 200;
export const OPEN_DELAY = 100;
export const OPEN_WAIT_TIMEOUT = 1000;

0 comments on commit 4d8a5b3

Please sign in to comment.