From 114fe25b08080b61524c12a81945eb2dfb303fc0 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Thu, 2 Mar 2023 23:02:58 +0800 Subject: [PATCH 1/4] chore: block --- apps/keck/src/server/api/blocks/block.rs | 121 +++++++++++++---------- 1 file changed, 68 insertions(+), 53 deletions(-) diff --git a/apps/keck/src/server/api/blocks/block.rs b/apps/keck/src/server/api/blocks/block.rs index 54718df28..b22526e4d 100644 --- a/apps/keck/src/server/api/blocks/block.rs +++ b/apps/keck/src/server/api/blocks/block.rs @@ -25,14 +25,17 @@ pub async fn get_block( Extension(context): Extension>, Path(params): Path<(String, String)>, ) -> Response { - let (ws_id, block) = params; - info!("get_block: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(ws_id).await { - if let Some(block) = workspace.with_trx(|t| workspace.get(&t.trx, block)) { - Json(block).into_response() - } else { - StatusCode::NOT_FOUND.into_response() - } + let (ws_id, block_id) = params; + info!("get_block: {}, {}", ws_id, block_id); + + if let Some(block) = context + .storage + .get_workspace(ws_id) + .await + .ok() + .and_then(|workspace| workspace.with_trx(|t| workspace.get(&t.trx, block_id))) + { + Json(block).into_response() } else { StatusCode::NOT_FOUND.into_response() } @@ -126,16 +129,23 @@ pub async fn get_block_history( Extension(context): Extension>, Path(params): Path<(String, String)>, ) -> Response { - let (ws_id, block) = params; - info!("get_block_history: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - workspace.with_trx(|t| { - if let Some(block) = workspace.get(&t.trx, block) { - Json(&block.history(&t.trx)).into_response() - } else { - StatusCode::NOT_FOUND.into_response() - } + let (ws_id, block_id) = params; + info!("get_block_history: {}, {}", ws_id, block_id); + + if let Some(history) = context + .storage + .get_workspace(&ws_id) + .await + .ok() + .and_then(|workspace| { + workspace.with_trx(|t| { + workspace + .get(&t.trx, block_id) + .map(|block| block.history(&t.rx)) + }) }) + { + Json(history).into_response() } else { StatusCode::NOT_FOUND.into_response() } @@ -162,22 +172,24 @@ pub async fn delete_block( Extension(context): Extension>, Path(params): Path<(String, String)>, ) -> StatusCode { - let (ws_id, block) = params; - info!("delete_block: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - if let Some(update) = workspace.with_trx(|mut t| { - if t.remove(&block) { - Some(t.trx.encode_update_v1()) - } else { - None - } - }) { - if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { - error!("db write error: {}", e.to_string()); - } - return StatusCode::NO_CONTENT; + let (ws_id, block_id) = params; + info!("delete_block: {}, {}", ws_id, block_id); + + if let Some(update) = context + .storage + .get_workspace(&ws_id) + .await + .ok() + .and_then(|workspace| { + workspace.with_trx(|mut t| t.remove(&block_id).then_some(t.trx.encode_update_v1())) + }) + { + if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { + error!("db write error: {}", e.to_string()); } + return StatusCode::NO_CONTENT; } + StatusCode::NOT_FOUND } @@ -204,34 +216,37 @@ pub async fn get_block_children( Path(params): Path<(String, String)>, Query(pagination): Query, ) -> Response { - let (ws_id, block) = params; + let (ws_id, block_id) = params; let Pagination { offset, limit } = pagination; - info!("get_block_children: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(ws_id).await { - if let Some(block) = workspace.with_trx(|t| workspace.get(&t.trx, &block)) { - let data: Vec = - block.children_iter(|children| children.skip(offset).take(limit).collect()); - - let status = if data.is_empty() { - StatusCode::NOT_FOUND - } else { - StatusCode::OK - }; + info!("get_block_children: {}, {}", ws_id, block_id); + if let Some((total, data)) = context + .storage + .get_workspace(ws_id) + .await + .ok() + .and_then(|workspace| workspace.with_trx(|t| workspace.get(&t.trx, &block_id))) + .map(|block| { ( - status, - Json(PageData { - total: block.children_len() as usize, - data, + block.children_len() as usize, + block.children_iter(|children| { + children.skip(offset).take(limit).collect::>() }), ) - .into_response() - } else { - StatusCode::NOT_FOUND.into_response() - } - } else { - StatusCode::NOT_FOUND.into_response() + }) + { + return ( + if data.is_empty() { + StatusCode::NOT_FOUND + } else { + StatusCode::OK + }, + Json(PageData { total, data }), + ) + .into_response(); } + + StatusCode::NOT_FOUND.into_response() } /// Insert a another `Block` into a `Block`'s children From 285af79c748dce0433023e56ede94c19bdccbcae Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Fri, 3 Mar 2023 09:02:25 +0800 Subject: [PATCH 2/4] chore: block apis --- apps/keck/src/server/api/blocks/block.rs | 227 ++++++++++---------- libs/jwst-binding/jwst-swift/src/storage.rs | 4 +- 2 files changed, 121 insertions(+), 110 deletions(-) diff --git a/apps/keck/src/server/api/blocks/block.rs b/apps/keck/src/server/api/blocks/block.rs index b22526e4d..cdbb0ae87 100644 --- a/apps/keck/src/server/api/blocks/block.rs +++ b/apps/keck/src/server/api/blocks/block.rs @@ -35,10 +35,10 @@ pub async fn get_block( .ok() .and_then(|workspace| workspace.with_trx(|t| workspace.get(&t.trx, block_id))) { - Json(block).into_response() - } else { - StatusCode::NOT_FOUND.into_response() + return Json(block).into_response(); } + + StatusCode::NOT_FOUND.into_response() } /// Create or set `Block` with content @@ -68,33 +68,37 @@ pub async fn set_block( Path(params): Path<(String, String)>, Json(payload): Json, ) -> Response { - let (ws_id, block) = params; - info!("set_block: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - let mut update = None; - - // set block content - let block = workspace.with_trx(|mut t| { - let block = t.create(&block, "text"); + let (ws_id, block_id) = params; + info!("set_block: {}, {}", ws_id, block_id); - // set block content - if let Some(block_content) = payload.as_object() { - let mut changed = false; - for (key, value) in block_content.iter() { - changed = true; - if let Ok(value) = serde_json::from_value::(value.clone()) { - block.set(&mut t.trx, key, value); - } - } + if let Some((update, block)) = + context + .storage + .get_workspace(&ws_id) + .await + .ok() + .and_then(|workspace| { + workspace.with_trx(|mut t| { + let block = t.create(&block_id, "text"); - if changed { - update = Some(t.trx.encode_update_v1()); - } - } - - block - }); + let count = payload + .as_object() + .map(|block_content| { + block_content + .iter() + .filter_map(|(key, value)| { + serde_json::from_value::(value.clone()) + .map(|value| block.set(&mut t.trx, key, value)) + .ok() + }) + .count() + }) + .unwrap_or_default(); + Some(((count > 0).then(|| t.trx.encode_update_v1()), block)) + }) + }) + { if let Some(update) = update { if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { error!("db write error: {}", e.to_string()); @@ -102,10 +106,10 @@ pub async fn set_block( } // response block content - Json(block).into_response() - } else { - StatusCode::NOT_FOUND.into_response() + return Json(block).into_response(); } + + StatusCode::NOT_FOUND.into_response() } /// Get `Block` history @@ -141,14 +145,14 @@ pub async fn get_block_history( workspace.with_trx(|t| { workspace .get(&t.trx, block_id) - .map(|block| block.history(&t.rx)) + .map(|block| block.history(&t.trx)) }) }) { - Json(history).into_response() - } else { - StatusCode::NOT_FOUND.into_response() + return Json(history).into_response(); } + + StatusCode::NOT_FOUND.into_response() } /// Delete block @@ -181,7 +185,7 @@ pub async fn delete_block( .await .ok() .and_then(|workspace| { - workspace.with_trx(|mut t| t.remove(&block_id).then_some(t.trx.encode_update_v1())) + workspace.with_trx(|mut t| t.remove(&block_id).then(|| t.trx.encode_update_v1())) }) { if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { @@ -275,64 +279,57 @@ pub async fn get_block_children( pub async fn insert_block_children( Extension(context): Extension>, Path(params): Path<(String, String)>, - Json(payload): Json, + Json(action): Json, ) -> Response { - let (ws_id, block) = params; - info!("insert_block: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - let mut update = None; - - if let Some(block) = workspace.with_trx(|t| workspace.get(&t.trx, block)) { - let block = workspace.with_trx(|mut t| { - let mut changed = false; - match payload { - InsertChildren::Push(block_id) => { - if let Some(child) = workspace.get(&t.trx, block_id) { - changed = true; - block.push_children(&mut t.trx, &child) - } - } - InsertChildren::InsertBefore { id, before } => { - if let Some(child) = workspace.get(&t.trx, id) { - changed = true; - block.insert_children_before(&mut t.trx, &child, &before) - } - } - InsertChildren::InsertAfter { id, after } => { - if let Some(child) = workspace.get(&t.trx, id) { - changed = true; - block.insert_children_after(&mut t.trx, &child, &after) - } - } - InsertChildren::InsertAt { id, pos } => { - if let Some(child) = workspace.get(&t.trx, id) { - changed = true; - block.insert_children_at(&mut t.trx, &child, pos) - } - } - } - - if changed { - update = Some(t.trx.encode_update_v1()); - } - - block - }); + let (ws_id, block_id) = params; + info!("insert_block: {}, {}", ws_id, block_id); - if let Some(update) = update { - if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { - error!("db write error: {}", e.to_string()); - } + if let Some((update, block)) = + context + .storage + .get_workspace(&ws_id) + .await + .ok() + .and_then(|workspace| { + workspace.with_trx(|mut t| { + workspace.get(&t.trx, block_id).map(|block| { + ( + match action { + InsertChildren::Push(id) => workspace + .get(&t.trx, id) + .map(|child| block.push_children(&mut t.trx, &child)), + InsertChildren::InsertBefore { id, before } => { + workspace.get(&t.trx, id).map(|child| { + block.insert_children_before(&mut t.trx, &child, &before) + }) + } + InsertChildren::InsertAfter { id, after } => { + workspace.get(&t.trx, id).map(|child| { + block.insert_children_after(&mut t.trx, &child, &after) + }) + } + InsertChildren::InsertAt { id, pos } => workspace + .get(&t.trx, id) + .map(|child| block.insert_children_at(&mut t.trx, &child, pos)), + } + .map(|_| t.trx.encode_update_v1()), + block, + ) + }) + }) + }) + { + if let Some(update) = update { + if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { + error!("db write error: {}", e.to_string()); } - - // response block content - Json(block).into_response() - } else { - StatusCode::NOT_FOUND.into_response() } - } else { - StatusCode::NOT_FOUND.into_response() + + // response block content + return Json(block).into_response(); } + + StatusCode::NOT_FOUND.into_response() } /// Remove children in `Block` @@ -356,29 +353,43 @@ pub async fn remove_block_children( Extension(context): Extension>, Path(params): Path<(String, String, String)>, ) -> Response { - let (ws_id, block, child_id) = params; - info!("insert_block: {}, {}", ws_id, block); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - if let Some(update) = workspace.with_trx(|mut t| { - if let Some(block) = workspace.get(&t.trx, &block) { - if block.children_exists(&t.trx, &child_id) { - if let Some(child) = workspace.get(&t.trx, &child_id) { - block.remove_children(&mut t.trx, &child); - return Some(t.trx.encode_update_v1()); - } - } - } - None - }) { + let (ws_id, block_id, child_id) = params; + info!("remove_block: {}, {}, {}", ws_id, block_id, child_id); + + if let Some((update, block)) = + context + .storage + .get_workspace(&ws_id) + .await + .ok() + .and_then(|workspace| { + workspace.with_trx(|mut t| { + workspace.get(&t.trx, &block_id).map(|block| { + ( + block + .children_exists(&t.trx, &child_id) + .then(|| { + workspace.get(&t.trx, &child_id).map(|child| { + block.remove_children(&mut t.trx, &child); + t.trx.encode_update_v1() + }) + }) + .flatten(), + block, + ) + }) + }) + }) + { + if let Some(update) = update { if let Err(e) = context.storage.docs().write_update(ws_id, &update).await { error!("db write error: {}", e.to_string()); } - // response block content - Json(block).into_response() - } else { - StatusCode::NOT_FOUND.into_response() } - } else { - StatusCode::NOT_FOUND.into_response() + + // response block content + return Json(block).into_response(); } + + StatusCode::NOT_FOUND.into_response() } diff --git a/libs/jwst-binding/jwst-swift/src/storage.rs b/libs/jwst-binding/jwst-swift/src/storage.rs index 9c99ec463..ae0579ac5 100644 --- a/libs/jwst-binding/jwst-swift/src/storage.rs +++ b/libs/jwst-binding/jwst-swift/src/storage.rs @@ -1,8 +1,8 @@ use crate::Workspace; -use jwst::{DocStorage, error, JwstError, JwstResult}; +use jwst::{error, DocStorage, JwstError, JwstResult}; use jwst_rpc::start_client; use jwst_storage::JwstStorage as AutoStorage; -use std::sync::{Arc}; +use std::sync::Arc; use tokio::{runtime::Runtime, sync::RwLock}; #[derive(Clone)] From 4d65a412ab0631d119d57e1cbc283911a3263c93 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Fri, 3 Mar 2023 09:59:50 +0800 Subject: [PATCH 3/4] chore: workspace apis --- apps/keck/src/server/api/blocks/workspace.rs | 180 +++++++++++-------- 1 file changed, 106 insertions(+), 74 deletions(-) diff --git a/apps/keck/src/server/api/blocks/workspace.rs b/apps/keck/src/server/api/blocks/workspace.rs index 11481e475..3b0aeed8f 100644 --- a/apps/keck/src/server/api/blocks/workspace.rs +++ b/apps/keck/src/server/api/blocks/workspace.rs @@ -1,7 +1,6 @@ use super::*; use axum::{ extract::{Path, Query}, - http::header, response::Response, }; use jwst::{parse_history, parse_history_client, DocStorage}; @@ -28,15 +27,16 @@ pub async fn get_workspace( Path(ws_id): Path, ) -> Response { info!("get_workspace: {}", ws_id); + if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - Json(workspace).into_response() - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), - ) - .into_response() + return Json(workspace).into_response(); } + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() } /// Create a `Workspace` by id @@ -124,14 +124,14 @@ pub async fn workspace_client( Path(ws_id): Path, ) -> Response { if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - Json(workspace.client_id()).into_response() - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), - ) - .into_response() + return Json(workspace.client_id()).into_response(); } + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() } /// Block search query @@ -161,28 +161,34 @@ pub struct BlockSearchQuery { pub async fn workspace_search( Extension(context): Extension>, Path(ws_id): Path, - query: Query, + Query(search): Query, ) -> Response { - let query_text = &query.query; - info!("workspace_search: {ws_id:?} query = {query_text:?}"); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - match workspace.search(query_text) { + let BlockSearchQuery { query } = search; + info!("workspace_search: {ws_id:?} query = {query:?}"); + + if let Ok(resp) = context + .storage + .get_workspace(&ws_id) + .await + .map(|workspace| match workspace.search(&query) { Ok(list) => { - debug!("workspace_search: {ws_id:?} query = {query_text:?}; {list:#?}"); + debug!("workspace_search: {ws_id:?} query = {query:?}; {list:#?}"); Json(list).into_response() } Err(err) => { error!("Internal server error calling workspace_search: {err:?}"); StatusCode::INTERNAL_SERVER_ERROR.into_response() } - } - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), - ) - .into_response() + }) + { + return resp; } + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() } /// Get `Block` in `Workspace` @@ -209,29 +215,40 @@ pub async fn get_workspace_block( ) -> Response { let Pagination { offset, limit } = pagination; info!("get_workspace_block: {ws_id:?}"); - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - let total = workspace.block_count() as usize; - let data = workspace.with_trx(|t| { - workspace.blocks(&t.trx, |blocks| { - blocks.skip(offset).take(limit).collect::>() - }) - }); + if let Some((total, data)) = context + .storage + .get_workspace(&ws_id) + .await + .ok() + .map(|workspace| { + let total = workspace.block_count() as usize; - let status = if data.is_empty() { - StatusCode::NOT_FOUND - } else { - StatusCode::OK - }; + let data = workspace.with_trx(|t| { + workspace.blocks(&t.trx, |blocks| { + blocks.skip(offset).take(limit).collect::>() + }) + }); - (status, Json(PageData { total, data })).into_response() - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), + (total, data) + }) + { + return ( + if data.is_empty() { + StatusCode::NOT_FOUND + } else { + StatusCode::OK + }, + Json(PageData { total, data }), ) - .into_response() + .into_response(); } + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() } /// Get all client ids of the `Workspace` @@ -262,19 +279,25 @@ pub async fn history_workspace_clients( Extension(context): Extension>, Path(ws_id): Path, ) -> Response { - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - if let Some(history) = parse_history_client(&workspace.doc()) { - Json(history).into_response() - } else { - StatusCode::INTERNAL_SERVER_ERROR.into_response() - } - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), - ) - .into_response() + if let Ok(resp) = context + .storage + .get_workspace(&ws_id) + .await + .map(|workspace| { + parse_history_client(&workspace.doc()).map_or_else( + || StatusCode::INTERNAL_SERVER_ERROR.into_response(), + |history| Json(history).into_response(), + ) + }) + { + return resp; } + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() } /// Get the history generated by a specific `Client ID` of the `Workspace` @@ -299,25 +322,34 @@ pub async fn history_workspace( Extension(context): Extension>, Path(params): Path<(String, String)>, ) -> Response { - let (ws_id, client) = params; - if let Ok(workspace) = context.storage.get_workspace(&ws_id).await { - if let Ok(client) = client.parse::() { - if let Some(json) = parse_history(&workspace.doc(), client) - .and_then(|history| serde_json::to_string(&history).ok()) + let (ws_id, client_id) = params; + + match client_id.parse::() { + Ok(client) => { + if let Ok(resp) = context + .storage + .get_workspace(&ws_id) + .await + .map(|workspace| { + parse_history(&workspace.doc(), client).map_or_else( + || StatusCode::INTERNAL_SERVER_ERROR.into_response(), + |history| Json(history).into_response(), + ) + }) { - ([(header::CONTENT_TYPE, "application/json")], json).into_response() - } else { - StatusCode::INTERNAL_SERVER_ERROR.into_response() + return resp; } - } else { - StatusCode::BAD_REQUEST.into_response() + + ( + StatusCode::NOT_FOUND, + format!("Workspace({ws_id:?}) not found"), + ) + .into_response() + } + Err(e) => { + error!("client id parsing failure: {e}"); + return StatusCode::BAD_REQUEST.into_response(); } - } else { - ( - StatusCode::NOT_FOUND, - format!("Workspace({ws_id:?}) not found"), - ) - .into_response() } } From 376c672701fa3a5d86dae47504de3fa831adc7d6 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Fri, 3 Mar 2023 15:30:07 +0800 Subject: [PATCH 4/4] chore: improve --- apps/keck/src/server/api/blocks/block.rs | 21 ++++++++------------ apps/keck/src/server/api/blocks/workspace.rs | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/apps/keck/src/server/api/blocks/block.rs b/apps/keck/src/server/api/blocks/block.rs index cdbb0ae87..612df7159 100644 --- a/apps/keck/src/server/api/blocks/block.rs +++ b/apps/keck/src/server/api/blocks/block.rs @@ -2,7 +2,7 @@ use super::*; use axum::{extract::Query, response::Response}; use jwst::DocStorage; use lib0::any::Any; -use serde_json::Value as JsonValue; +use serde_json::{Map, Value}; /// Get a `Block` by id /// - Return 200 and `Block`'s data if `Block` is exists. @@ -66,7 +66,7 @@ pub async fn get_block( pub async fn set_block( Extension(context): Extension>, Path(params): Path<(String, String)>, - Json(payload): Json, + Json(payload): Json>, ) -> Response { let (ws_id, block_id) = params; info!("set_block: {}, {}", ws_id, block_id); @@ -82,18 +82,13 @@ pub async fn set_block( let block = t.create(&block_id, "text"); let count = payload - .as_object() - .map(|block_content| { - block_content - .iter() - .filter_map(|(key, value)| { - serde_json::from_value::(value.clone()) - .map(|value| block.set(&mut t.trx, key, value)) - .ok() - }) - .count() + .into_iter() + .filter_map(|(key, value)| { + serde_json::from_value::(value) + .map(|value| block.set(&mut t.trx, &key, value)) + .ok() }) - .unwrap_or_default(); + .count(); Some(((count > 0).then(|| t.trx.encode_update_v1()), block)) }) diff --git a/apps/keck/src/server/api/blocks/workspace.rs b/apps/keck/src/server/api/blocks/workspace.rs index 3b0aeed8f..104b7b193 100644 --- a/apps/keck/src/server/api/blocks/workspace.rs +++ b/apps/keck/src/server/api/blocks/workspace.rs @@ -348,7 +348,7 @@ pub async fn history_workspace( } Err(e) => { error!("client id parsing failure: {e}"); - return StatusCode::BAD_REQUEST.into_response(); + StatusCode::BAD_REQUEST.into_response() } } }