2022-10-22 13:57:44 +00:00
use crate ::editor ::{ initial_document_content , AppFlowyDocumentEditor , DocumentRevisionCompress } ;
use crate ::entities ::{ DocumentVersionPB , EditParams } ;
use crate ::old_editor ::editor ::{ DeltaDocumentEditor , DeltaDocumentRevisionCompress } ;
use crate ::services ::DocumentPersistence ;
2022-10-20 03:35:11 +00:00
use crate ::{ errors ::FlowyError , DocumentCloudService } ;
2021-11-09 08:00:09 +00:00
use bytes ::Bytes ;
2021-12-10 03:05:23 +00:00
use dashmap ::DashMap ;
2022-03-19 08:52:28 +00:00
use flowy_database ::ConnectionPool ;
use flowy_error ::FlowyResult ;
2022-10-22 13:57:44 +00:00
use flowy_revision ::disk ::{ SQLiteDeltaDocumentRevisionPersistence , SQLiteDocumentRevisionPersistence } ;
2022-06-09 12:58:56 +00:00
use flowy_revision ::{
2022-07-20 06:07:54 +00:00
RevisionCloudService , RevisionManager , RevisionPersistence , RevisionWebSocket , SQLiteRevisionSnapshotPersistence ,
2022-06-09 12:58:56 +00:00
} ;
2022-10-22 13:57:44 +00:00
use flowy_sync ::client_document ::initial_delta_document_content ;
2022-03-19 08:52:28 +00:00
use flowy_sync ::entities ::{
2022-10-22 13:57:44 +00:00
document ::DocumentIdPB ,
2022-01-14 07:23:21 +00:00
revision ::{ md5 , RepeatedRevision , Revision } ,
2022-01-15 03:20:28 +00:00
ws_data ::ServerRevisionWSData ,
2022-01-01 06:23:58 +00:00
} ;
2021-12-13 05:55:44 +00:00
use lib_infra ::future ::FutureResult ;
2022-10-20 03:35:11 +00:00
use lib_ws ::WSConnectState ;
use std ::any ::Any ;
2022-01-14 12:52:03 +00:00
use std ::{ convert ::TryInto , sync ::Arc } ;
2021-07-23 06:37:18 +00:00
2022-10-13 15:29:37 +00:00
pub trait DocumentUser : Send + Sync {
2022-01-22 10:48:43 +00:00
fn user_dir ( & self ) -> Result < String , FlowyError > ;
fn user_id ( & self ) -> Result < String , FlowyError > ;
fn token ( & self ) -> Result < String , FlowyError > ;
2022-10-22 13:57:44 +00:00
}
pub trait DocumentDatabase : Send + Sync {
2022-01-22 10:48:43 +00:00
fn db_pool ( & self ) -> Result < Arc < ConnectionPool > , FlowyError > ;
}
2022-10-20 03:35:11 +00:00
pub trait DocumentEditor : Send + Sync {
2022-10-22 13:57:44 +00:00
/// Called when the document get closed
2022-10-20 03:35:11 +00:00
fn close ( & self ) ;
2022-10-22 13:57:44 +00:00
/// Exports the document content. The content is encoded in the corresponding
/// editor data format.
fn export ( & self ) -> FutureResult < String , FlowyError > ;
/// Duplicate the document inner data into String
fn duplicate ( & self ) -> FutureResult < String , FlowyError > ;
2022-10-20 03:35:11 +00:00
fn receive_ws_data ( & self , data : ServerRevisionWSData ) -> FutureResult < ( ) , FlowyError > ;
2022-10-22 13:57:44 +00:00
2022-10-20 03:35:11 +00:00
fn receive_ws_state ( & self , state : & WSConnectState ) ;
2022-10-22 13:57:44 +00:00
/// Receives the local operations made by the user input. The operations are encoded
/// in binary format.
fn compose_local_operations ( & self , data : Bytes ) -> FutureResult < ( ) , FlowyError > ;
2022-10-20 03:35:11 +00:00
/// Returns the `Any` reference that can be used to downcast back to the original,
/// concrete type.
///
/// The indirection through `as_any` is because using `downcast_ref`
/// on `Box<A>` *directly* only lets us downcast back to `&A` again. You can take a look at [this](https://stackoverflow.com/questions/33687447/how-to-get-a-reference-to-a-concrete-type-from-a-trait-object)
/// for more information.
///
///
fn as_any ( & self ) -> & dyn Any ;
}
#[ derive(Clone, Debug) ]
pub struct DocumentConfig {
2022-10-22 13:57:44 +00:00
pub version : DocumentVersionPB ,
}
impl std ::default ::Default for DocumentConfig {
fn default ( ) -> Self {
Self {
version : DocumentVersionPB ::V1 ,
}
}
2022-10-20 03:35:11 +00:00
}
2022-10-13 15:29:37 +00:00
pub struct DocumentManager {
cloud_service : Arc < dyn DocumentCloudService > ,
2022-02-18 15:04:55 +00:00
rev_web_socket : Arc < dyn RevisionWebSocket > ,
2022-10-13 15:29:37 +00:00
editor_map : Arc < DocumentEditorMap > ,
user : Arc < dyn DocumentUser > ,
2022-10-22 13:57:44 +00:00
persistence : Arc < DocumentPersistence > ,
#[ allow(dead_code) ]
2022-10-20 03:35:11 +00:00
config : DocumentConfig ,
2021-07-23 06:37:18 +00:00
}
2022-10-13 15:29:37 +00:00
impl DocumentManager {
2022-01-14 12:52:03 +00:00
pub fn new (
2022-10-13 15:29:37 +00:00
cloud_service : Arc < dyn DocumentCloudService > ,
document_user : Arc < dyn DocumentUser > ,
2022-10-22 13:57:44 +00:00
database : Arc < dyn DocumentDatabase > ,
2022-02-18 15:04:55 +00:00
rev_web_socket : Arc < dyn RevisionWebSocket > ,
2022-10-20 03:35:11 +00:00
config : DocumentConfig ,
2021-12-25 13:44:45 +00:00
) -> Self {
2021-12-17 16:23:26 +00:00
Self {
2022-01-10 15:45:59 +00:00
cloud_service ,
2022-02-18 15:04:55 +00:00
rev_web_socket ,
2022-10-13 15:29:37 +00:00
editor_map : Arc ::new ( DocumentEditorMap ::new ( ) ) ,
user : document_user ,
2022-10-22 13:57:44 +00:00
persistence : Arc ::new ( DocumentPersistence ::new ( database ) ) ,
2022-10-20 03:35:11 +00:00
config ,
2021-12-17 16:23:26 +00:00
}
2021-07-23 06:37:18 +00:00
}
2022-10-22 13:57:44 +00:00
/// Called immediately after the application launched with the user sign in/sign up.
#[ tracing::instrument(level = " trace " , skip_all, err) ]
pub async fn initialize ( & self , user_id : & str ) -> FlowyResult < ( ) > {
let _ = self . persistence . initialize ( user_id ) ? ;
2022-03-10 09:14:10 +00:00
listen_ws_state_changed ( self . rev_web_socket . clone ( ) , self . editor_map . clone ( ) ) ;
2022-10-22 13:57:44 +00:00
Ok ( ( ) )
}
2021-12-25 13:44:45 +00:00
2022-10-22 13:57:44 +00:00
pub async fn initialize_with_new_user ( & self , _user_id : & str , _token : & str ) -> FlowyResult < ( ) > {
2021-10-05 06:37:45 +00:00
Ok ( ( ) )
}
2022-10-22 13:57:44 +00:00
#[ tracing::instrument(level = " trace " , skip_all, fields(document_id), err) ]
2022-10-20 03:35:11 +00:00
pub async fn open_document_editor < T : AsRef < str > > (
& self ,
2022-10-22 13:57:44 +00:00
document_id : T ,
2022-10-20 03:35:11 +00:00
) -> Result < Arc < dyn DocumentEditor > , FlowyError > {
2022-10-22 13:57:44 +00:00
let document_id = document_id . as_ref ( ) ;
tracing ::Span ::current ( ) . record ( " document_id " , & document_id ) ;
self . init_document_editor ( document_id ) . await
2021-09-09 07:43:05 +00:00
}
2022-09-13 12:23:56 +00:00
#[ tracing::instrument(level = " trace " , skip(self, editor_id), fields(editor_id), err) ]
2022-10-13 15:29:37 +00:00
pub fn close_document_editor < T : AsRef < str > > ( & self , editor_id : T ) -> Result < ( ) , FlowyError > {
2022-09-13 12:23:56 +00:00
let editor_id = editor_id . as_ref ( ) ;
tracing ::Span ::current ( ) . record ( " editor_id " , & editor_id ) ;
self . editor_map . remove ( editor_id ) ;
2021-09-22 15:21:44 +00:00
Ok ( ( ) )
}
2022-09-13 12:23:56 +00:00
pub async fn apply_edit ( & self , params : EditParams ) -> FlowyResult < ( ) > {
2022-10-13 15:29:37 +00:00
let editor = self . get_document_editor ( & params . doc_id ) . await ? ;
2022-10-20 03:35:11 +00:00
let _ = editor . compose_local_operations ( Bytes ::from ( params . operations ) ) . await ? ;
2022-09-13 12:23:56 +00:00
Ok ( ( ) )
}
2022-10-13 15:29:37 +00:00
pub async fn create_document < T : AsRef < str > > ( & self , doc_id : T , revisions : RepeatedRevision ) -> FlowyResult < ( ) > {
let doc_id = doc_id . as_ref ( ) . to_owned ( ) ;
2022-10-22 13:57:44 +00:00
let db_pool = self . persistence . database . db_pool ( ) ? ;
2022-10-13 15:29:37 +00:00
// Maybe we could save the document to disk without creating the RevisionManager
2022-10-22 13:57:44 +00:00
let rev_manager = self . make_rev_manager ( & doc_id , db_pool ) ? ;
2022-01-14 07:23:21 +00:00
let _ = rev_manager . reset_object ( revisions ) . await ? ;
2022-01-01 06:23:58 +00:00
Ok ( ( ) )
}
2022-02-18 15:04:55 +00:00
pub async fn receive_ws_data ( & self , data : Bytes ) {
2022-01-20 15:51:11 +00:00
let result : Result < ServerRevisionWSData , protobuf ::ProtobufError > = data . try_into ( ) ;
match result {
2022-03-10 09:14:10 +00:00
Ok ( data ) = > match self . editor_map . get ( & data . object_id ) {
2022-01-21 13:41:24 +00:00
None = > tracing ::error! ( " Can't find any source handler for {:?}-{:?} " , data . object_id , data . ty ) ,
2022-03-10 09:14:10 +00:00
Some ( editor ) = > match editor . receive_ws_data ( data ) . await {
2022-01-24 09:35:58 +00:00
Ok ( _ ) = > { }
2022-01-20 15:51:11 +00:00
Err ( e ) = > tracing ::error! ( " {} " , e ) ,
} ,
} ,
Err ( e ) = > {
tracing ::error! ( " Document ws data parser failed: {:?} " , e ) ;
2022-01-24 09:35:58 +00:00
}
2022-01-14 12:52:03 +00:00
}
}
2022-10-20 03:35:11 +00:00
pub fn initial_document_content ( & self ) -> String {
2022-10-22 13:57:44 +00:00
match self . config . version {
DocumentVersionPB ::V0 = > initial_delta_document_content ( ) ,
DocumentVersionPB ::V1 = > initial_document_content ( ) ,
2022-10-20 03:35:11 +00:00
}
}
2022-01-14 12:52:03 +00:00
}
2022-10-13 15:29:37 +00:00
impl DocumentManager {
/// Returns the `DocumentEditor`
///
/// # Arguments
///
/// * `doc_id`: the id of the document
///
/// returns: Result<Arc<DocumentEditor>, FlowyError>
///
2022-10-20 03:35:11 +00:00
async fn get_document_editor ( & self , doc_id : & str ) -> FlowyResult < Arc < dyn DocumentEditor > > {
2022-10-13 15:29:37 +00:00
match self . editor_map . get ( doc_id ) {
2022-10-22 13:57:44 +00:00
None = > {
//
tracing ::warn! ( " Should call init_document_editor first " ) ;
self . init_document_editor ( doc_id ) . await
}
2022-01-01 06:23:58 +00:00
Some ( editor ) = > Ok ( editor ) ,
}
}
2021-07-23 06:37:18 +00:00
2022-10-13 15:29:37 +00:00
/// Initializes a document editor with the doc_id
///
/// # Arguments
///
/// * `doc_id`: the id of the document
/// * `pool`: sqlite connection pool
///
/// returns: Result<Arc<DocumentEditor>, FlowyError>
///
2022-10-20 03:35:11 +00:00
#[ tracing::instrument(level = " trace " , skip(self), err) ]
pub async fn init_document_editor ( & self , doc_id : & str ) -> Result < Arc < dyn DocumentEditor > , FlowyError > {
2022-10-22 13:57:44 +00:00
let pool = self . persistence . database . db_pool ( ) ? ;
2022-03-10 09:14:10 +00:00
let user = self . user . clone ( ) ;
let token = self . user . token ( ) ? ;
2022-10-13 15:29:37 +00:00
let cloud_service = Arc ::new ( DocumentRevisionCloudService {
2021-12-17 16:23:26 +00:00
token ,
2022-01-10 15:45:59 +00:00
server : self . cloud_service . clone ( ) ,
2021-12-17 16:23:26 +00:00
} ) ;
2022-10-20 03:35:11 +00:00
2022-10-22 13:57:44 +00:00
match self . config . version {
DocumentVersionPB ::V0 = > {
let rev_manager = self . make_delta_document_rev_manager ( doc_id , pool . clone ( ) ) ? ;
let editor : Arc < dyn DocumentEditor > = Arc ::new (
DeltaDocumentEditor ::new ( doc_id , user , rev_manager , self . rev_web_socket . clone ( ) , cloud_service )
. await ? ,
) ;
self . editor_map . insert ( doc_id , editor . clone ( ) ) ;
Ok ( editor )
}
DocumentVersionPB ::V1 = > {
let rev_manager = self . make_document_rev_manager ( doc_id , pool . clone ( ) ) ? ;
let editor : Arc < dyn DocumentEditor > =
Arc ::new ( AppFlowyDocumentEditor ::new ( doc_id , user , rev_manager , cloud_service ) . await ? ) ;
self . editor_map . insert ( doc_id , editor . clone ( ) ) ;
Ok ( editor )
}
}
}
fn make_rev_manager ( & self , doc_id : & str , pool : Arc < ConnectionPool > ) -> Result < RevisionManager , FlowyError > {
match self . config . version {
DocumentVersionPB ::V0 = > self . make_delta_document_rev_manager ( doc_id , pool ) ,
DocumentVersionPB ::V1 = > self . make_document_rev_manager ( doc_id , pool ) ,
}
2021-12-08 13:51:06 +00:00
}
2022-10-13 15:29:37 +00:00
fn make_document_rev_manager (
2022-09-13 12:23:56 +00:00
& self ,
doc_id : & str ,
pool : Arc < ConnectionPool > ,
) -> Result < RevisionManager , FlowyError > {
2022-03-10 09:14:10 +00:00
let user_id = self . user . user_id ( ) ? ;
2022-10-13 15:29:37 +00:00
let disk_cache = SQLiteDocumentRevisionPersistence ::new ( & user_id , pool . clone ( ) ) ;
2022-06-09 12:58:56 +00:00
let rev_persistence = RevisionPersistence ::new ( & user_id , doc_id , disk_cache ) ;
2022-07-20 06:07:54 +00:00
// let history_persistence = SQLiteRevisionHistoryPersistence::new(doc_id, pool.clone());
2022-06-10 14:27:19 +00:00
let snapshot_persistence = SQLiteRevisionSnapshotPersistence ::new ( doc_id , pool ) ;
2022-10-22 13:57:44 +00:00
Ok ( RevisionManager ::new (
& user_id ,
doc_id ,
rev_persistence ,
DocumentRevisionCompress ( ) ,
// history_persistence,
snapshot_persistence ,
) )
}
2022-06-09 12:58:56 +00:00
2022-10-22 13:57:44 +00:00
fn make_delta_document_rev_manager (
& self ,
doc_id : & str ,
pool : Arc < ConnectionPool > ,
) -> Result < RevisionManager , FlowyError > {
let user_id = self . user . user_id ( ) ? ;
let disk_cache = SQLiteDeltaDocumentRevisionPersistence ::new ( & user_id , pool . clone ( ) ) ;
let rev_persistence = RevisionPersistence ::new ( & user_id , doc_id , disk_cache ) ;
// let history_persistence = SQLiteRevisionHistoryPersistence::new(doc_id, pool.clone());
let snapshot_persistence = SQLiteRevisionSnapshotPersistence ::new ( doc_id , pool ) ;
2022-06-09 12:58:56 +00:00
Ok ( RevisionManager ::new (
& user_id ,
doc_id ,
rev_persistence ,
2022-10-22 13:57:44 +00:00
DeltaDocumentRevisionCompress ( ) ,
2022-07-20 06:07:54 +00:00
// history_persistence,
2022-06-10 14:27:19 +00:00
snapshot_persistence ,
2022-06-09 12:58:56 +00:00
) )
2021-07-23 06:37:18 +00:00
}
2021-09-21 07:07:07 +00:00
}
2021-09-26 08:39:57 +00:00
2022-10-13 15:29:37 +00:00
struct DocumentRevisionCloudService {
2021-10-02 09:19:54 +00:00
token : String ,
2022-10-13 15:29:37 +00:00
server : Arc < dyn DocumentCloudService > ,
2021-10-02 09:19:54 +00:00
}
2022-10-13 15:29:37 +00:00
impl RevisionCloudService for DocumentRevisionCloudService {
2022-01-23 14:33:47 +00:00
#[ tracing::instrument(level = " trace " , skip(self)) ]
2022-02-24 12:36:24 +00:00
fn fetch_object ( & self , user_id : & str , object_id : & str ) -> FutureResult < Vec < Revision > , FlowyError > {
2022-10-13 15:29:37 +00:00
let params : DocumentIdPB = object_id . to_string ( ) . into ( ) ;
2021-10-02 09:19:54 +00:00
let server = self . server . clone ( ) ;
let token = self . token . clone ( ) ;
2022-01-14 07:23:21 +00:00
let user_id = user_id . to_string ( ) ;
2021-10-02 09:19:54 +00:00
2021-12-13 05:55:44 +00:00
FutureResult ::new ( async move {
2022-10-13 15:29:37 +00:00
match server . fetch_document ( & token , params ) . await ? {
2021-12-14 10:04:51 +00:00
None = > Err ( FlowyError ::record_not_found ( ) . context ( " Remote doesn't have this document " ) ) ,
2022-10-13 15:29:37 +00:00
Some ( payload ) = > {
let bytes = Bytes ::from ( payload . content . clone ( ) ) ;
let doc_md5 = md5 ( & bytes ) ;
2022-03-02 13:12:21 +00:00
let revision = Revision ::new (
2022-10-13 15:29:37 +00:00
& payload . doc_id ,
payload . base_rev_id ,
payload . rev_id ,
bytes ,
2022-03-02 13:12:21 +00:00
& user_id ,
doc_md5 ,
) ;
2022-01-14 07:23:21 +00:00
Ok ( vec! [ revision ] )
2022-01-24 09:35:58 +00:00
}
2021-10-02 09:19:54 +00:00
}
} )
}
}
2022-10-13 15:29:37 +00:00
pub struct DocumentEditorMap {
2022-10-20 03:35:11 +00:00
inner : DashMap < String , Arc < dyn DocumentEditor > > ,
2021-12-10 03:05:23 +00:00
}
2022-10-13 15:29:37 +00:00
impl DocumentEditorMap {
2022-01-24 09:35:58 +00:00
fn new ( ) -> Self {
Self { inner : DashMap ::new ( ) }
}
2021-12-10 03:05:23 +00:00
2022-10-20 03:35:11 +00:00
pub ( crate ) fn insert ( & self , editor_id : & str , editor : Arc < dyn DocumentEditor > ) {
2022-09-13 12:23:56 +00:00
if self . inner . contains_key ( editor_id ) {
2022-10-22 12:58:33 +00:00
log ::warn! ( " Editor:{} already open " , editor_id ) ;
2021-12-10 03:05:23 +00:00
}
2022-10-20 03:35:11 +00:00
self . inner . insert ( editor_id . to_string ( ) , editor ) ;
2021-12-10 03:05:23 +00:00
}
2022-10-20 03:35:11 +00:00
pub ( crate ) fn get ( & self , editor_id : & str ) -> Option < Arc < dyn DocumentEditor > > {
2022-09-13 12:23:56 +00:00
Some ( self . inner . get ( editor_id ) ? . clone ( ) )
2021-12-10 03:05:23 +00:00
}
2022-09-13 12:23:56 +00:00
pub ( crate ) fn remove ( & self , editor_id : & str ) {
if let Some ( editor ) = self . get ( editor_id ) {
2022-10-20 03:35:11 +00:00
editor . close ( )
2021-09-26 08:39:57 +00:00
}
2022-09-13 12:23:56 +00:00
self . inner . remove ( editor_id ) ;
2021-12-10 03:05:23 +00:00
}
2021-09-26 08:39:57 +00:00
}
2021-12-10 03:05:23 +00:00
2022-02-25 14:27:44 +00:00
#[ tracing::instrument(level = " trace " , skip(web_socket, handlers)) ]
2022-10-13 15:29:37 +00:00
fn listen_ws_state_changed ( web_socket : Arc < dyn RevisionWebSocket > , handlers : Arc < DocumentEditorMap > ) {
2021-12-25 13:44:45 +00:00
tokio ::spawn ( async move {
2022-01-24 08:27:40 +00:00
let mut notify = web_socket . subscribe_state_changed ( ) . await ;
while let Ok ( state ) = notify . recv ( ) . await {
2022-02-25 14:27:44 +00:00
handlers . inner . iter ( ) . for_each ( | handler | {
handler . receive_ws_state ( & state ) ;
} )
2021-12-25 13:44:45 +00:00
}
} ) ;
}