view_controller.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. use crate::{
  2. entities::view::{CreateViewParams, UpdateViewParams, View},
  3. errors::WorkspaceError,
  4. module::WorkspaceDatabase,
  5. notify::send_dart_notification,
  6. services::{helper::spawn, server::Server},
  7. sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
  8. };
  9. use crate::{
  10. entities::{
  11. view::{DeleteViewParams, QueryViewParams, RepeatedView},
  12. },
  13. errors::internal_error,
  14. module::WorkspaceUser,
  15. notify::WorkspaceNotification,
  16. services::{TrashCan, TrashEvent},
  17. sql_tables::trash::TrashSource,
  18. };
  19. use flowy_database::SqliteConnection;
  20. use flowy_document::{
  21. entities::doc::{CreateDocParams, DocDelta, QueryDocParams},
  22. module::FlowyDocument,
  23. };
  24. use crate::errors::WorkspaceResult;
  25. use futures::{FutureExt, StreamExt, TryStreamExt};
  26. use std::sync::Arc;
  27. pub(crate) struct ViewController {
  28. user: Arc<dyn WorkspaceUser>,
  29. server: Server,
  30. database: Arc<dyn WorkspaceDatabase>,
  31. trash_can: Arc<TrashCan>,
  32. document: Arc<FlowyDocument>,
  33. }
  34. impl ViewController {
  35. pub(crate) fn new(
  36. user: Arc<dyn WorkspaceUser>,
  37. database: Arc<dyn WorkspaceDatabase>,
  38. server: Server,
  39. trash_can: Arc<TrashCan>,
  40. document: Arc<FlowyDocument>,
  41. ) -> Self {
  42. Self {
  43. user,
  44. server,
  45. database,
  46. trash_can,
  47. document,
  48. }
  49. }
  50. pub(crate) fn init(&self) -> Result<(), WorkspaceError> {
  51. let _ = self.document.init()?;
  52. self.listen_trash_can_event();
  53. Ok(())
  54. }
  55. #[tracing::instrument(level = "debug", skip(self, params), err)]
  56. pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
  57. let view = self.create_view_on_server(params.clone()).await?;
  58. let conn = &*self.database.db_connection()?;
  59. // TODO: rollback anything created before if failed?
  60. conn.immediate_transaction::<_, WorkspaceError, _>(|| {
  61. let _ = self.save_view(view.clone(), conn)?;
  62. self.document.create(CreateDocParams::new(&view.id, params.data))?;
  63. let repeated_view = ViewTableSql::read_views(&view.belong_to_id, conn)?;
  64. send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
  65. .payload(repeated_view)
  66. .send();
  67. Ok(())
  68. })?;
  69. Ok(view)
  70. }
  71. pub(crate) fn save_view(&self, view: View, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
  72. let view_table = ViewTable::new(view);
  73. let _ = ViewTableSql::create_view(view_table, conn)?;
  74. Ok(())
  75. }
  76. pub(crate) async fn read_view(&self, params: QueryViewParams) -> Result<View, WorkspaceError> {
  77. let conn = self.database.db_connection()?;
  78. let view_table = ViewTableSql::read_view(&params.view_id, &*conn)?;
  79. let view: View = view_table.into();
  80. let _ = self.read_view_on_server(params);
  81. Ok(view)
  82. }
  83. #[tracing::instrument(level = "debug", skip(self), err)]
  84. pub(crate) async fn open_view(&self, params: QueryDocParams) -> Result<DocDelta, WorkspaceError> {
  85. let edit_context = self.document.open(params, self.database.db_pool()?).await?;
  86. Ok(edit_context.delta().await.map_err(internal_error)?)
  87. }
  88. #[tracing::instrument(level = "debug", skip(self, params), err)]
  89. pub(crate) async fn delete_view(&self, params: DeleteViewParams) -> Result<(), WorkspaceError> {
  90. let conn = &*self.database.db_connection()?;
  91. let _ = self.delete_view_on_server(params.view_ids.clone());
  92. conn.immediate_transaction::<_, WorkspaceError, _>(|| {
  93. for view_id in params.view_ids {
  94. let view_table = ViewTableSql::delete_view(&view_id, conn)?;
  95. let _ = self.document.delete(view_id.into())?;
  96. let repeated_view = ViewTableSql::read_views(&view_table.belong_to_id, conn)?;
  97. send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
  98. .payload(repeated_view)
  99. .send();
  100. }
  101. Ok(())
  102. })?;
  103. Ok(())
  104. }
  105. // belong_to_id will be the app_id or view_id.
  106. #[tracing::instrument(level = "debug", skip(self), err)]
  107. pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
  108. // TODO: read from server
  109. let conn = self.database.db_connection()?;
  110. let repeated_view = ViewTableSql::read_views(belong_to_id, &*conn)?;
  111. Ok(repeated_view)
  112. }
  113. #[tracing::instrument(level = "debug", skip(self, params), err)]
  114. pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<View, WorkspaceError> {
  115. let conn = &*self.database.db_connection()?;
  116. let changeset = ViewTableChangeset::new(params.clone());
  117. let view_id = changeset.id.clone();
  118. let updated_view = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
  119. let _ = ViewTableSql::update_view(changeset, conn)?;
  120. let view: View = ViewTableSql::read_view(&view_id, conn)?.into();
  121. Ok(view)
  122. })?;
  123. match params.is_trash {
  124. None => {
  125. send_dart_notification(&view_id, WorkspaceNotification::ViewUpdated)
  126. .payload(updated_view.clone())
  127. .send();
  128. },
  129. Some(is_trash) => {
  130. if is_trash {
  131. self.trash_can.add(updated_view.clone(), TrashSource::View, conn)?;
  132. }
  133. let _ = notify_view_num_did_change(&updated_view.belong_to_id, conn)?;
  134. },
  135. }
  136. let _ = self.update_view_on_server(params);
  137. Ok(updated_view)
  138. }
  139. pub(crate) async fn apply_doc_delta(&self, params: DocDelta) -> Result<DocDelta, WorkspaceError> {
  140. let doc = self.document.apply_doc_delta(params).await?;
  141. Ok(doc)
  142. }
  143. }
  144. impl ViewController {
  145. #[tracing::instrument(skip(self), err)]
  146. async fn create_view_on_server(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
  147. let token = self.user.token()?;
  148. let view = self.server.create_view(&token, params).await?;
  149. Ok(view)
  150. }
  151. #[tracing::instrument(skip(self), err)]
  152. fn update_view_on_server(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
  153. let token = self.user.token()?;
  154. let server = self.server.clone();
  155. spawn(async move {
  156. match server.update_view(&token, params).await {
  157. Ok(_) => {},
  158. Err(e) => {
  159. // TODO: retry?
  160. log::error!("Update view failed: {:?}", e);
  161. },
  162. }
  163. });
  164. Ok(())
  165. }
  166. #[tracing::instrument(skip(self), err)]
  167. fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(), WorkspaceError> {
  168. let token = self.user.token()?;
  169. let server = self.server.clone();
  170. let params = DeleteViewParams { view_ids };
  171. spawn(async move {
  172. match server.delete_view(&token, params).await {
  173. Ok(_) => {},
  174. Err(e) => {
  175. // TODO: retry?
  176. log::error!("Delete view failed: {:?}", e);
  177. },
  178. }
  179. });
  180. Ok(())
  181. }
  182. #[tracing::instrument(skip(self), err)]
  183. fn read_view_on_server(&self, params: QueryViewParams) -> Result<(), WorkspaceError> {
  184. let token = self.user.token()?;
  185. let server = self.server.clone();
  186. spawn(async move {
  187. match server.read_view(&token, params).await {
  188. Ok(_) => {},
  189. Err(e) => {
  190. // TODO: retry?
  191. log::error!("Read view failed: {:?}", e);
  192. },
  193. }
  194. });
  195. Ok(())
  196. }
  197. fn listen_trash_can_event(&self) {
  198. let mut rx = self.trash_can.subscribe();
  199. let database = self.database.clone();
  200. let _ = tokio::spawn(async move {
  201. loop {
  202. let mut stream = Box::pin(rx.recv().into_stream().filter_map(|result| async move {
  203. match result {
  204. Ok(event) => event.select(TrashSource::View),
  205. Err(_) => None,
  206. }
  207. }));
  208. let event: Option<TrashEvent> = stream.next().await;
  209. match event {
  210. Some(event) => handle_trash_event(database.clone(), event),
  211. None => {},
  212. }
  213. }
  214. });
  215. }
  216. }
  217. fn notify_view_num_did_change(belong_to_id: &str, conn: &SqliteConnection) -> WorkspaceResult<()> {
  218. let repeated_view = ViewTableSql::read_views(belong_to_id, conn)?;
  219. send_dart_notification(belong_to_id, WorkspaceNotification::AppViewsChanged)
  220. .payload(repeated_view)
  221. .send();
  222. Ok(())
  223. }
  224. fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, event: TrashEvent) {
  225. let db_result = database.db_connection();
  226. match event {
  227. TrashEvent::Putback(_, putback_ids, ret) => {
  228. let result = || {
  229. let conn = &*db_result?;
  230. let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
  231. for putback_id in putback_ids {
  232. match ViewTableSql::read_view(&putback_id, conn) {
  233. Ok(view_table) => {
  234. let _ = notify_view_num_did_change(&view_table.belong_to_id, conn)?;
  235. },
  236. Err(e) => log::error!("Putback view: {} failed: {:?}", putback_id, e),
  237. }
  238. }
  239. Ok(())
  240. })?;
  241. Ok::<(), WorkspaceError>(())
  242. };
  243. ret.send(result());
  244. },
  245. TrashEvent::Delete(_, delete_ids, ret) => {
  246. let result = || {
  247. let conn = &*db_result?;
  248. let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
  249. for delete_id in delete_ids {
  250. match ViewTableSql::delete_view(&delete_id, conn) {
  251. Ok(view_table) => {
  252. let _ = notify_view_num_did_change(&view_table.belong_to_id, conn)?;
  253. },
  254. Err(e) => log::error!("Delete view: {} failed: {:?}", delete_id, e),
  255. }
  256. }
  257. Ok(())
  258. })?;
  259. Ok::<(), WorkspaceError>(())
  260. };
  261. ret.send(result());
  262. },
  263. }
  264. }