@ -22,7 +22,7 @@ import {
FIREBASE_STORAGE_PREFIXES ,
FIREBASE_STORAGE_PREFIXES ,
INITIAL_SCENE_UPDATE_TIMEOUT ,
INITIAL_SCENE_UPDATE_TIMEOUT ,
LOAD_IMAGES_TIMEOUT ,
LOAD_IMAGES_TIMEOUT ,
SCENE,
WS_ SCENE_EVENT_TYPES ,
STORAGE_KEYS ,
STORAGE_KEYS ,
SYNC_FULL_SCENE_INTERVAL_MS ,
SYNC_FULL_SCENE_INTERVAL_MS ,
} from "../app_constants" ;
} from "../app_constants" ;
@ -88,7 +88,7 @@ export interface CollabAPI {
onPointerUpdate : CollabInstance [ "onPointerUpdate" ] ;
onPointerUpdate : CollabInstance [ "onPointerUpdate" ] ;
initializeSocketClient : CollabInstance [ "initializeSocketClient" ] ;
initializeSocketClient : CollabInstance [ "initializeSocketClient" ] ;
onCollabButtonClick : CollabInstance [ "onCollabButtonClick" ] ;
onCollabButtonClick : CollabInstance [ "onCollabButtonClick" ] ;
broadcastElements: CollabInstance [ "broadcast Elements"] ;
syncElements: CollabInstance [ "sync Elements"] ;
fetchImageFilesFromFirebase : CollabInstance [ "fetchImageFilesFromFirebase" ] ;
fetchImageFilesFromFirebase : CollabInstance [ "fetchImageFilesFromFirebase" ] ;
setUsername : ( username : string ) = > void ;
setUsername : ( username : string ) = > void ;
}
}
@ -232,12 +232,20 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
} ) ;
} ) ;
saveCollabRoomToFirebase = async (
saveCollabRoomToFirebase = async (
syncableElements : readonly ExcalidrawElement [ ] = this . getSyncableElements (
syncableElements : readonly ExcalidrawElement [ ] ,
this . excalidrawAPI . getSceneElementsIncludingDeleted ( ) ,
) ,
) = > {
) = > {
try {
try {
await saveToFirebase ( this . portal , syncableElements ) ;
const savedData = await saveToFirebase (
this . portal ,
syncableElements ,
this . excalidrawAPI . getAppState ( ) ,
) ;
if ( this . isCollaborating ( ) && savedData && savedData . reconciledElements ) {
this . handleRemoteSceneUpdate (
this . reconcileElements ( savedData . reconciledElements ) ,
) ;
}
} catch ( error : any ) {
} catch ( error : any ) {
console . error ( error ) ;
console . error ( error ) ;
}
}
@ -250,9 +258,14 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
closePortal = ( ) = > {
closePortal = ( ) = > {
this . queueBroadcastAllElements . cancel ( ) ;
this . queueBroadcastAllElements . cancel ( ) ;
this . queueSaveToFirebase . cancel ( ) ;
this . loadImageFiles . cancel ( ) ;
this . loadImageFiles . cancel ( ) ;
this . saveCollabRoomToFirebase ( ) ;
this . saveCollabRoomToFirebase (
this . getSyncableElements (
this . excalidrawAPI . getSceneElementsIncludingDeleted ( ) ,
) ,
) ;
if ( window . confirm ( t ( "alerts.collabStopOverridePrompt" ) ) ) {
if ( window . confirm ( t ( "alerts.collabStopOverridePrompt" ) ) ) {
// hack to ensure that we prefer we disregard any new browser state
// hack to ensure that we prefer we disregard any new browser state
// that could have been saved in other tabs while we were collaborating
// that could have been saved in other tabs while we were collaborating
@ -400,10 +413,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
commitToHistory : true ,
commitToHistory : true ,
} ) ;
} ) ;
this . broadcastElements ( elements ) ;
this . saveCollabRoomToFirebase ( this . getSyncableElements ( elements ) ) ;
const syncableElements = this . getSyncableElements ( elements ) ;
this . saveCollabRoomToFirebase ( syncableElements ) ;
}
}
// fallback in case you're not alone in the room but still don't receive
// fallback in case you're not alone in the room but still don't receive
@ -433,7 +443,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
switch ( decryptedData . type ) {
switch ( decryptedData . type ) {
case "INVALID_RESPONSE" :
case "INVALID_RESPONSE" :
return ;
return ;
case SCENE. INIT : {
case WS_ SCENE_EVENT_TYPES . INIT : {
if ( ! this . portal . socketInitialized ) {
if ( ! this . portal . socketInitialized ) {
this . initializeRoom ( { fetchScene : false } ) ;
this . initializeRoom ( { fetchScene : false } ) ;
const remoteElements = decryptedData . payload . elements ;
const remoteElements = decryptedData . payload . elements ;
@ -449,7 +459,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
}
}
break ;
break ;
}
}
case SCENE. UPDATE :
case WS_ SCENE_EVENT_TYPES . UPDATE :
this . handleRemoteSceneUpdate (
this . handleRemoteSceneUpdate (
this . reconcileElements ( decryptedData . payload . elements ) ,
this . reconcileElements ( decryptedData . payload . elements ) ,
) ;
) ;
@ -711,15 +721,20 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
getSceneVersion ( elements ) >
getSceneVersion ( elements ) >
this . getLastBroadcastedOrReceivedSceneVersion ( )
this . getLastBroadcastedOrReceivedSceneVersion ( )
) {
) {
this . portal . broadcastScene ( SCENE. UPDATE , elements , false ) ;
this . portal . broadcastScene ( WS_ SCENE_EVENT_TYPES . UPDATE , elements , false ) ;
this . lastBroadcastedOrReceivedSceneVersion = getSceneVersion ( elements ) ;
this . lastBroadcastedOrReceivedSceneVersion = getSceneVersion ( elements ) ;
this . queueBroadcastAllElements ( ) ;
this . queueBroadcastAllElements ( ) ;
}
}
} ;
} ;
syncElements = ( elements : readonly ExcalidrawElement [ ] ) = > {
this . broadcastElements ( elements ) ;
this . queueSaveToFirebase ( ) ;
} ;
queueBroadcastAllElements = throttle ( ( ) = > {
queueBroadcastAllElements = throttle ( ( ) = > {
this . portal . broadcastScene (
this . portal . broadcastScene (
SCENE . UPDATE ,
WS_ SCENE_EVENT_TYPES . UPDATE ,
this . excalidrawAPI . getSceneElementsIncludingDeleted ( ) ,
this . excalidrawAPI . getSceneElementsIncludingDeleted ( ) ,
true ,
true ,
) ;
) ;
@ -731,6 +746,16 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
this . setLastBroadcastedOrReceivedSceneVersion ( newVersion ) ;
this . setLastBroadcastedOrReceivedSceneVersion ( newVersion ) ;
} , SYNC_FULL_SCENE_INTERVAL_MS ) ;
} , SYNC_FULL_SCENE_INTERVAL_MS ) ;
queueSaveToFirebase = throttle ( ( ) = > {
if ( this . portal . socketInitialized ) {
this . saveCollabRoomToFirebase (
this . getSyncableElements (
this . excalidrawAPI . getSceneElementsIncludingDeleted ( ) ,
) ,
) ;
}
} , SYNC_FULL_SCENE_INTERVAL_MS ) ;
handleClose = ( ) = > {
handleClose = ( ) = > {
this . setState ( { modalIsShown : false } ) ;
this . setState ( { modalIsShown : false } ) ;
} ;
} ;
@ -771,7 +796,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
this . contextValue . onPointerUpdate = this . onPointerUpdate ;
this . contextValue . onPointerUpdate = this . onPointerUpdate ;
this . contextValue . initializeSocketClient = this . initializeSocketClient ;
this . contextValue . initializeSocketClient = this . initializeSocketClient ;
this . contextValue . onCollabButtonClick = this . onCollabButtonClick ;
this . contextValue . onCollabButtonClick = this . onCollabButtonClick ;
this . contextValue . broadcastElements = this . broadcast Elements;
this . contextValue . syncElements = this . sync Elements;
this . contextValue . fetchImageFilesFromFirebase =
this . contextValue . fetchImageFilesFromFirebase =
this . fetchImageFilesFromFirebase ;
this . fetchImageFilesFromFirebase ;
this . contextValue . setUsername = this . setUsername ;
this . contextValue . setUsername = this . setUsername ;