config doc reqeust

This commit is contained in:
appflowy 2021-09-09 17:34:01 +08:00
parent a5a07944dc
commit 2b4a9c2497
37 changed files with 196 additions and 278 deletions

View File

@ -77,7 +77,6 @@ impl Token {
use actix_web::{dev::Payload, FromRequest, HttpRequest};
use flowy_net::config::HEADER_TOKEN;
use futures::future::{ready, Ready};
use std::convert::TryInto;
impl FromRequest for Token {
type Config = ();

View File

@ -46,9 +46,8 @@ impl LoggedUser {
}
use actix_web::{dev::Payload, FromRequest, HttpRequest};
use flowy_net::config::HEADER_TOKEN;
use futures::future::{ready, Ready};
use std::convert::TryInto;
impl FromRequest for LoggedUser {
type Config = ();

View File

@ -18,7 +18,7 @@ use flowy_workspace::{
app::parser::{AppDesc, AppName},
workspace::parser::WorkspaceId,
},
protobuf::{CreateAppParams, QueryAppParams, RepeatedApp, RepeatedView, UpdateAppParams},
protobuf::{CreateAppParams, QueryAppParams, RepeatedView, UpdateAppParams},
};
use protobuf::Message;
use sqlx::{postgres::PgArguments, PgPool, Postgres};

View File

@ -146,7 +146,7 @@ pub async fn spawn_app() -> TestApp {
let _ = tokio::spawn(async {
let _ = application.run_until_stopped();
drop_test_database(database_name).await;
// drop_test_database(database_name).await;
});
TestApp {
@ -181,6 +181,7 @@ async fn configure_database(config: &DatabaseSettings) -> PgPool {
connection_pool
}
#[allow(dead_code)]
async fn drop_test_database(database_name: String) {
// https://stackoverflow.com/questions/36502401/postgres-drop-database-error-pq-cannot-drop-the-currently-open-database?rq=1
let configuration = {

View File

@ -9,7 +9,6 @@ edition = "2018"
[dependencies]
derive_more = {version = "0.99", features = ["display"]}
flowy-dispatch = { path = "../flowy-dispatch" }
flowy-log = { path = "../flowy-log" }
flowy-derive = { path = "../flowy-derive" }
flowy-database = { path = "../flowy-database" }
flowy-infra = { path = "../flowy-infra" }

View File

@ -27,7 +27,7 @@ impl TryInto<CreateDocParams> for CreateDocRequest {
type Error = DocError;
fn try_into(self) -> Result<CreateDocParams, Self::Error> {
let id = DocViewId::parse(self.id)
let id = DocId::parse(self.id)
.map_err(|e| ErrorBuilder::new(ErrorCode::DocIdInvalid).msg(e).build())?
.0;

View File

@ -1,7 +1,4 @@
use crate::{
entities::doc::parser::{DocId, DocPath},
errors::*,
};
use crate::{entities::doc::parser::DocId, errors::*};
use flowy_derive::ProtoBuf;
use std::convert::TryInto;

View File

@ -1,14 +0,0 @@
use unicode_segmentation::UnicodeSegmentation;
#[derive(Debug)]
pub struct DocDesc(pub String);
impl DocDesc {
pub fn parse(s: String) -> Result<DocDesc, String> {
if s.graphemes(true).count() > 1000 {
return Err(format!("Doc desc too long"));
}
Ok(Self(s))
}
}

View File

@ -1,12 +0,0 @@
#[derive(Debug)]
pub struct DocName(pub String);
impl DocName {
pub fn parse(s: String) -> Result<DocName, String> {
if s.trim().is_empty() {
return Err(format!("Doc name can not be empty or whitespace"));
}
Ok(Self(s))
}
}

View File

@ -1,12 +0,0 @@
#[derive(Debug)]
pub struct DocPath(pub String);
impl DocPath {
pub fn parse(s: String) -> Result<DocPath, String> {
if s.trim().is_empty() {
return Err(format!("Doc path can not be empty or whitespace"));
}
Ok(Self(s))
}
}

View File

@ -1,12 +0,0 @@
#[derive(Debug)]
pub struct DocViewId(pub String);
impl DocViewId {
pub fn parse(s: String) -> Result<DocViewId, String> {
if s.trim().is_empty() {
return Err(format!("Doc view id can not be empty or whitespace"));
}
Ok(Self(s))
}
}

View File

@ -1,11 +1,3 @@
mod doc_desc;
mod doc_id;
mod doc_name;
mod doc_path;
mod doc_view_id;
pub use doc_desc::*;
pub use doc_id::*;
pub use doc_name::*;
pub use doc_path::*;
pub use doc_view_id::*;

View File

@ -1,11 +1,6 @@
use crate::{
entities::doc::*,
errors::DocError,
services::{doc_controller::DocController, file_manager::FileManager},
};
use crate::{entities::doc::*, errors::DocError, services::doc_controller::DocController};
use flowy_dispatch::prelude::*;
use std::{convert::TryInto, path::Path};
use tokio::sync::RwLock;
use std::convert::TryInto;
#[tracing::instrument(skip(data, controller))]
pub async fn create_doc_handler(data: Data<CreateDocRequest>, controller: Unit<DocController>) -> DataResult<Doc, DocError> {
@ -23,7 +18,7 @@ pub async fn read_doc_handler(data: Data<QueryDocRequest>, controller: Unit<DocC
#[tracing::instrument(skip(data, controller))]
pub async fn update_doc_handler(data: Data<UpdateDocRequest>, controller: Unit<DocController>) -> Result<(), DocError> {
let mut params: UpdateDocParams = data.into_inner().try_into()?;
let params: UpdateDocParams = data.into_inner().try_into()?;
let _ = controller.update_doc(params).await?;
Ok(())
}

View File

@ -1,3 +1,3 @@
mod observable;
pub use observable::*;
pub(crate) use observable::*;

View File

@ -10,4 +10,5 @@ impl std::convert::Into<i32> for DocObservable {
fn into(self) -> i32 { self as i32 }
}
#[allow(dead_code)]
pub(crate) fn observable(id: &str, ty: DocObservable) -> ObservableBuilder { ObservableBuilder::new(id, ty, OBSERVABLE_CATEGORY) }

View File

@ -62,14 +62,14 @@ impl DocController {
}
impl DocController {
#[tracing::instrument(level = "debug", skip(self), err)]
#[tracing::instrument(skip(self), err)]
async fn create_doc_on_server(&self, params: CreateDocParams) -> Result<Doc, DocError> {
let token = self.user.token()?;
let doc = self.server.create_doc(&token, params).await?;
Ok(doc)
}
#[tracing::instrument(level = "debug", skip(self, params), err)]
#[tracing::instrument(level = "debug", skip(self), err)]
fn update_doc_on_server(&self, params: UpdateDocParams) -> Result<(), DocError> {
let token = self.user.token()?;
let server = self.server.clone();
@ -85,13 +85,13 @@ impl DocController {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, params), err)]
#[tracing::instrument(level = "debug", skip(self), err)]
fn read_doc_on_server(&self, params: QueryDocParams) -> Result<(), DocError> {
let token = self.user.token()?;
let server = self.server.clone();
tokio::spawn(async move {
// Opti: handle the error and retry?
let doc = server.read_doc(&token, params).await?;
let _doc = server.read_doc(&token, params).await?;
// save to disk
// notify
@ -100,7 +100,7 @@ impl DocController {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, params), err)]
#[tracing::instrument(level = "debug", skip(self), err)]
fn delete_doc_on_server(&self, params: QueryDocParams) -> Result<(), DocError> {
let token = self.user.token()?;
let server = self.server.clone();

View File

@ -48,15 +48,14 @@ pub struct FileInfo {
pub encoding: CharacterEncoding,
}
#[allow(dead_code)]
pub(crate) fn try_load_file<P>(path: P) -> Result<(String, FileInfo), FileError>
where
P: AsRef<Path>,
{
let mut f =
File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
let mut f = File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
let mut bytes = Vec::new();
f.read_to_end(&mut bytes)
.map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
f.read_to_end(&mut bytes).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
let encoding = CharacterEncoding::guess(&bytes);
let s = try_decode(bytes, encoding, path.as_ref())?;
@ -69,12 +68,8 @@ where
Ok((s, info))
}
pub(crate) fn try_save(
path: &Path,
text: &str,
encoding: CharacterEncoding,
_file_info: Option<&FileInfo>,
) -> io::Result<()> {
#[allow(dead_code)]
pub(crate) fn try_save(path: &Path, text: &str, encoding: CharacterEncoding, _file_info: Option<&FileInfo>) -> io::Result<()> {
let tmp_extension = path.extension().map_or_else(
|| OsString::from("swp"),
|ext| {
@ -97,20 +92,14 @@ pub(crate) fn try_save(
Ok(())
}
pub(crate) fn try_decode(
bytes: Vec<u8>,
encoding: CharacterEncoding,
path: &Path,
) -> Result<String, FileError> {
#[allow(dead_code)]
pub(crate) fn try_decode(bytes: Vec<u8>, encoding: CharacterEncoding, path: &Path) -> Result<String, FileError> {
match encoding {
CharacterEncoding::Utf8 => {
Ok(String::from(str::from_utf8(&bytes).map_err(|_e| {
FileError::UnknownEncoding(path.to_owned())
})?))
},
CharacterEncoding::Utf8 => Ok(String::from(
str::from_utf8(&bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?,
)),
CharacterEncoding::Utf8WithBom => {
let s = String::from_utf8(bytes)
.map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
let s = String::from_utf8(bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
Ok(String::from(&s[UTF8_BOM.len()..]))
},
}
@ -123,8 +112,5 @@ pub(crate) fn create_dir_if_not_exist(dir: &str) -> Result<(), io::Error> {
}
pub(crate) fn get_modified_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
File::open(path)
.and_then(|f| f.metadata())
.and_then(|meta| meta.modified())
.ok()
File::open(path).and_then(|f| f.metadata()).and_then(|meta| meta.modified()).ok()
}

View File

@ -20,6 +20,7 @@ impl FileManager {
}
}
#[allow(dead_code)]
pub(crate) fn open<T>(&mut self, path: &Path, id: T) -> Result<String, FileError>
where
T: Into<FileId>,
@ -35,6 +36,7 @@ impl FileManager {
Ok(s)
}
#[allow(dead_code)]
pub(crate) fn save<T>(&mut self, path: &Path, text: &String, id: T) -> Result<(), FileError>
where
T: Into<FileId>,
@ -58,12 +60,8 @@ impl FileManager {
}
}
pub(crate) fn create_file(
&mut self,
id: &str,
dir: &str,
text: &str,
) -> Result<PathBuf, FileError> {
#[allow(dead_code)]
pub(crate) fn create_file(&mut self, id: &str, dir: &str, text: &str) -> Result<PathBuf, FileError> {
let path = PathBuf::from(format!("{}/{}", dir, id));
let file_id: FileId = id.to_owned().into();
log::info!("Create doc at: {:?}", path);
@ -75,9 +73,7 @@ impl FileManager {
pub(crate) fn get_info(&self, id: &FileId) -> Option<&FileInfo> { self.file_info.get(id) }
#[allow(dead_code)]
pub(crate) fn get_file_id(&self, path: &Path) -> Option<FileId> {
self.open_files.get(path).cloned()
}
pub(crate) fn get_file_id(&self, path: &Path) -> Option<FileId> { self.open_files.get(path).cloned() }
#[allow(dead_code)]
pub fn check_file(&mut self, path: &Path, id: &FileId) -> bool {
@ -91,9 +87,9 @@ impl FileManager {
false
}
#[allow(dead_code)]
fn save_new(&mut self, path: &Path, text: &str, id: &FileId) -> Result<(), FileError> {
try_save(path, text, CharacterEncoding::Utf8, self.get_info(id))
.map_err(|e| FileError::Io(e, path.to_owned()))?;
try_save(path, text, CharacterEncoding::Utf8, self.get_info(id)).map_err(|e| FileError::Io(e, path.to_owned()))?;
let info = FileInfo {
encoding: CharacterEncoding::Utf8,
path: path.to_owned(),
@ -105,6 +101,7 @@ impl FileManager {
Ok(())
}
#[allow(dead_code)]
fn save_existing(&mut self, path: &Path, text: &String, id: &FileId) -> Result<(), FileError> {
let prev_path = self.file_info[id].path.clone();
if prev_path != path {
@ -114,8 +111,7 @@ impl FileManager {
return Err(FileError::HasChanged(path.to_owned()));
} else {
let encoding = self.file_info[&id].encoding;
try_save(path, text, encoding, self.get_info(id))
.map_err(|e| FileError::Io(e, path.to_owned()))?;
try_save(path, text, encoding, self.get_info(id)).map_err(|e| FileError::Io(e, path.to_owned()))?;
self.file_info.get_mut(&id).unwrap().modified_time = get_modified_time(path);
}
Ok(())

View File

@ -15,7 +15,7 @@ impl ResponseMiddleware for DocMiddleware {
match token {
None => {},
Some(token) => {
Some(_token) => {
// let error =
// WorkspaceError::new(ErrorCode::UserUnauthorized, "");
// observable(token,

View File

@ -4,18 +4,30 @@ use crate::{
services::server::DocumentServerAPI,
};
use flowy_infra::future::ResultFuture;
use flowy_net::{config::HEADER_TOKEN, request::HttpRequestBuilder};
use flowy_net::{config::*, request::HttpRequestBuilder};
pub struct DocServer {}
impl DocumentServerAPI for DocServer {
fn create_doc(&self, token: &str, params: CreateDocParams) -> ResultFuture<Doc, DocError> { unimplemented!() }
fn create_doc(&self, token: &str, params: CreateDocParams) -> ResultFuture<Doc, DocError> {
let token = token.to_owned();
ResultFuture::new(async move { create_doc_request(&token, params, DOC_URL.as_ref()).await })
}
fn read_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<Option<Doc>, DocError> { unimplemented!() }
fn read_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<Option<Doc>, DocError> {
let token = token.to_owned();
ResultFuture::new(async move { read_doc_request(&token, params, DOC_URL.as_ref()).await })
}
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError> { unimplemented!() }
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError> {
let token = token.to_owned();
ResultFuture::new(async move { update_doc_request(&token, params, DOC_URL.as_ref()).await })
}
fn delete_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<(), DocError> { unimplemented!() }
fn delete_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<(), DocError> {
let token = token.to_owned();
ResultFuture::new(async move { delete_doc_request(&token, params, DOC_URL.as_ref()).await })
}
}
pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(super::middleware::MIDDLEWARE.clone()) }
@ -25,9 +37,38 @@ pub async fn create_doc_request(token: &str, params: CreateDocParams, url: &str)
.post(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?
.response()
.await?;
Ok(doc)
}
pub async fn read_doc_request(token: &str, params: QueryDocParams, url: &str) -> Result<Option<Doc>, DocError> {
let doc = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.option_response()
.await?;
Ok(doc)
}
pub async fn update_doc_request(token: &str, params: UpdateDocParams, url: &str) -> Result<(), DocError> {
let _ = request_builder()
.patch(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?;
Ok(())
}
pub async fn delete_doc_request(token: &str, params: QueryDocParams, url: &str) -> Result<(), DocError> {
let _ = request_builder()
.delete(url)
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?;
Ok(())
}

View File

@ -3,15 +3,14 @@ use crate::{
errors::DocError,
services::server::DocumentServerAPI,
};
use flowy_infra::{future::ResultFuture, uuid};
use flowy_infra::future::ResultFuture;
pub struct DocServerMock {}
impl DocumentServerAPI for DocServerMock {
fn create_doc(&self, _token: &str, _params: CreateDocParams) -> ResultFuture<Doc, DocError> {
let uuid = uuid();
fn create_doc(&self, _token: &str, params: CreateDocParams) -> ResultFuture<Doc, DocError> {
let doc = Doc {
id: uuid,
data: "".to_string(),
id: params.id,
data: params.data,
};
ResultFuture::new(async { Ok(doc) })

View File

@ -1,6 +1,5 @@
use crate::{
errors::DocError,
module::DocumentDatabase,
sql_tables::doc::{DocTable, DocTableChangeset},
};
use flowy_database::{
@ -8,7 +7,7 @@ use flowy_database::{
schema::{doc_table, doc_table::dsl},
SqliteConnection,
};
use std::sync::Arc;
pub struct DocTableSql {}
impl DocTableSql {

View File

@ -1,6 +1,5 @@
use crate::entities::doc::{CreateDocParams, Doc, UpdateDocParams};
use crate::entities::doc::{Doc, UpdateDocParams};
use flowy_database::schema::doc_table;
use flowy_infra::timestamp;
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "doc_table"]
@ -14,7 +13,7 @@ impl DocTable {
pub fn new(doc: Doc) -> Self {
Self {
id: doc.id,
data: "".to_owned(),
data: doc.data,
version: 0,
}
}

View File

@ -2,24 +2,35 @@ use crate::helper::*;
use flowy_test::FlowyEnv;
#[test]
fn file_create_test() {
fn doc_create_test() {
let sdk = FlowyEnv::setup().sdk;
let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", "123");
dbg!(&doc_desc);
let doc = create_doc(&sdk, "flutter ❤️ rust");
dbg!(&doc);
let doc = read_doc_data(&sdk, &doc_desc.id, &doc_desc.path);
assert_eq!(doc.text, "123".to_owned());
let doc = read_doc_data(&sdk, &doc.id);
assert_eq!(doc.data, "flutter ❤️ rust".to_owned());
}
#[test]
fn file_update_text_test() {
fn doc_update_test() {
let sdk = FlowyEnv::setup().sdk;
let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", "");
let doc_desc = create_doc(&sdk, "flutter ❤️ rust");
dbg!(&doc_desc);
let content = "😁😁😁😁😁😁😁😁😁😁".to_owned();
save_doc(&sdk, &doc_desc, &content);
let doc = read_doc_data(&sdk, &doc_desc.id, &doc_desc.path);
assert_eq!(doc.text, content);
let doc = read_doc_data(&sdk, &doc_desc.id);
assert_eq!(doc.data, content);
}
#[test]
fn doc_update_big_data_test() {
let sdk = FlowyEnv::setup().sdk;
let doc_desc = create_doc(&sdk, "");
let content = "flutter ❤️ rust".repeat(1000000);
save_doc(&sdk, &doc_desc, &content);
let doc = read_doc_data(&sdk, &doc_desc.id);
assert_eq!(doc.data, content);
}

View File

@ -4,11 +4,9 @@ use flowy_document::{entities::doc::*, event::EditorEvent::*};
use flowy_infra::uuid;
use flowy_test::prelude::*;
pub fn create_doc(sdk: &FlowyTestSDK, name: &str, desc: &str, text: &str) -> Doc {
pub fn create_doc(sdk: &FlowyTestSDK, text: &str) -> Doc {
let request = CreateDocRequest {
id: uuid(),
name: name.to_owned(),
desc: desc.to_owned(),
data: text.to_owned(),
};
@ -20,11 +18,9 @@ pub fn create_doc(sdk: &FlowyTestSDK, name: &str, desc: &str, text: &str) -> Doc
doc
}
pub fn save_doc(sdk: &FlowyTestSDK, desc: &Doc, content: &str) {
pub fn save_doc(sdk: &FlowyTestSDK, doc: &Doc, content: &str) {
let request = UpdateDocRequest {
id: desc.id.clone(),
name: Some(desc.name.clone()),
desc: Some(desc.desc.clone()),
id: doc.id.clone(),
data: Some(content.to_owned()),
};
@ -46,17 +42,12 @@ pub fn save_doc(sdk: &FlowyTestSDK, desc: &Doc, content: &str) {
// doc
// }
pub(crate) fn read_doc_data(sdk: &FlowyTestSDK, doc_id: &str, path: &str) -> DocData {
let request = QueryDocDataRequest {
pub(crate) fn read_doc_data(sdk: &FlowyTestSDK, doc_id: &str) -> Doc {
let request = QueryDocRequest {
doc_id: doc_id.to_string(),
path: path.to_string(),
};
let doc = DocTest::new(sdk.clone())
.event(ReadDocData)
.request(request)
.sync_send()
.parse::<DocData>();
let doc = DocTest::new(sdk.clone()).event(ReadDoc).request(request).sync_send().parse::<Doc>();
doc
}

View File

@ -14,4 +14,7 @@ lazy_static! {
pub static ref WORKSPACE_URL: String = format!("{}/api/workspace", HOST);
pub static ref APP_URL: String = format!("{}/api/app", HOST);
pub static ref VIEW_URL: String = format!("{}/api/view", HOST);
//
pub static ref DOC_URL: String = format!("{}/api/doc", HOST);
}

View File

@ -42,7 +42,7 @@ impl ServerError {
self
}
pub fn is_not_found(&self) -> bool { self.code == ErrorCode::RecordNotFound }
pub fn is_record_not_found(&self) -> bool { self.code == ErrorCode::RecordNotFound }
pub fn is_unauthorized(&self) -> bool { self.code == ErrorCode::UserUnauthorized }
}

View File

@ -1,17 +1,8 @@
use crate::{
config::HEADER_TOKEN,
errors::{ErrorCode, ServerError},
response::FlowyResponse,
};
use crate::{config::HEADER_TOKEN, errors::ServerError, response::FlowyResponse};
use bytes::Bytes;
use hyper::{http, http::HeaderValue};
use hyper::http;
use protobuf::ProtobufError;
use reqwest::{
header::{HeaderMap, ToStrError},
Client,
Method,
Response,
};
use reqwest::{header::HeaderMap, Client, Method, Response};
use std::{
convert::{TryFrom, TryInto},
sync::Arc,
@ -94,7 +85,50 @@ impl HttpRequestBuilder {
Ok(self)
}
pub async fn send(mut self) -> Result<Self, ServerError> {
pub async fn send(self) -> Result<(), ServerError> {
let _ = self.inner_send().await?;
Ok(())
}
pub async fn response<T>(self) -> Result<T, ServerError>
where
T: TryFrom<Bytes, Error = ProtobufError>,
{
let builder = self.inner_send().await?;
match builder.response {
None => Err(unexpected_empty_payload(&builder.url)),
Some(data) => Ok(T::try_from(data)?),
}
}
pub async fn option_response<T>(self) -> Result<Option<T>, ServerError>
where
T: TryFrom<Bytes, Error = ProtobufError>,
{
let result = self.inner_send().await;
match result {
Ok(builder) => match builder.response {
None => Err(unexpected_empty_payload(&builder.url)),
Some(data) => Ok(Some(T::try_from(data)?)),
},
Err(error) => match error.is_record_not_found() {
true => Ok(None),
false => Err(error),
},
}
}
fn token(&self) -> Option<String> {
match self.headers.get(HEADER_TOKEN) {
None => None,
Some(header) => match header.to_str() {
Ok(val) => Some(val.to_owned()),
Err(_) => None,
},
}
}
async fn inner_send(mut self) -> Result<Self, ServerError> {
let (tx, rx) = oneshot::channel::<Result<Response, _>>();
let url = self.url.clone();
let body = self.body.take();
@ -132,29 +166,11 @@ impl HttpRequestBuilder {
Some(error) => Err(error),
}
}
}
pub async fn response<T2>(self) -> Result<T2, ServerError>
where
T2: TryFrom<Bytes, Error = ProtobufError>,
{
match self.response {
None => {
let msg = format!("Request: {} receives unexpected empty body", self.url);
Err(ServerError::payload_none().context(msg))
},
Some(data) => Ok(T2::try_from(data)?),
}
}
fn token(&self) -> Option<String> {
match self.headers.get(HEADER_TOKEN) {
None => None,
Some(header) => match header.to_str() {
Ok(val) => Some(val.to_owned()),
Err(_) => None,
},
}
}
fn unexpected_empty_payload(url: &str) -> ServerError {
let msg = format!("Request: {} receives unexpected empty payload", url);
ServerError::payload_none().context(msg)
}
async fn flowy_response_from(original: Response) -> Result<FlowyResponse, ServerError> {

View File

@ -27,7 +27,7 @@ impl DocumentUser for EditorUserImpl {
let dir = self
.user_session
.user_dir()
.map_err(|e| ErrorBuilder::new(ErrorCode::EditorUserNotLoginYet).error(e).build())?;
.map_err(|e| ErrorBuilder::new(ErrorCode::UserUnauthorized).error(e).build())?;
let doc_dir = format!("{}/doc", dir);
if !Path::new(&doc_dir).exists() {

View File

@ -38,6 +38,7 @@ fn crate_log_filter(level: Option<String>) -> String {
filters.push(format!("flowy_sdk={}", level));
filters.push(format!("flowy_workspace={}", level));
filters.push(format!("flowy_user={}", level));
filters.push(format!("flowy_document={}", level));
filters.push(format!("flowy_observable={}", level));
filters.push(format!("info"));
filters.join(",")

View File

@ -8,7 +8,6 @@ edition = "2018"
[dependencies]
derive_more = {version = "0.99", features = ["display"]}
flowy-dispatch = { path = "../flowy-dispatch" }
flowy-log = { path = "../flowy-log" }
flowy-derive = { path = "../flowy-derive" }
flowy-database = { path = "../flowy-database" }
flowy-sqlite = { path = "../flowy-sqlite" }

View File

@ -1,2 +1,2 @@
mod observable;
pub use observable::*;
pub(crate) use observable::*;

View File

@ -72,24 +72,12 @@ impl ResponseMiddleware for Middleware {
pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(MIDDLEWARE.clone()) }
pub async fn user_sign_up_request(params: SignUpParams, url: &str) -> Result<SignUpResponse, UserError> {
let response = request_builder()
.post(&url.to_owned())
.protobuf(params)?
.send()
.await?
.response()
.await?;
let response = request_builder().post(&url.to_owned()).protobuf(params)?.response().await?;
Ok(response)
}
pub async fn user_sign_in_request(params: SignInParams, url: &str) -> Result<SignInResponse, UserError> {
let response = request_builder()
.post(&url.to_owned())
.protobuf(params)?
.send()
.await?
.response()
.await?;
let response = request_builder().post(&url.to_owned()).protobuf(params)?.response().await?;
Ok(response)
}
@ -102,8 +90,6 @@ pub async fn get_user_profile_request(token: &str, url: &str) -> Result<UserProf
let user_profile = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
.send()
.await?
.response()
.await?;
Ok(user_profile)

View File

@ -7,7 +7,6 @@ edition = "2018"
[dependencies]
flowy-dispatch = { path = "../flowy-dispatch" }
flowy-log = { path = "../flowy-log" }
flowy-derive = { path = "../flowy-derive" }
flowy-database = { path = "../flowy-database" }
flowy-sqlite = { path = "../flowy-sqlite" }

View File

@ -10,7 +10,7 @@ use crate::{
};
use flowy_net::{request::ResponseMiddleware, response::FlowyResponse};
struct WorkspaceMiddleware {}
pub(crate) struct WorkspaceMiddleware {}
impl ResponseMiddleware for WorkspaceMiddleware {
fn receive_response(&self, token: &Option<String>, response: &FlowyResponse) {
if let Some(error) = &response.error {

View File

@ -15,12 +15,7 @@ use crate::{
services::server::WorkspaceServerAPI,
};
use flowy_infra::future::ResultFuture;
use flowy_net::{
config::*,
request::{HttpRequestBuilder, ResponseMiddleware},
response::FlowyResponse,
};
use std::sync::Arc;
use flowy_net::{config::*, request::HttpRequestBuilder};
pub struct WorkspaceServer {}
@ -92,27 +87,20 @@ pub async fn create_workspace_request(token: &str, params: CreateWorkspaceParams
.post(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?
.response()
.await?;
Ok(workspace)
}
pub async fn read_workspaces_request(token: &str, params: QueryWorkspaceParams, url: &str) -> Result<RepeatedWorkspace, WorkspaceError> {
let result = request_builder()
let repeated_workspace = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?
.response::<RepeatedWorkspace>()
.await;
.await?;
match result {
Ok(repeated_workspace) => Ok(repeated_workspace),
Err(e) => Err(e.into()),
}
Ok(repeated_workspace)
}
pub async fn update_workspace_request(token: &str, params: UpdateWorkspaceParams, url: &str) -> Result<(), WorkspaceError> {
@ -141,31 +129,20 @@ pub async fn create_app_request(token: &str, params: CreateAppParams, url: &str)
.post(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?
.response()
.await?;
Ok(app)
}
pub async fn read_app_request(token: &str, params: QueryAppParams, url: &str) -> Result<Option<App>, WorkspaceError> {
let result = request_builder()
let app = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await;
.option_response()
.await?;
match result {
Ok(builder) => Ok(Some(builder.response::<App>().await?)),
Err(e) => {
if e.is_not_found() {
Ok(None)
} else {
Err(e.into())
}
},
}
Ok(app)
}
pub async fn update_app_request(token: &str, params: UpdateAppParams, url: &str) -> Result<(), WorkspaceError> {
@ -194,34 +171,20 @@ pub async fn create_view_request(token: &str, params: CreateViewParams, url: &st
.post(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await?
.response()
.await?;
Ok(view)
}
pub async fn read_view_request(token: &str, params: QueryViewParams, url: &str) -> Result<Option<View>, WorkspaceError> {
let result = request_builder()
let view = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
.protobuf(params)?
.send()
.await;
.option_response()
.await?;
match result {
Ok(builder) => {
let view = builder.response::<View>().await?;
Ok(Some(view))
},
Err(e) => {
if e.is_not_found() {
Ok(None)
} else {
Err(e.into())
}
},
}
Ok(view)
}
pub async fn update_view_request(token: &str, params: UpdateViewParams, url: &str) -> Result<(), WorkspaceError> {

View File

@ -59,14 +59,10 @@ impl WorkspaceTableSql {
workspace_id: &str,
conn: &SqliteConnection,
) -> Result<Vec<AppTable>, WorkspaceError> {
let apps = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
let workspace_table: WorkspaceTable = dsl::workspace_table
.filter(workspace_table::id.eq(workspace_id))
.first::<WorkspaceTable>(conn)?;
let apps = AppTable::belonging_to(&workspace_table).load::<AppTable>(conn)?;
Ok(apps)
})?;
let workspace_table: WorkspaceTable = dsl::workspace_table
.filter(workspace_table::id.eq(workspace_id))
.first::<WorkspaceTable>(conn)?;
let apps = AppTable::belonging_to(&workspace_table).load::<AppTable>(conn)?;
Ok(apps)
}
}