manager.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. use std::collections::HashSet;
  2. use std::ops::Deref;
  3. use std::sync::{Arc, Weak};
  4. use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
  5. use collab::core::collab_state::CollabState;
  6. use collab_folder::core::{
  7. Folder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord, View,
  8. ViewChange, ViewChangeReceiver, ViewLayout, Workspace,
  9. };
  10. use parking_lot::Mutex;
  11. use tokio_stream::wrappers::WatchStream;
  12. use tokio_stream::StreamExt;
  13. use tracing::{event, Level};
  14. use flowy_error::{ErrorCode, FlowyError, FlowyResult};
  15. use lib_infra::util::timestamp;
  16. use crate::deps::{FolderCloudService, FolderUser};
  17. use crate::entities::{
  18. view_pb_with_child_views, CreateViewParams, CreateWorkspaceParams, DeletedViewPB,
  19. RepeatedTrashPB, RepeatedViewPB, RepeatedWorkspacePB, UpdateViewParams, ViewPB, WorkspacePB,
  20. };
  21. use crate::notification::{
  22. send_notification, send_workspace_notification, send_workspace_setting_notification,
  23. FolderNotification,
  24. };
  25. use crate::share::ImportParams;
  26. use crate::user_default::DefaultFolderBuilder;
  27. use crate::view_operation::{
  28. create_view, gen_view_id, FolderOperationHandler, FolderOperationHandlers,
  29. };
  30. pub struct Folder2Manager {
  31. mutex_folder: Arc<MutexFolder>,
  32. collab_builder: Arc<AppFlowyCollabBuilder>,
  33. user: Arc<dyn FolderUser>,
  34. operation_handlers: FolderOperationHandlers,
  35. cloud_service: Arc<dyn FolderCloudService>,
  36. }
  37. unsafe impl Send for Folder2Manager {}
  38. unsafe impl Sync for Folder2Manager {}
  39. impl Folder2Manager {
  40. pub async fn new(
  41. user: Arc<dyn FolderUser>,
  42. collab_builder: Arc<AppFlowyCollabBuilder>,
  43. operation_handlers: FolderOperationHandlers,
  44. cloud_service: Arc<dyn FolderCloudService>,
  45. ) -> FlowyResult<Self> {
  46. let mutex_folder = Arc::new(MutexFolder::default());
  47. let manager = Self {
  48. user,
  49. mutex_folder,
  50. collab_builder,
  51. operation_handlers,
  52. cloud_service,
  53. };
  54. Ok(manager)
  55. }
  56. pub async fn get_current_workspace(&self) -> FlowyResult<WorkspacePB> {
  57. self.with_folder(Err(FlowyError::internal()), |folder| {
  58. match folder.get_current_workspace() {
  59. None => Err(FlowyError::record_not_found().context("Can not find the workspace")),
  60. Some(workspace) => {
  61. let views = get_workspace_view_pbs(&workspace.id, folder);
  62. let workspace: WorkspacePB = (workspace, views).into();
  63. Ok(workspace)
  64. },
  65. }
  66. })
  67. }
  68. /// Return a list of views of the current workspace.
  69. /// Only the first level of child views are included.
  70. pub async fn get_current_workspace_views(&self) -> FlowyResult<Vec<ViewPB>> {
  71. let workspace_id = self
  72. .mutex_folder
  73. .lock()
  74. .as_ref()
  75. .map(|folder| folder.get_current_workspace_id());
  76. if let Some(Some(workspace_id)) = workspace_id {
  77. self.get_workspace_views(&workspace_id).await
  78. } else {
  79. Ok(vec![])
  80. }
  81. }
  82. pub async fn get_workspace_views(&self, workspace_id: &str) -> FlowyResult<Vec<ViewPB>> {
  83. let views = self.with_folder(vec![], |folder| {
  84. get_workspace_view_pbs(workspace_id, folder)
  85. });
  86. Ok(views)
  87. }
  88. /// Called immediately after the application launched fi the user already sign in/sign up.
  89. #[tracing::instrument(level = "debug", skip(self), err)]
  90. pub async fn initialize(&self, uid: i64, workspace_id: &str) -> FlowyResult<()> {
  91. let workspace_id = workspace_id.to_string();
  92. if let Ok(collab_db) = self.user.collab_db() {
  93. let collab = self
  94. .collab_builder
  95. .build(uid, &workspace_id, "workspace", collab_db);
  96. let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
  97. let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
  98. let folder_context = FolderContext {
  99. view_change_tx: view_tx,
  100. trash_change_tx: trash_tx,
  101. };
  102. let folder = Folder::get_or_create(collab, folder_context);
  103. let folder_state_rx = folder.subscribe_state_change();
  104. *self.mutex_folder.lock() = Some(folder);
  105. let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
  106. listen_on_folder_state_change(workspace_id, folder_state_rx, &weak_mutex_folder);
  107. listen_on_trash_change(trash_rx, &weak_mutex_folder);
  108. listen_on_view_change(view_rx, &weak_mutex_folder);
  109. }
  110. Ok(())
  111. }
  112. /// Called after the user sign up / sign in
  113. pub async fn initialize_with_new_user(
  114. &self,
  115. user_id: i64,
  116. token: &str,
  117. workspace_id: &str,
  118. ) -> FlowyResult<()> {
  119. self.initialize(user_id, workspace_id).await?;
  120. let (folder_data, workspace_pb) = DefaultFolderBuilder::build(
  121. self.user.user_id()?,
  122. workspace_id.to_string(),
  123. &self.operation_handlers,
  124. )
  125. .await;
  126. self.with_folder((), |folder| {
  127. folder.create_with_data(folder_data);
  128. });
  129. send_notification(token, FolderNotification::DidCreateWorkspace)
  130. .payload(RepeatedWorkspacePB {
  131. items: vec![workspace_pb],
  132. })
  133. .send();
  134. Ok(())
  135. }
  136. /// Called when the current user logout
  137. ///
  138. pub async fn clear(&self, _user_id: i64) {}
  139. pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> FlowyResult<Workspace> {
  140. let workspace = self
  141. .cloud_service
  142. .create_workspace(self.user.user_id()?, &params.name)
  143. .await?;
  144. self.with_folder((), |folder| {
  145. folder.workspaces.create_workspace(workspace.clone());
  146. folder.set_current_workspace(&workspace.id);
  147. });
  148. let repeated_workspace = RepeatedWorkspacePB {
  149. items: vec![workspace.clone().into()],
  150. };
  151. send_workspace_notification(FolderNotification::DidCreateWorkspace, repeated_workspace);
  152. Ok(workspace)
  153. }
  154. pub async fn open_workspace(&self, workspace_id: &str) -> FlowyResult<Workspace> {
  155. self.with_folder(Err(FlowyError::internal()), |folder| {
  156. let workspace = folder
  157. .workspaces
  158. .get_workspace(workspace_id)
  159. .ok_or_else(|| {
  160. FlowyError::record_not_found().context("Can't open not existing workspace")
  161. })?;
  162. folder.set_current_workspace(workspace_id);
  163. Ok::<Workspace, FlowyError>(workspace)
  164. })
  165. }
  166. pub async fn get_workspace(&self, workspace_id: &str) -> Option<Workspace> {
  167. self.with_folder(None, |folder| folder.workspaces.get_workspace(workspace_id))
  168. }
  169. fn with_folder<F, Output>(&self, default_value: Output, f: F) -> Output
  170. where
  171. F: FnOnce(&Folder) -> Output,
  172. {
  173. let folder = self.mutex_folder.lock();
  174. match &*folder {
  175. None => default_value,
  176. Some(folder) => f(folder),
  177. }
  178. }
  179. pub async fn get_all_workspaces(&self) -> Vec<Workspace> {
  180. self.with_folder(vec![], |folder| folder.workspaces.get_all_workspaces())
  181. }
  182. pub async fn create_view_with_params(&self, params: CreateViewParams) -> FlowyResult<View> {
  183. let view_layout: ViewLayout = params.layout.clone().into();
  184. let handler = self.get_handler(&view_layout)?;
  185. let user_id = self.user.user_id()?;
  186. let meta = params.meta.clone();
  187. if meta.is_empty() && params.initial_data.is_empty() {
  188. tracing::trace!("Create view with build-in data");
  189. handler
  190. .create_built_in_view(user_id, &params.view_id, &params.name, view_layout.clone())
  191. .await?;
  192. } else {
  193. tracing::trace!("Create view with view data");
  194. handler
  195. .create_view_with_view_data(
  196. user_id,
  197. &params.view_id,
  198. &params.name,
  199. params.initial_data.clone(),
  200. view_layout.clone(),
  201. meta,
  202. )
  203. .await?;
  204. }
  205. let view = create_view(params, view_layout);
  206. self.with_folder((), |folder| {
  207. folder.insert_view(view.clone());
  208. });
  209. notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id.clone()]);
  210. Ok(view)
  211. }
  212. #[tracing::instrument(level = "debug", skip(self), err)]
  213. pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
  214. let view = self
  215. .with_folder(None, |folder| folder.views.get_view(view_id))
  216. .ok_or_else(|| {
  217. FlowyError::record_not_found().context("Can't find the view when closing the view")
  218. })?;
  219. let handler = self.get_handler(&view.layout)?;
  220. handler.close_view(view_id).await?;
  221. Ok(())
  222. }
  223. /// Returns the view with the given view id.
  224. /// The child views of the view will only access the first. So if you want to get the child view's
  225. /// child view, you need to call this method again.
  226. #[tracing::instrument(level = "debug", skip(self, view_id), err)]
  227. pub async fn get_view(&self, view_id: &str) -> FlowyResult<ViewPB> {
  228. let view_id = view_id.to_string();
  229. let folder = self.mutex_folder.lock();
  230. let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
  231. let trash_ids = folder
  232. .trash
  233. .get_all_trash()
  234. .into_iter()
  235. .map(|trash| trash.id)
  236. .collect::<Vec<String>>();
  237. if trash_ids.contains(&view_id) {
  238. return Err(FlowyError::record_not_found());
  239. }
  240. match folder.views.get_view(&view_id) {
  241. None => Err(FlowyError::record_not_found()),
  242. Some(mut view) => {
  243. view.children.retain(|b| !trash_ids.contains(&b.id));
  244. let child_views = folder
  245. .views
  246. .get_views_belong_to(&view.id)
  247. .into_iter()
  248. .filter(|view| !trash_ids.contains(&view.id))
  249. .collect::<Vec<View>>();
  250. let view_pb = view_pb_with_child_views(view, child_views);
  251. Ok(view_pb)
  252. },
  253. }
  254. }
  255. /// Move the view to trash. If the view is the current view, then set the current view to empty.
  256. /// When the view is moved to trash, all the child views will be moved to trash as well.
  257. #[tracing::instrument(level = "debug", skip(self), err)]
  258. pub async fn move_view_to_trash(&self, view_id: &str) -> FlowyResult<()> {
  259. self.with_folder((), |folder| {
  260. folder.trash.add_trash(vec![TrashRecord {
  261. id: view_id.to_string(),
  262. created_at: timestamp(),
  263. }]);
  264. if let Some(view) = folder.get_current_view() {
  265. if view == view_id {
  266. folder.set_current_view("");
  267. }
  268. }
  269. // notify the parent view that the view is moved to trash
  270. send_notification(view_id, FolderNotification::DidMoveViewToTrash)
  271. .payload(DeletedViewPB {
  272. view_id: view_id.to_string(),
  273. index: None,
  274. })
  275. .send();
  276. });
  277. Ok(())
  278. }
  279. /// Move the view with given id from one position to another position.
  280. /// The view will be moved to the new position in the same parent view.
  281. /// The passed in index is the index of the view that displayed in the UI.
  282. /// We need to convert the index to the real index of the view in the parent view.
  283. #[tracing::instrument(level = "trace", skip(self), err)]
  284. pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
  285. if let Some((is_workspace, parent_view_id, child_views)) = self.get_view_relation(view_id).await
  286. {
  287. // The display parent view is the view that is displayed in the UI
  288. let display_views = if is_workspace {
  289. self
  290. .get_current_workspace()
  291. .await?
  292. .views
  293. .into_iter()
  294. .map(|view| view.id)
  295. .collect::<Vec<_>>()
  296. } else {
  297. self
  298. .get_view(&parent_view_id)
  299. .await?
  300. .child_views
  301. .into_iter()
  302. .map(|view| view.id)
  303. .collect::<Vec<_>>()
  304. };
  305. if display_views.len() > to {
  306. let to_view_id = display_views[to].clone();
  307. // Find the actual index of the view in the parent view
  308. let actual_from_index = child_views.iter().position(|id| id == view_id);
  309. let actual_to_index = child_views.iter().position(|id| id == &to_view_id);
  310. if let (Some(actual_from_index), Some(actual_to_index)) =
  311. (actual_from_index, actual_to_index)
  312. {
  313. self.with_folder((), |folder| {
  314. folder.move_view(view_id, actual_from_index as u32, actual_to_index as u32);
  315. });
  316. notify_parent_view_did_change(self.mutex_folder.clone(), vec![parent_view_id]);
  317. }
  318. }
  319. }
  320. Ok(())
  321. }
  322. /// Return a list of views that belong to the given parent view id.
  323. #[tracing::instrument(level = "debug", skip(self, parent_view_id), err)]
  324. pub async fn get_views_belong_to(&self, parent_view_id: &str) -> FlowyResult<Vec<View>> {
  325. let views = self.with_folder(vec![], |folder| {
  326. folder.views.get_views_belong_to(parent_view_id)
  327. });
  328. Ok(views)
  329. }
  330. /// Update the view with the given params.
  331. #[tracing::instrument(level = "trace", skip(self), err)]
  332. pub async fn update_view_with_params(&self, params: UpdateViewParams) -> FlowyResult<()> {
  333. let value = self.with_folder(None, |folder| {
  334. let old_view = folder.views.get_view(&params.view_id);
  335. let new_view = folder.views.update_view(&params.view_id, |update| {
  336. update
  337. .set_name_if_not_none(params.name)
  338. .set_desc_if_not_none(params.desc)
  339. .set_layout_if_not_none(params.layout)
  340. .done()
  341. });
  342. Some((old_view, new_view))
  343. });
  344. if let Some((Some(old_view), Some(new_view))) = value {
  345. if let Ok(handler) = self.get_handler(&old_view.layout) {
  346. handler.did_update_view(&old_view, &new_view).await?;
  347. }
  348. }
  349. if let Ok(view_pb) = self.get_view(&params.view_id).await {
  350. notify_parent_view_did_change(
  351. self.mutex_folder.clone(),
  352. vec![view_pb.parent_view_id.clone()],
  353. );
  354. send_notification(&view_pb.id, FolderNotification::DidUpdateView)
  355. .payload(view_pb)
  356. .send();
  357. }
  358. Ok(())
  359. }
  360. /// Duplicate the view with the given view id.
  361. #[tracing::instrument(level = "debug", skip(self), err)]
  362. pub(crate) async fn duplicate_view(&self, view_id: &str) -> Result<(), FlowyError> {
  363. let view = self
  364. .with_folder(None, |folder| folder.views.get_view(view_id))
  365. .ok_or_else(|| FlowyError::record_not_found().context("Can't duplicate the view"))?;
  366. let handler = self.get_handler(&view.layout)?;
  367. let view_data = handler.duplicate_view(&view.id).await?;
  368. let duplicate_params = CreateViewParams {
  369. parent_view_id: view.parent_view_id.clone(),
  370. name: format!("{} (copy)", &view.name),
  371. desc: view.desc,
  372. layout: view.layout.into(),
  373. initial_data: view_data.to_vec(),
  374. view_id: gen_view_id(),
  375. meta: Default::default(),
  376. set_as_current: true,
  377. };
  378. let _ = self.create_view_with_params(duplicate_params).await?;
  379. Ok(())
  380. }
  381. #[tracing::instrument(level = "trace", skip(self), err)]
  382. pub(crate) async fn set_current_view(&self, view_id: &str) -> Result<(), FlowyError> {
  383. let folder = self.mutex_folder.lock();
  384. let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
  385. folder.set_current_view(view_id);
  386. let workspace = folder.get_current_workspace();
  387. let view = folder
  388. .get_current_view()
  389. .and_then(|view_id| folder.views.get_view(&view_id));
  390. send_workspace_setting_notification(workspace, view);
  391. Ok(())
  392. }
  393. #[tracing::instrument(level = "trace", skip(self))]
  394. pub(crate) async fn get_current_view(&self) -> Option<ViewPB> {
  395. let view_id = self.with_folder(None, |folder| folder.get_current_view())?;
  396. self.get_view(&view_id).await.ok()
  397. }
  398. #[tracing::instrument(level = "trace", skip(self))]
  399. pub(crate) async fn get_all_trash(&self) -> Vec<TrashInfo> {
  400. self.with_folder(vec![], |folder| folder.trash.get_all_trash())
  401. }
  402. #[tracing::instrument(level = "trace", skip(self))]
  403. pub(crate) async fn restore_all_trash(&self) {
  404. self.with_folder((), |folder| {
  405. folder.trash.clear();
  406. });
  407. send_notification("trash", FolderNotification::DidUpdateTrash)
  408. .payload(RepeatedTrashPB { items: vec![] })
  409. .send();
  410. }
  411. #[tracing::instrument(level = "trace", skip(self))]
  412. pub(crate) async fn restore_trash(&self, trash_id: &str) {
  413. self.with_folder((), |folder| {
  414. folder.trash.delete_trash(vec![trash_id]);
  415. });
  416. }
  417. /// Delete all the trash permanently.
  418. #[tracing::instrument(level = "trace", skip(self))]
  419. pub(crate) async fn delete_all_trash(&self) {
  420. let deleted_trash = self.with_folder(vec![], |folder| folder.trash.get_all_trash());
  421. for trash in deleted_trash {
  422. let _ = self.delete_trash(&trash.id).await;
  423. }
  424. send_notification("trash", FolderNotification::DidUpdateTrash)
  425. .payload(RepeatedTrashPB { items: vec![] })
  426. .send();
  427. }
  428. /// Delete the trash permanently.
  429. /// Delete the view will delete all the resources that the view holds. For example, if the view
  430. /// is a database view. Then the database will be deleted as well.
  431. #[tracing::instrument(level = "debug", skip(self, view_id), err)]
  432. pub async fn delete_trash(&self, view_id: &str) -> FlowyResult<()> {
  433. let view = self.with_folder(None, |folder| folder.views.get_view(view_id));
  434. self.with_folder((), |folder| {
  435. folder.trash.delete_trash(vec![view_id]);
  436. folder.views.delete_views(vec![view_id]);
  437. });
  438. if let Some(view) = view {
  439. if let Ok(handler) = self.get_handler(&view.layout) {
  440. handler.delete_view(view_id).await?;
  441. }
  442. }
  443. Ok(())
  444. }
  445. pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult<View> {
  446. if import_data.data.is_none() && import_data.file_path.is_none() {
  447. return Err(FlowyError::new(
  448. ErrorCode::InvalidData,
  449. "data or file_path is required",
  450. ));
  451. }
  452. let handler = self.get_handler(&import_data.view_layout)?;
  453. let view_id = gen_view_id();
  454. if let Some(data) = import_data.data {
  455. handler
  456. .import_from_bytes(&view_id, &import_data.name, import_data.import_type, data)
  457. .await?;
  458. }
  459. if let Some(file_path) = import_data.file_path {
  460. handler
  461. .import_from_file_path(&view_id, &import_data.name, file_path)
  462. .await?;
  463. }
  464. let params = CreateViewParams {
  465. parent_view_id: import_data.parent_view_id,
  466. name: import_data.name,
  467. desc: "".to_string(),
  468. layout: import_data.view_layout.clone().into(),
  469. initial_data: vec![],
  470. view_id,
  471. meta: Default::default(),
  472. set_as_current: false,
  473. };
  474. let view = create_view(params, import_data.view_layout);
  475. self.with_folder((), |folder| {
  476. folder.insert_view(view.clone());
  477. });
  478. notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id.clone()]);
  479. Ok(view)
  480. }
  481. /// Returns a handler that implements the [FolderOperationHandler] trait
  482. fn get_handler(
  483. &self,
  484. view_layout: &ViewLayout,
  485. ) -> FlowyResult<Arc<dyn FolderOperationHandler + Send + Sync>> {
  486. match self.operation_handlers.get(view_layout) {
  487. None => Err(FlowyError::internal().context(format!(
  488. "Get data processor failed. Unknown layout type: {:?}",
  489. view_layout
  490. ))),
  491. Some(processor) => Ok(processor.clone()),
  492. }
  493. }
  494. /// Returns the relation of the view. The relation is a tuple of (is_workspace, parent_view_id,
  495. /// child_view_ids). If the view is a workspace, then the parent_view_id is the workspace id.
  496. /// Otherwise, the parent_view_id is the parent view id of the view. The child_view_ids is the
  497. /// child view ids of the view.
  498. async fn get_view_relation(&self, view_id: &str) -> Option<(bool, String, Vec<String>)> {
  499. self.with_folder(None, |folder| {
  500. let view = folder.views.get_view(view_id)?;
  501. match folder.views.get_view(&view.parent_view_id) {
  502. None => folder.get_current_workspace().map(|workspace| {
  503. (
  504. true,
  505. workspace.id,
  506. workspace
  507. .child_views
  508. .items
  509. .into_iter()
  510. .map(|view| view.id)
  511. .collect::<Vec<String>>(),
  512. )
  513. }),
  514. Some(parent_view) => Some((
  515. false,
  516. parent_view.id,
  517. parent_view
  518. .children
  519. .items
  520. .into_iter()
  521. .map(|view| view.id)
  522. .collect::<Vec<String>>(),
  523. )),
  524. }
  525. })
  526. }
  527. }
  528. /// Listen on the [ViewChange] after create/delete/update events happened
  529. fn listen_on_view_change(mut rx: ViewChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
  530. let weak_mutex_folder = weak_mutex_folder.clone();
  531. tokio::spawn(async move {
  532. while let Ok(value) = rx.recv().await {
  533. if let Some(folder) = weak_mutex_folder.upgrade() {
  534. tracing::trace!("Did receive view change: {:?}", value);
  535. match value {
  536. ViewChange::DidCreateView { view } => {
  537. notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id]);
  538. },
  539. ViewChange::DidDeleteView { views: _ } => {},
  540. ViewChange::DidUpdate { view } => {
  541. notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id]);
  542. },
  543. };
  544. }
  545. }
  546. });
  547. }
  548. fn listen_on_folder_state_change(
  549. workspace_id: String,
  550. mut folder_state_rx: WatchStream<CollabState>,
  551. weak_mutex_folder: &Weak<MutexFolder>,
  552. ) {
  553. let weak_mutex_folder = weak_mutex_folder.clone();
  554. tokio::spawn(async move {
  555. while let Some(state) = folder_state_rx.next().await {
  556. if state.is_root_changed() {
  557. if let Some(mutex_folder) = weak_mutex_folder.upgrade() {
  558. let folder = mutex_folder.lock().take();
  559. if let Some(folder) = folder {
  560. tracing::trace!("🔥Reload folder");
  561. let reload_folder = folder.reload();
  562. notify_did_update_workspace(&workspace_id, &reload_folder);
  563. *mutex_folder.lock() = Some(reload_folder);
  564. }
  565. }
  566. }
  567. }
  568. });
  569. }
  570. /// Listen on the [TrashChange]s and notify the frontend some views were changed.
  571. fn listen_on_trash_change(mut rx: TrashChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
  572. let weak_mutex_folder = weak_mutex_folder.clone();
  573. tokio::spawn(async move {
  574. while let Ok(value) = rx.recv().await {
  575. if let Some(folder) = weak_mutex_folder.upgrade() {
  576. let mut unique_ids = HashSet::new();
  577. tracing::trace!("Did receive trash change: {:?}", value);
  578. let ids = match value {
  579. TrashChange::DidCreateTrash { ids } => ids,
  580. TrashChange::DidDeleteTrash { ids } => ids,
  581. };
  582. if let Some(folder) = folder.lock().as_ref() {
  583. let views = folder.views.get_views(&ids);
  584. for view in views {
  585. unique_ids.insert(view.parent_view_id);
  586. }
  587. let repeated_trash: RepeatedTrashPB = folder.trash.get_all_trash().into();
  588. send_notification("trash", FolderNotification::DidUpdateTrash)
  589. .payload(repeated_trash)
  590. .send();
  591. }
  592. let parent_view_ids = unique_ids.into_iter().collect();
  593. notify_parent_view_did_change(folder.clone(), parent_view_ids);
  594. }
  595. }
  596. });
  597. }
  598. /// Return the views that belong to the workspace. The views are filtered by the trash.
  599. fn get_workspace_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
  600. let trash_ids = folder
  601. .trash
  602. .get_all_trash()
  603. .into_iter()
  604. .map(|trash| trash.id)
  605. .collect::<Vec<String>>();
  606. let mut views = folder.get_workspace_views(workspace_id);
  607. views.retain(|view| !trash_ids.contains(&view.id));
  608. views
  609. .into_iter()
  610. .map(|view| {
  611. // Get child views
  612. let child_views = folder
  613. .views
  614. .get_views_belong_to(&view.id)
  615. .into_iter()
  616. .collect();
  617. view_pb_with_child_views(view, child_views)
  618. })
  619. .collect()
  620. }
  621. fn notify_did_update_workspace(workspace_id: &str, folder: &Folder) {
  622. let repeated_view: RepeatedViewPB = get_workspace_view_pbs(workspace_id, folder).into();
  623. tracing::trace!("Did update workspace views: {:?}", repeated_view);
  624. send_notification(workspace_id, FolderNotification::DidUpdateWorkspaceViews)
  625. .payload(repeated_view)
  626. .send();
  627. }
  628. /// Notify the the list of parent view ids that its child views were changed.
  629. #[tracing::instrument(level = "debug", skip(folder, parent_view_ids))]
  630. fn notify_parent_view_did_change<T: AsRef<str>>(
  631. folder: Arc<MutexFolder>,
  632. parent_view_ids: Vec<T>,
  633. ) -> Option<()> {
  634. let folder = folder.lock();
  635. let folder = folder.as_ref()?;
  636. let workspace_id = folder.get_current_workspace_id()?;
  637. let trash_ids = folder
  638. .trash
  639. .get_all_trash()
  640. .into_iter()
  641. .map(|trash| trash.id)
  642. .collect::<Vec<String>>();
  643. for parent_view_id in parent_view_ids {
  644. let parent_view_id = parent_view_id.as_ref();
  645. // if the view's parent id equal to workspace id. Then it will fetch the current
  646. // workspace views. Because the the workspace is not a view stored in the views map.
  647. if parent_view_id == workspace_id {
  648. notify_did_update_workspace(&workspace_id, folder)
  649. } else {
  650. // Parent view can contain a list of child views. Currently, only get the first level
  651. // child views.
  652. let parent_view = folder.views.get_view(parent_view_id)?;
  653. let mut child_views = folder.views.get_views_belong_to(parent_view_id);
  654. child_views.retain(|view| !trash_ids.contains(&view.id));
  655. event!(Level::DEBUG, child_views_count = child_views.len());
  656. // Post the notification
  657. let parent_view_pb = view_pb_with_child_views(parent_view, child_views);
  658. send_notification(parent_view_id, FolderNotification::DidUpdateChildViews)
  659. .payload(parent_view_pb)
  660. .send();
  661. }
  662. }
  663. None
  664. }
  665. fn folder_not_init_error() -> FlowyError {
  666. FlowyError::internal().context("Folder not initialized")
  667. }
  668. #[derive(Clone, Default)]
  669. pub struct MutexFolder(Arc<Mutex<Option<Folder>>>);
  670. impl Deref for MutexFolder {
  671. type Target = Arc<Mutex<Option<Folder>>>;
  672. fn deref(&self) -> &Self::Target {
  673. &self.0
  674. }
  675. }
  676. unsafe impl Sync for MutexFolder {}
  677. unsafe impl Send for MutexFolder {}