consume reqwest status code

This commit is contained in:
appflowy 2021-08-21 17:17:54 +08:00
parent 6229b7f5b9
commit 49e5f38406
29 changed files with 501 additions and 254 deletions

View File

@ -20,13 +20,20 @@ class UserErrCode extends $pb.ProtobufEnum {
static const UserErrCode UserNotLoginYet = UserErrCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
static const UserErrCode ReadCurrentIdFailed = UserErrCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadCurrentIdFailed');
static const UserErrCode WriteCurrentIdFailed = UserErrCode._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WriteCurrentIdFailed');
static const UserErrCode EmailInvalid = UserErrCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailInvalid');
static const UserErrCode PasswordInvalid = UserErrCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordInvalid');
static const UserErrCode UserNameInvalid = UserErrCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameInvalid');
static const UserErrCode UserWorkspaceInvalid = UserErrCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserWorkspaceInvalid');
static const UserErrCode UserIdInvalid = UserErrCode._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdInvalid');
static const UserErrCode CreateDefaultWorkspaceFailed = UserErrCode._(25, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspaceFailed');
static const UserErrCode DefaultWorkspaceAlreadyExist = UserErrCode._(26, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DefaultWorkspaceAlreadyExist');
static const UserErrCode EmailIsEmpty = UserErrCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailIsEmpty');
static const UserErrCode EmailFormatInvalid = UserErrCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailFormatInvalid');
static const UserErrCode EmailAlreadyExists = UserErrCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailAlreadyExists');
static const UserErrCode PasswordIsEmpty = UserErrCode._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordIsEmpty');
static const UserErrCode PasswordTooLong = UserErrCode._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordTooLong');
static const UserErrCode PasswordContainsForbidCharacters = UserErrCode._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordContainsForbidCharacters');
static const UserErrCode PasswordFormatInvalid = UserErrCode._(33, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordFormatInvalid');
static const UserErrCode UserNameTooLong = UserErrCode._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameTooLong');
static const UserErrCode UserNameContainsForbiddenCharacters = UserErrCode._(41, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameContainsForbiddenCharacters');
static const UserErrCode UserNameIsEmpty = UserErrCode._(42, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameIsEmpty');
static const UserErrCode UserWorkspaceInvalid = UserErrCode._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserWorkspaceInvalid');
static const UserErrCode UserIdInvalid = UserErrCode._(51, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdInvalid');
static const UserErrCode CreateDefaultWorkspaceFailed = UserErrCode._(52, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspaceFailed');
static const UserErrCode DefaultWorkspaceAlreadyExist = UserErrCode._(53, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DefaultWorkspaceAlreadyExist');
static const UserErrCode NetworkError = UserErrCode._(100, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NetworkError');
static const $core.List<UserErrCode> values = <UserErrCode> [
@ -40,9 +47,16 @@ class UserErrCode extends $pb.ProtobufEnum {
UserNotLoginYet,
ReadCurrentIdFailed,
WriteCurrentIdFailed,
EmailInvalid,
PasswordInvalid,
UserNameInvalid,
EmailIsEmpty,
EmailFormatInvalid,
EmailAlreadyExists,
PasswordIsEmpty,
PasswordTooLong,
PasswordContainsForbidCharacters,
PasswordFormatInvalid,
UserNameTooLong,
UserNameContainsForbiddenCharacters,
UserNameIsEmpty,
UserWorkspaceInvalid,
UserIdInvalid,
CreateDefaultWorkspaceFailed,

View File

@ -22,19 +22,26 @@ const UserErrCode$json = const {
const {'1': 'UserNotLoginYet', '2': 10},
const {'1': 'ReadCurrentIdFailed', '2': 11},
const {'1': 'WriteCurrentIdFailed', '2': 12},
const {'1': 'EmailInvalid', '2': 20},
const {'1': 'PasswordInvalid', '2': 21},
const {'1': 'UserNameInvalid', '2': 22},
const {'1': 'UserWorkspaceInvalid', '2': 23},
const {'1': 'UserIdInvalid', '2': 24},
const {'1': 'CreateDefaultWorkspaceFailed', '2': 25},
const {'1': 'DefaultWorkspaceAlreadyExist', '2': 26},
const {'1': 'EmailIsEmpty', '2': 20},
const {'1': 'EmailFormatInvalid', '2': 21},
const {'1': 'EmailAlreadyExists', '2': 22},
const {'1': 'PasswordIsEmpty', '2': 30},
const {'1': 'PasswordTooLong', '2': 31},
const {'1': 'PasswordContainsForbidCharacters', '2': 32},
const {'1': 'PasswordFormatInvalid', '2': 33},
const {'1': 'UserNameTooLong', '2': 40},
const {'1': 'UserNameContainsForbiddenCharacters', '2': 41},
const {'1': 'UserNameIsEmpty', '2': 42},
const {'1': 'UserWorkspaceInvalid', '2': 50},
const {'1': 'UserIdInvalid', '2': 51},
const {'1': 'CreateDefaultWorkspaceFailed', '2': 52},
const {'1': 'DefaultWorkspaceAlreadyExist', '2': 53},
const {'1': 'NetworkError', '2': 100},
],
};
/// Descriptor for `UserErrCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List userErrCodeDescriptor = $convert.base64Decode('CgtVc2VyRXJyQ29kZRILCgdVbmtub3duEAASGgoWVXNlckRhdGFiYXNlSW5pdEZhaWxlZBABEhsKF1VzZXJEYXRhYmFzZVdyaXRlTG9ja2VkEAISGgoWVXNlckRhdGFiYXNlUmVhZExvY2tlZBADEhsKF1VzZXJEYXRhYmFzZURpZE5vdE1hdGNoEAQSHQoZVXNlckRhdGFiYXNlSW50ZXJuYWxFcnJvchAFEhQKEFNxbEludGVybmFsRXJyb3IQBhITCg9Vc2VyTm90TG9naW5ZZXQQChIXChNSZWFkQ3VycmVudElkRmFpbGVkEAsSGAoUV3JpdGVDdXJyZW50SWRGYWlsZWQQDBIQCgxFbWFpbEludmFsaWQQFBITCg9QYXNzd29yZEludmFsaWQQFRITCg9Vc2VyTmFtZUludmFsaWQQFhIYChRVc2VyV29ya3NwYWNlSW52YWxpZBAXEhEKDVVzZXJJZEludmFsaWQQGBIgChxDcmVhdGVEZWZhdWx0V29ya3NwYWNlRmFpbGVkEBkSIAocRGVmYXVsdFdvcmtzcGFjZUFscmVhZHlFeGlzdBAaEhAKDE5ldHdvcmtFcnJvchBk');
final $typed_data.Uint8List userErrCodeDescriptor = $convert.base64Decode('CgtVc2VyRXJyQ29kZRILCgdVbmtub3duEAASGgoWVXNlckRhdGFiYXNlSW5pdEZhaWxlZBABEhsKF1VzZXJEYXRhYmFzZVdyaXRlTG9ja2VkEAISGgoWVXNlckRhdGFiYXNlUmVhZExvY2tlZBADEhsKF1VzZXJEYXRhYmFzZURpZE5vdE1hdGNoEAQSHQoZVXNlckRhdGFiYXNlSW50ZXJuYWxFcnJvchAFEhQKEFNxbEludGVybmFsRXJyb3IQBhITCg9Vc2VyTm90TG9naW5ZZXQQChIXChNSZWFkQ3VycmVudElkRmFpbGVkEAsSGAoUV3JpdGVDdXJyZW50SWRGYWlsZWQQDBIQCgxFbWFpbElzRW1wdHkQFBIWChJFbWFpbEZvcm1hdEludmFsaWQQFRIWChJFbWFpbEFscmVhZHlFeGlzdHMQFhITCg9QYXNzd29yZElzRW1wdHkQHhITCg9QYXNzd29yZFRvb0xvbmcQHxIkCiBQYXNzd29yZENvbnRhaW5zRm9yYmlkQ2hhcmFjdGVycxAgEhkKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBAhEhMKD1VzZXJOYW1lVG9vTG9uZxAoEicKI1VzZXJOYW1lQ29udGFpbnNGb3JiaWRkZW5DaGFyYWN0ZXJzECkSEwoPVXNlck5hbWVJc0VtcHR5ECoSGAoUVXNlcldvcmtzcGFjZUludmFsaWQQMhIRCg1Vc2VySWRJbnZhbGlkEDMSIAocQ3JlYXRlRGVmYXVsdFdvcmtzcGFjZUZhaWxlZBA0EiAKHERlZmF1bHRXb3Jrc3BhY2VBbHJlYWR5RXhpc3QQNRIQCgxOZXR3b3JrRXJyb3IQZA==');
@$core.Deprecated('Use userErrorDescriptor instead')
const UserError$json = const {
'1': 'UserError',

View File

@ -1,15 +1,15 @@
use crate::config::MAX_PAYLOAD_SIZE;
use actix_web::web;
use flowy_net::{errors::NetworkError, response::*};
use flowy_net::response::*;
use futures::StreamExt;
use protobuf::{Message, ProtobufResult};
pub async fn parse_from_payload<T: Message>(payload: web::Payload) -> Result<T, NetworkError> {
pub async fn parse_from_payload<T: Message>(payload: web::Payload) -> Result<T, ServerError> {
let bytes = poll_payload(payload).await?;
parse_from_bytes(&bytes)
}
pub fn parse_from_bytes<T: Message>(bytes: &[u8]) -> Result<T, NetworkError> {
pub fn parse_from_bytes<T: Message>(bytes: &[u8]) -> Result<T, ServerError> {
let result: ProtobufResult<T> = Message::parse_from_bytes(&bytes);
match result {
Ok(data) => Ok(data),
@ -17,13 +17,19 @@ pub fn parse_from_bytes<T: Message>(bytes: &[u8]) -> Result<T, NetworkError> {
}
}
pub async fn poll_payload(mut payload: web::Payload) -> Result<web::BytesMut, NetworkError> {
pub async fn poll_payload(mut payload: web::Payload) -> Result<web::BytesMut, ServerError> {
let mut body = web::BytesMut::new();
while let Some(chunk) = payload.next().await {
let chunk = chunk.map_err(|e| NetworkError::InternalError(format!("{:?}", e)))?;
let chunk = chunk.map_err(|e| ServerError {
code: ServerCode::InternalError,
msg: format!("{:?}", e),
})?;
if (body.len() + chunk.len()) > MAX_PAYLOAD_SIZE {
let resp = FlowyResponse::from_msg("Payload overflow", ServerCode::PayloadOverflow);
return Err(NetworkError::BadRequest(resp));
return Err(ServerError {
code: ServerCode::PayloadOverflow,
msg: "Payload overflow".to_string(),
});
}
body.extend_from_slice(&chunk);
}

View File

@ -6,7 +6,7 @@ use crate::{
ws_service::WSServer,
};
use actix::Actor;
use actix_web::{dev::Server, middleware, web, App, HttpServer, Scope};
use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer, Scope};
use sqlx::PgPool;
use std::{net::TcpListener, sync::Arc};
@ -14,12 +14,12 @@ pub fn run(app_ctx: Arc<AppContext>, listener: TcpListener) -> Result<Server, st
let server = HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
.data(web::JsonConfig::default().limit(4096))
.app_data(web::JsonConfig::default().limit(4096))
.service(ws_scope())
.service(user_scope())
.data(app_ctx.ws_server.clone())
.data(app_ctx.db_pool.clone())
.data(app_ctx.auth.clone())
.app_data(Data::new(app_ctx.ws_server.clone()))
.app_data(Data::new(app_ctx.db_pool.clone()))
.app_data(Data::new(app_ctx.auth.clone()))
})
.listen(listener)?
.run();

View File

@ -1,4 +1,4 @@
use flowy_net::errors::NetworkError;
use flowy_net::response::{ServerCode, ServerError};
use flowy_user::{entities::SignUpResponse, protobuf::SignUpParams};
use sqlx::PgPool;
use std::sync::Arc;
@ -10,15 +10,13 @@ pub struct Auth {
impl Auth {
pub fn new(db_pool: Arc<PgPool>) -> Self { Self { db_pool } }
pub fn sign_up(&self, params: SignUpParams) -> Result<SignUpResponse, NetworkError> {
pub fn sign_up(&self, params: SignUpParams) -> Result<SignUpResponse, ServerError> {
// email exist?
// generate user id
//
unimplemented!()
}
pub fn is_email_exist(&self, email: &str) -> bool {}
pub fn is_email_exist(&self, email: &str) -> bool { true }
}

View File

@ -1,6 +1,6 @@
use crate::ws_service::ClientMessage;
use actix::{Message, Recipient};
use flowy_net::errors::NetworkError;
use flowy_net::response::ServerError;
use serde::{Deserialize, Serialize};
use std::fmt::Formatter;
@ -37,14 +37,14 @@ impl std::fmt::Display for SessionId {
}
#[derive(Debug, Message, Clone)]
#[rtype(result = "Result<(), NetworkError>")]
#[rtype(result = "Result<(), ServerError>")]
pub struct Connect {
pub socket: Socket,
pub sid: SessionId,
}
#[derive(Debug, Message, Clone)]
#[rtype(result = "Result<(), NetworkError>")]
#[rtype(result = "Result<(), ServerError>")]
pub struct Disconnect {
pub sid: SessionId,
}

View File

@ -4,7 +4,7 @@ use crate::ws_service::{
};
use actix::{Actor, Context, Handler};
use dashmap::DashMap;
use flowy_net::errors::NetworkError;
use flowy_net::response::ServerError;
pub struct WSServer {
sessions: DashMap<SessionId, Session>,
@ -26,7 +26,7 @@ impl Actor for WSServer {
}
impl Handler<Connect> for WSServer {
type Result = Result<(), NetworkError>;
type Result = Result<(), ServerError>;
fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result {
let session: Session = msg.into();
self.sessions.insert(session.id.clone(), session);
@ -36,7 +36,7 @@ impl Handler<Connect> for WSServer {
}
impl Handler<Disconnect> for WSServer {
type Result = Result<(), NetworkError>;
type Result = Result<(), ServerError>;
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) -> Self::Result {
self.sessions.remove(&msg.sid);
Ok(())

View File

@ -7,11 +7,11 @@ edition = "2018"
[lib]
name = "dart_ffi"
# this value will change depending on the target os
# for iOS it would be `rlib`
# for Macos it would be `rlib`
# for iOS it would be `cdylib`
# for Macos it would be `cdylib`
# for android it would be `c-dylib`
# default rlib
crate-type = ["rlib"]
# default cdylib
crate-type = ["cdylib"]
[dependencies]

View File

@ -64,6 +64,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "EditorEvent"
| "DocErrorCode"
| "FFIStatusCode"
| "UserServerError"
| "UserStatus"
| "UserEvent"
| "UserErrCode"

View File

@ -0,0 +1,46 @@
use std::{fmt::Debug, marker::PhantomData};
pub trait Build<C> {
fn build(code: C, msg: String) -> Self;
}
pub struct Builder<C, O> {
pub code: C,
pub msg: Option<String>,
phantom: PhantomData<O>,
}
impl<C, O> Builder<C, O>
where
C: Debug,
O: Build<C> + Build<C>,
{
pub fn new(code: C) -> Self {
Builder {
code,
msg: None,
phantom: PhantomData,
}
}
pub fn msg<M>(mut self, msg: M) -> Self
where
M: Into<String>,
{
self.msg = Some(msg.into());
self
}
pub fn error<Err>(mut self, err: Err) -> Self
where
Err: std::fmt::Debug,
{
self.msg = Some(format!("{:?}", err));
self
}
pub fn build(mut self) -> O {
let msg = self.msg.take().unwrap_or("".to_owned());
O::build(self.code, msg)
}
}

View File

@ -0,0 +1,3 @@
pub mod builder;
pub use builder::*;

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
reqwest = "0.11"
hyper = "0.14"
protobuf = {version = "2.18.0"}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
@ -17,8 +18,10 @@ log = "0.4"
bytes = "1.0"
lazy_static = "1.4.0"
tokio = { version = "1", features = ["full"] }
actix-web = {version = "4.0.0-beta.8", optional = true}
derive_more = {version = "0.99", features = ["display"]}
flowy-derive = { path = "../flowy-derive" }
[features]
http = ["actix-web"]

View File

@ -1,40 +0,0 @@
use crate::response::FlowyResponse;
use protobuf::ProtobufError;
use std::fmt::{Formatter, Write};
#[derive(Debug)]
pub enum NetworkError {
InternalError(String),
ProtobufError(ProtobufError),
BadRequest(FlowyResponse<String>),
Unauthorized,
}
impl std::fmt::Display for NetworkError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
NetworkError::InternalError(_) => f.write_str("Internal Server Error"),
NetworkError::ProtobufError(err) => f.write_str(&format!("protobuf error: {}", err)),
NetworkError::BadRequest(request) => {
let msg = format!("Bad Request: {:?}", request);
f.write_str(&msg)
},
NetworkError::Unauthorized => f.write_str("Unauthorized"),
}
}
}
impl std::convert::From<ProtobufError> for NetworkError {
fn from(err: ProtobufError) -> Self { NetworkError::ProtobufError(err) }
}
impl std::convert::From<reqwest::Error> for NetworkError {
fn from(error: reqwest::Error) -> Self {
let msg = format!("{:?}", error);
NetworkError::InternalError(msg)
}
}
impl std::convert::From<String> for NetworkError {
fn from(error: String) -> Self { NetworkError::InternalError(error) }
}

View File

@ -0,0 +1,45 @@
use crate::response::FlowyResponse;
use protobuf::ProtobufError;
use std::fmt::{Formatter, Write};
// #[derive(Debug)]
// pub struct ServerError {
// code: ErrorCode
// }
//
// pub enum ErrorCode {
// InternalError(String),
// ProtobufError(ProtobufError),
// BadRequest(FlowyResponse<String>),
// Unauthorized,
// }
//
//
// impl std::fmt::Display for ErrorCode {
// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// match self {
// ErrorCode::InternalError(_) => f.write_str("Internal Server
// Error"), ErrorCode::ProtobufError(err) =>
// f.write_str(&format!("protobuf error: {}", err)),
// ErrorCode::BadRequest(request) => { let msg = format!("Bad
// Request: {:?}", request); f.write_str(&msg)
// },
// ErrorCode::Unauthorized => f.write_str("Unauthorized"),
// }
// }
// }
// impl std::convert::From<ProtobufError> for ServerCode {
// fn from(err: ProtobufError) -> Self { ServerCode::ProtobufError(err) }
// }
//
// impl std::convert::From<reqwest::Error> for ServerError {
// fn from(error: reqwest::Error) -> Self {
// let msg = format!("{:?}", error);
// ServerError::InternalError(msg)
// }
// }
//
// impl std::convert::From<String> for ServerError {
// fn from(error: String) -> Self { ServerError::InternalError(error) }
// }

View File

@ -0,0 +1,3 @@
mod errors;
pub use errors::*;

View File

@ -1,4 +1,4 @@
use crate::{errors::NetworkError, future::ResultFuture};
use crate::{future::ResultFuture, response::ServerError};
use bytes::Bytes;
use protobuf::{Message, ProtobufError};
use reqwest::{Client, Error, Response};
@ -6,7 +6,9 @@ use std::{
convert::{TryFrom, TryInto},
time::Duration,
};
use hyper::{StatusCode, http};
use tokio::sync::{oneshot, oneshot::error::RecvError};
use crate::response::ServerCode;
// pub async fn http_post<T1, T2>(url: &str, data: T1) -> ResultFuture<T2,
// NetworkError> where
@ -17,7 +19,7 @@ use tokio::sync::{oneshot, oneshot::error::RecvError};
// ResultFuture::new(async move { post(url, data).await })
// }
pub async fn http_post<T1, T2>(url: &str, data: T1) -> Result<T2, NetworkError>
pub async fn http_post<T1, T2>(url: &str, data: T1) -> Result<T2, ServerError>
where
T1: TryInto<Bytes, Error = ProtobufError>,
T2: TryFrom<Bytes, Error = ProtobufError>,
@ -32,20 +34,21 @@ where
tx.send(response);
});
match rx.await {
Ok(response) => {
let response = response?;
let response_bytes = response.bytes().await?;
let data = T2::try_from(response_bytes)?;
Ok(data)
},
Err(e) => {
unimplemented!()
},
let response = rx.await??;
if response.status() == http::StatusCode::OK {
let response_bytes = response.bytes().await?;
let data = T2::try_from(response_bytes)?;
Ok(data)
} else {
Err(ServerError {
code: ServerCode::InternalError,
msg: format!("{:?}", response),
})
}
}
async fn parse_response<T>(response: Response) -> Result<T, NetworkError>
async fn parse_response<T>(response: Response) -> Result<T, ServerError>
where
T: Message,
{
@ -53,7 +56,7 @@ where
parse_bytes(bytes)
}
fn parse_bytes<T>(bytes: Bytes) -> Result<T, NetworkError>
fn parse_bytes<T>(bytes: Bytes) -> Result<T, ServerError>
where
T: Message,
{

View File

@ -1,8 +1,32 @@
use serde::Serialize;
use serde::{Serialize, __private::Formatter};
use serde_repr::*;
use std::{error::Error, fmt};
use tokio::sync::oneshot::error::RecvError;
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[derive(Debug)]
pub struct ServerError {
pub code: ServerCode,
pub msg: String,
}
impl std::fmt::Display for ServerError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let msg = format!("{:?}:{}", self.code, self.msg);
f.write_str(&msg)
}
}
impl std::convert::From<&ServerError> for FlowyResponse<String> {
fn from(error: &ServerError) -> Self {
FlowyResponse {
msg: error.msg.clone(),
data: None,
code: error.code.clone(),
}
}
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone)]
#[repr(u16)]
pub enum ServerCode {
Success = 0,
@ -12,6 +36,11 @@ pub enum ServerCode {
PayloadOverflow = 4,
PayloadSerdeFail = 5,
ProtobufError = 6,
SerdeError = 7,
ConnectRefused = 8,
ConnectTimeout = 9,
ConnectClose = 10,
ConnectCancel = 11,
}
#[derive(Debug, Serialize)]
@ -42,3 +71,69 @@ impl FlowyResponse<String> {
Self::new(Some("".to_owned()), msg, code)
}
}
impl std::convert::From<protobuf::ProtobufError> for ServerError {
fn from(err: protobuf::ProtobufError) -> Self {
ServerError {
code: ServerCode::ProtobufError,
msg: format!("{}", err),
}
}
}
impl std::convert::From<RecvError> for ServerError {
fn from(error: RecvError) -> Self {
ServerError {
code: ServerCode::InternalError,
msg: format!("{:?}", error),
}
}
}
impl std::convert::From<reqwest::Error> for ServerError {
fn from(error: reqwest::Error) -> Self {
if error.is_timeout() {
return ServerError {
code: ServerCode::ConnectTimeout,
msg: format!("{}", error),
};
}
if error.is_request() {
let hyper_error: Option<&hyper::Error> = error.source().unwrap().downcast_ref();
return match hyper_error {
None => ServerError {
code: ServerCode::ConnectRefused,
msg: format!("{:?}", error),
},
Some(hyper_error) => {
let mut code = ServerCode::InternalError;
let msg = format!("{}", error);
if hyper_error.is_closed() {
code = ServerCode::ConnectClose;
}
if hyper_error.is_connect() {
code = ServerCode::ConnectRefused;
}
if hyper_error.is_canceled() {
code = ServerCode::ConnectCancel;
}
if hyper_error.is_timeout() {
}
ServerError { code, msg }
},
};
}
let msg = format!("{:?}", error);
ServerError {
code: ServerCode::ProtobufError,
msg,
}
}
}

View File

@ -1,28 +1,15 @@
use crate::{errors::NetworkError, response::*};
use crate::response::*;
use actix_web::{body::Body, error::ResponseError, BaseHttpResponse, HttpResponse};
use serde::Serialize;
impl NetworkError {
impl ServerError {
fn http_response(&self) -> HttpResponse {
match self {
NetworkError::InternalError(msg) => {
let resp = FlowyResponse::from_msg(&msg, ServerCode::InternalError);
HttpResponse::InternalServerError().json(resp)
},
NetworkError::ProtobufError(err) => {
let resp = FlowyResponse::from_msg(&format!("{}", err), ServerCode::ProtobufError);
HttpResponse::InternalServerError().json(resp)
},
NetworkError::BadRequest(ref resp) => HttpResponse::BadRequest().json(resp),
NetworkError::Unauthorized => {
let resp = FlowyResponse::from_msg("Unauthorized", ServerCode::Unauthorized);
HttpResponse::Unauthorized().json(resp)
},
}
let resp: FlowyResponse<String> = self.into();
HttpResponse::Ok().json(resp)
}
}
impl ResponseError for NetworkError {
impl ResponseError for ServerError {
fn error_response(&self) -> HttpResponse { self.http_response().into() }
}
@ -32,7 +19,11 @@ impl<T: Serialize> std::convert::Into<HttpResponse> for FlowyResponse<T> {
Ok(body) => HttpResponse::Ok().body(Body::from(body)),
Err(e) => {
let msg = format!("Serial error: {:?}", e);
NetworkError::InternalError(msg).error_response()
ServerError {
code: ServerCode::SerdeError,
msg,
}
.error_response()
},
}
}

View File

@ -1,18 +1,19 @@
use crate::errors::UserErrCode;
use validator::validate_email;
#[derive(Debug)]
pub struct UserEmail(pub String);
impl UserEmail {
pub fn parse(s: String) -> Result<UserEmail, String> {
pub fn parse(s: String) -> Result<UserEmail, UserErrCode> {
if s.trim().is_empty() {
return Err(format!("Email can not be empty or whitespace"));
return Err(UserErrCode::EmailIsEmpty);
}
if validate_email(&s) {
Ok(Self(s))
} else {
Err(format!("{} is not a valid email.", s))
Err(UserErrCode::EmailFormatInvalid)
}
}
}

View File

@ -1,11 +1,15 @@
use crate::errors::UserErrCode;
use unicode_segmentation::UnicodeSegmentation;
#[derive(Debug)]
pub struct UserName(pub String);
impl UserName {
pub fn parse(s: String) -> Result<UserName, String> {
pub fn parse(s: String) -> Result<UserName, UserErrCode> {
let is_empty_or_whitespace = s.trim().is_empty();
if is_empty_or_whitespace {
return Err(UserErrCode::UserNameIsEmpty);
}
// A grapheme is defined by the Unicode standard as a "user-perceived"
// character: `å` is a single grapheme, but it is composed of two characters
// (`a` and `̊`).
@ -14,15 +18,18 @@ impl UserName {
// `true` specifies that we want to use the extended grapheme definition set,
// the recommended one.
let is_too_long = s.graphemes(true).count() > 256;
if is_too_long {
return Err(UserErrCode::UserNameTooLong);
}
let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
if is_empty_or_whitespace || is_too_long || contains_forbidden_characters {
Err(format!("{} is not a valid name.", s))
} else {
Ok(Self(s))
if contains_forbidden_characters {
return Err(UserErrCode::UserNameContainsForbiddenCharacters);
}
Ok(Self(s))
}
}

View File

@ -1,27 +1,29 @@
use crate::errors::UserErrCode;
use fancy_regex::Regex;
use lazy_static::lazy_static;
use unicode_segmentation::UnicodeSegmentation;
#[derive(Debug)]
pub struct UserPassword(pub String);
impl UserPassword {
pub fn parse(s: String) -> Result<UserPassword, String> {
pub fn parse(s: String) -> Result<UserPassword, UserErrCode> {
if s.trim().is_empty() {
return Err(format!("Password can not be empty or whitespace."));
return Err(UserErrCode::PasswordIsEmpty);
}
if s.graphemes(true).count() > 100 {
return Err(format!("Password too long."));
return Err(UserErrCode::PasswordTooLong);
}
let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
if contains_forbidden_characters {
return Err(format!("Password contains forbidden characters."));
return Err(UserErrCode::PasswordContainsForbidCharacters);
}
if !validate_password(&s) {
return Err(format!("Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric"));
return Err(UserErrCode::PasswordFormatInvalid);
}
Ok(Self(s))

View File

@ -36,13 +36,9 @@ impl TryInto<SignInParams> for SignInRequest {
type Error = UserError;
fn try_into(self) -> Result<SignInParams, Self::Error> {
let email = UserEmail::parse(self.email)
.map_err(|e| ErrorBuilder::new(UserErrCode::EmailInvalid).msg(e).build())?;
let password = UserPassword::parse(self.password).map_err(|e| {
ErrorBuilder::new(UserErrCode::PasswordInvalid)
.msg(e)
.build()
})?;
let email = UserEmail::parse(self.email).map_err(|e| ErrorBuilder::new(e).build())?;
let password =
UserPassword::parse(self.password).map_err(|e| ErrorBuilder::new(e).build())?;
Ok(SignInParams {
email: email.0,

View File

@ -20,19 +20,10 @@ impl TryInto<SignUpParams> for SignUpRequest {
type Error = UserError;
fn try_into(self) -> Result<SignUpParams, Self::Error> {
let email = UserEmail::parse(self.email)
.map_err(|e| ErrorBuilder::new(UserErrCode::EmailInvalid).msg(e).build())?;
let password = UserPassword::parse(self.password).map_err(|e| {
ErrorBuilder::new(UserErrCode::PasswordInvalid)
.msg(e)
.build()
})?;
let name = UserName::parse(self.name).map_err(|e| {
ErrorBuilder::new(UserErrCode::UserNameInvalid)
.msg(e)
.build()
})?;
let email = UserEmail::parse(self.email).map_err(|e| ErrorBuilder::new(e).build())?;
let password =
UserPassword::parse(self.password).map_err(|e| ErrorBuilder::new(e).build())?;
let name = UserName::parse(self.name).map_err(|e| ErrorBuilder::new(e).build())?;
Ok(SignUpParams {
email: email.0,

View File

@ -72,11 +72,7 @@ impl TryInto<UpdateUserParams> for UpdateUserRequest {
None => None,
Some(name) => Some(
UserName::parse(name)
.map_err(|e| {
ErrorBuilder::new(UserErrCode::UserNameInvalid)
.msg(e)
.build()
})?
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
};
@ -85,7 +81,7 @@ impl TryInto<UpdateUserParams> for UpdateUserRequest {
None => None,
Some(email) => Some(
UserEmail::parse(email)
.map_err(|e| ErrorBuilder::new(UserErrCode::EmailInvalid).msg(e).build())?
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
};
@ -107,11 +103,7 @@ impl TryInto<UpdateUserParams> for UpdateUserRequest {
None => None,
Some(password) => Some(
UserPassword::parse(password)
.map_err(|e| {
ErrorBuilder::new(UserErrCode::PasswordInvalid)
.msg(e)
.build()
})?
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
};

View File

@ -47,21 +47,37 @@ pub enum UserErrCode {
#[display(fmt = "Get current id write lock failed")]
WriteCurrentIdFailed = 12,
#[display(fmt = "Email format is not correct")]
EmailInvalid = 20,
#[display(fmt = "Password format is not correct")]
PasswordInvalid = 21,
#[display(fmt = "User name is invalid")]
UserNameInvalid = 22,
#[display(fmt = "Email can not be empty or whitespace")]
EmailIsEmpty = 20,
#[display(fmt = "Email format is not valid")]
EmailFormatInvalid = 21,
#[display(fmt = "Email already exists")]
EmailAlreadyExists = 22,
#[display(fmt = "Password can not be empty or whitespace")]
PasswordIsEmpty = 30,
#[display(fmt = "Password format too long")]
PasswordTooLong = 31,
#[display(fmt = "Password contains forbidden characters.")]
PasswordContainsForbidCharacters = 32,
#[display(
fmt = "Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric"
)]
PasswordFormatInvalid = 33,
#[display(fmt = "User name is too long")]
UserNameTooLong = 40,
#[display(fmt = "User name contain forbidden characters")]
UserNameContainsForbiddenCharacters = 41,
#[display(fmt = "User name can not be empty or whitespace")]
UserNameIsEmpty = 42,
#[display(fmt = "User workspace is invalid")]
UserWorkspaceInvalid = 23,
UserWorkspaceInvalid = 50,
#[display(fmt = "User id is invalid")]
UserIdInvalid = 24,
UserIdInvalid = 51,
#[display(fmt = "Create user default workspace failed")]
CreateDefaultWorkspaceFailed = 25,
CreateDefaultWorkspaceFailed = 52,
#[display(fmt = "User default workspace already exists")]
DefaultWorkspaceAlreadyExist = 26,
DefaultWorkspaceAlreadyExist = 53,
#[display(fmt = "Network error")]
NetworkError = 100,
@ -116,8 +132,8 @@ impl std::convert::From<flowy_sqlite::Error> for UserError {
}
}
impl std::convert::From<flowy_net::errors::NetworkError> for UserError {
fn from(error: flowy_net::errors::NetworkError) -> Self {
impl std::convert::From<flowy_net::response::ServerError> for UserError {
fn from(error: flowy_net::response::ServerError) -> Self {
ErrorBuilder::new(UserErrCode::NetworkError)
.error(error)
.build()
@ -134,5 +150,12 @@ impl flowy_dispatch::Error for UserError {
pub type ErrorBuilder = flowy_infra::errors::Builder<UserErrCode, UserError>;
impl flowy_infra::errors::Build<UserErrCode> for UserError {
fn build(code: UserErrCode, msg: String) -> Self { UserError::new(code, &msg) }
fn build(code: UserErrCode, msg: String) -> Self {
let msg = if msg.is_empty() {
format!("{}", code)
} else {
msg
};
UserError::new(code, &msg)
}
}

View File

@ -225,13 +225,20 @@ pub enum UserErrCode {
UserNotLoginYet = 10,
ReadCurrentIdFailed = 11,
WriteCurrentIdFailed = 12,
EmailInvalid = 20,
PasswordInvalid = 21,
UserNameInvalid = 22,
UserWorkspaceInvalid = 23,
UserIdInvalid = 24,
CreateDefaultWorkspaceFailed = 25,
DefaultWorkspaceAlreadyExist = 26,
EmailIsEmpty = 20,
EmailFormatInvalid = 21,
EmailAlreadyExists = 22,
PasswordIsEmpty = 30,
PasswordTooLong = 31,
PasswordContainsForbidCharacters = 32,
PasswordFormatInvalid = 33,
UserNameTooLong = 40,
UserNameContainsForbiddenCharacters = 41,
UserNameIsEmpty = 42,
UserWorkspaceInvalid = 50,
UserIdInvalid = 51,
CreateDefaultWorkspaceFailed = 52,
DefaultWorkspaceAlreadyExist = 53,
NetworkError = 100,
}
@ -252,13 +259,20 @@ impl ::protobuf::ProtobufEnum for UserErrCode {
10 => ::std::option::Option::Some(UserErrCode::UserNotLoginYet),
11 => ::std::option::Option::Some(UserErrCode::ReadCurrentIdFailed),
12 => ::std::option::Option::Some(UserErrCode::WriteCurrentIdFailed),
20 => ::std::option::Option::Some(UserErrCode::EmailInvalid),
21 => ::std::option::Option::Some(UserErrCode::PasswordInvalid),
22 => ::std::option::Option::Some(UserErrCode::UserNameInvalid),
23 => ::std::option::Option::Some(UserErrCode::UserWorkspaceInvalid),
24 => ::std::option::Option::Some(UserErrCode::UserIdInvalid),
25 => ::std::option::Option::Some(UserErrCode::CreateDefaultWorkspaceFailed),
26 => ::std::option::Option::Some(UserErrCode::DefaultWorkspaceAlreadyExist),
20 => ::std::option::Option::Some(UserErrCode::EmailIsEmpty),
21 => ::std::option::Option::Some(UserErrCode::EmailFormatInvalid),
22 => ::std::option::Option::Some(UserErrCode::EmailAlreadyExists),
30 => ::std::option::Option::Some(UserErrCode::PasswordIsEmpty),
31 => ::std::option::Option::Some(UserErrCode::PasswordTooLong),
32 => ::std::option::Option::Some(UserErrCode::PasswordContainsForbidCharacters),
33 => ::std::option::Option::Some(UserErrCode::PasswordFormatInvalid),
40 => ::std::option::Option::Some(UserErrCode::UserNameTooLong),
41 => ::std::option::Option::Some(UserErrCode::UserNameContainsForbiddenCharacters),
42 => ::std::option::Option::Some(UserErrCode::UserNameIsEmpty),
50 => ::std::option::Option::Some(UserErrCode::UserWorkspaceInvalid),
51 => ::std::option::Option::Some(UserErrCode::UserIdInvalid),
52 => ::std::option::Option::Some(UserErrCode::CreateDefaultWorkspaceFailed),
53 => ::std::option::Option::Some(UserErrCode::DefaultWorkspaceAlreadyExist),
100 => ::std::option::Option::Some(UserErrCode::NetworkError),
_ => ::std::option::Option::None
}
@ -276,9 +290,16 @@ impl ::protobuf::ProtobufEnum for UserErrCode {
UserErrCode::UserNotLoginYet,
UserErrCode::ReadCurrentIdFailed,
UserErrCode::WriteCurrentIdFailed,
UserErrCode::EmailInvalid,
UserErrCode::PasswordInvalid,
UserErrCode::UserNameInvalid,
UserErrCode::EmailIsEmpty,
UserErrCode::EmailFormatInvalid,
UserErrCode::EmailAlreadyExists,
UserErrCode::PasswordIsEmpty,
UserErrCode::PasswordTooLong,
UserErrCode::PasswordContainsForbidCharacters,
UserErrCode::PasswordFormatInvalid,
UserErrCode::UserNameTooLong,
UserErrCode::UserNameContainsForbiddenCharacters,
UserErrCode::UserNameIsEmpty,
UserErrCode::UserWorkspaceInvalid,
UserErrCode::UserIdInvalid,
UserErrCode::CreateDefaultWorkspaceFailed,
@ -314,62 +335,80 @@ impl ::protobuf::reflect::ProtobufValue for UserErrCode {
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0cerrors.proto\"?\n\tUserError\x12\x20\n\x04code\x18\x01\x20\x01(\
\x0e2\x0c.UserErrCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03m\
sg*\xc8\x03\n\x0bUserErrCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16Use\
sg*\x8c\x05\n\x0bUserErrCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16Use\
rDatabaseInitFailed\x10\x01\x12\x1b\n\x17UserDatabaseWriteLocked\x10\x02\
\x12\x1a\n\x16UserDatabaseReadLocked\x10\x03\x12\x1b\n\x17UserDatabaseDi\
dNotMatch\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\
\n\x10SqlInternalError\x10\x06\x12\x13\n\x0fUserNotLoginYet\x10\n\x12\
\x17\n\x13ReadCurrentIdFailed\x10\x0b\x12\x18\n\x14WriteCurrentIdFailed\
\x10\x0c\x12\x10\n\x0cEmailInvalid\x10\x14\x12\x13\n\x0fPasswordInvalid\
\x10\x15\x12\x13\n\x0fUserNameInvalid\x10\x16\x12\x18\n\x14UserWorkspace\
Invalid\x10\x17\x12\x11\n\rUserIdInvalid\x10\x18\x12\x20\n\x1cCreateDefa\
ultWorkspaceFailed\x10\x19\x12\x20\n\x1cDefaultWorkspaceAlreadyExist\x10\
\x1a\x12\x10\n\x0cNetworkError\x10dJ\x92\x07\n\x06\x12\x04\0\0\x19\x01\n\
\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\
\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
\x04\x19\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0f\n\x0c\n\x05\x04\
\0\x02\0\x01\x12\x03\x03\x10\x14\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
\x17\x18\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\n\x0c\n\x05\x04\0\
\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\
\x0b\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\x12\n\n\n\x02\x05\
\0\x12\x04\x06\0\x19\x01\n\n\n\x03\x05\0\x01\x12\x03\x06\x05\x10\n\x0b\n\
\x04\x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\
\x07\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\
\x05\0\x02\x01\x12\x03\x08\x04\x1f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\
\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x08\x1d\x1e\n\x0b\n\
\x04\x05\0\x02\x02\x12\x03\t\x04\x20\n\x0c\n\x05\x05\0\x02\x02\x01\x12\
\x03\t\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x1e\x1f\n\x0b\n\
\x04\x05\0\x02\x03\x12\x03\n\x04\x1f\n\x0c\n\x05\x05\0\x02\x03\x01\x12\
\x03\n\x04\x1a\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1d\x1e\n\x0b\n\
\x04\x05\0\x02\x04\x12\x03\x0b\x04\x20\n\x0c\n\x05\x05\0\x02\x04\x01\x12\
\x03\x0b\x04\x1b\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x0b\x1e\x1f\n\x0b\
\n\x04\x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\x05\x05\0\x02\x05\x01\x12\
\x03\x0c\x04\x1d\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x0c\x20!\n\x0b\n\
\x04\x05\0\x02\x06\x12\x03\r\x04\x19\n\x0c\n\x05\x05\0\x02\x06\x01\x12\
\x03\r\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\r\x17\x18\n\x0b\n\
\x04\x05\0\x02\x07\x12\x03\x0e\x04\x19\n\x0c\n\x05\x05\0\x02\x07\x01\x12\
\x03\x0e\x04\x13\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\x0e\x16\x18\n\x0b\
\n\x04\x05\0\x02\x08\x12\x03\x0f\x04\x1d\n\x0c\n\x05\x05\0\x02\x08\x01\
\x12\x03\x0f\x04\x17\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0f\x1a\x1c\n\
\x0b\n\x04\x05\0\x02\t\x12\x03\x10\x04\x1e\n\x0c\n\x05\x05\0\x02\t\x01\
\x12\x03\x10\x04\x18\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x10\x1b\x1d\n\
\x0b\n\x04\x05\0\x02\n\x12\x03\x11\x04\x16\n\x0c\n\x05\x05\0\x02\n\x01\
\x12\x03\x11\x04\x10\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\x11\x13\x15\n\
\x0b\n\x04\x05\0\x02\x0b\x12\x03\x12\x04\x19\n\x0c\n\x05\x05\0\x02\x0b\
\x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x12\x16\
\x18\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x13\x04\x19\n\x0c\n\x05\x05\0\x02\
\x0c\x01\x12\x03\x13\x04\x13\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x13\
\x16\x18\n\x0b\n\x04\x05\0\x02\r\x12\x03\x14\x04\x1e\n\x0c\n\x05\x05\0\
\x02\r\x01\x12\x03\x14\x04\x18\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x14\
\x1b\x1d\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x15\x04\x17\n\x0c\n\x05\x05\0\
\x02\x0e\x01\x12\x03\x15\x04\x11\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\
\x15\x14\x16\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x16\x04&\n\x0c\n\x05\x05\
\0\x02\x0f\x01\x12\x03\x16\x04\x20\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\
\x16#%\n\x0b\n\x04\x05\0\x02\x10\x12\x03\x17\x04&\n\x0c\n\x05\x05\0\x02\
\x10\x01\x12\x03\x17\x04\x20\n\x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x17#%\
\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x18\x04\x17\n\x0c\n\x05\x05\0\x02\x11\
\x01\x12\x03\x18\x04\x10\n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x18\x13\
\x16b\x06proto3\
\x10\x0c\x12\x10\n\x0cEmailIsEmpty\x10\x14\x12\x16\n\x12EmailFormatInval\
id\x10\x15\x12\x16\n\x12EmailAlreadyExists\x10\x16\x12\x13\n\x0fPassword\
IsEmpty\x10\x1e\x12\x13\n\x0fPasswordTooLong\x10\x1f\x12$\n\x20PasswordC\
ontainsForbidCharacters\x10\x20\x12\x19\n\x15PasswordFormatInvalid\x10!\
\x12\x13\n\x0fUserNameTooLong\x10(\x12'\n#UserNameContainsForbiddenChara\
cters\x10)\x12\x13\n\x0fUserNameIsEmpty\x10*\x12\x18\n\x14UserWorkspaceI\
nvalid\x102\x12\x11\n\rUserIdInvalid\x103\x12\x20\n\x1cCreateDefaultWork\
spaceFailed\x104\x12\x20\n\x1cDefaultWorkspaceAlreadyExist\x105\x12\x10\
\n\x0cNetworkError\x10dJ\xb1\t\n\x06\x12\x04\0\0\x20\x01\n\x08\n\x01\x0c\
\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\
\x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x19\n\
\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0f\n\x0c\n\x05\x04\0\x02\0\
\x01\x12\x03\x03\x10\x14\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x17\x18\
\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\
\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0e\
\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\x12\n\n\n\x02\x05\0\x12\
\x04\x06\0\x20\x01\n\n\n\x03\x05\0\x01\x12\x03\x06\x05\x10\n\x0b\n\x04\
\x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x07\
\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\x05\
\0\x02\x01\x12\x03\x08\x04\x1f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x08\
\x04\x1a\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x08\x1d\x1e\n\x0b\n\x04\
\x05\0\x02\x02\x12\x03\t\x04\x20\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\
\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x1e\x1f\n\x0b\n\x04\x05\
\0\x02\x03\x12\x03\n\x04\x1f\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\
\x1a\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1d\x1e\n\x0b\n\x04\x05\0\
\x02\x04\x12\x03\x0b\x04\x20\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x0b\
\x04\x1b\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x0b\x1e\x1f\n\x0b\n\x04\
\x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\
\x0c\x04\x1d\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x0c\x20!\n\x0b\n\x04\
\x05\0\x02\x06\x12\x03\r\x04\x19\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\r\
\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\r\x17\x18\n\x0b\n\x04\x05\
\0\x02\x07\x12\x03\x0e\x04\x19\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\x0e\
\x04\x13\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\x0e\x16\x18\n\x0b\n\x04\
\x05\0\x02\x08\x12\x03\x0f\x04\x1d\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\
\x0f\x04\x17\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0f\x1a\x1c\n\x0b\n\
\x04\x05\0\x02\t\x12\x03\x10\x04\x1e\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\
\x10\x04\x18\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x10\x1b\x1d\n\x0b\n\x04\
\x05\0\x02\n\x12\x03\x11\x04\x16\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\x11\
\x04\x10\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\x11\x13\x15\n\x0b\n\x04\x05\
\0\x02\x0b\x12\x03\x12\x04\x1c\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x12\
\x04\x16\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x12\x19\x1b\n\x0b\n\x04\
\x05\0\x02\x0c\x12\x03\x13\x04\x1c\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\
\x13\x04\x16\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x13\x19\x1b\n\x0b\n\
\x04\x05\0\x02\r\x12\x03\x14\x04\x19\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\
\x14\x04\x13\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x14\x16\x18\n\x0b\n\x04\
\x05\0\x02\x0e\x12\x03\x15\x04\x19\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\
\x15\x04\x13\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\x15\x16\x18\n\x0b\n\
\x04\x05\0\x02\x0f\x12\x03\x16\x04*\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\
\x03\x16\x04$\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\x16')\n\x0b\n\x04\
\x05\0\x02\x10\x12\x03\x17\x04\x1f\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\
\x17\x04\x19\n\x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x17\x1c\x1e\n\x0b\n\
\x04\x05\0\x02\x11\x12\x03\x18\x04\x19\n\x0c\n\x05\x05\0\x02\x11\x01\x12\
\x03\x18\x04\x13\n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x18\x16\x18\n\x0b\
\n\x04\x05\0\x02\x12\x12\x03\x19\x04-\n\x0c\n\x05\x05\0\x02\x12\x01\x12\
\x03\x19\x04'\n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x19*,\n\x0b\n\x04\
\x05\0\x02\x13\x12\x03\x1a\x04\x19\n\x0c\n\x05\x05\0\x02\x13\x01\x12\x03\
\x1a\x04\x13\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x1a\x16\x18\n\x0b\n\
\x04\x05\0\x02\x14\x12\x03\x1b\x04\x1e\n\x0c\n\x05\x05\0\x02\x14\x01\x12\
\x03\x1b\x04\x18\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\x1b\x1b\x1d\n\x0b\
\n\x04\x05\0\x02\x15\x12\x03\x1c\x04\x17\n\x0c\n\x05\x05\0\x02\x15\x01\
\x12\x03\x1c\x04\x11\n\x0c\n\x05\x05\0\x02\x15\x02\x12\x03\x1c\x14\x16\n\
\x0b\n\x04\x05\0\x02\x16\x12\x03\x1d\x04&\n\x0c\n\x05\x05\0\x02\x16\x01\
\x12\x03\x1d\x04\x20\n\x0c\n\x05\x05\0\x02\x16\x02\x12\x03\x1d#%\n\x0b\n\
\x04\x05\0\x02\x17\x12\x03\x1e\x04&\n\x0c\n\x05\x05\0\x02\x17\x01\x12\
\x03\x1e\x04\x20\n\x0c\n\x05\x05\0\x02\x17\x02\x12\x03\x1e#%\n\x0b\n\x04\
\x05\0\x02\x18\x12\x03\x1f\x04\x17\n\x0c\n\x05\x05\0\x02\x18\x01\x12\x03\
\x1f\x04\x10\n\x0c\n\x05\x05\0\x02\x18\x02\x12\x03\x1f\x13\x16b\x06proto\
3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -15,12 +15,19 @@ enum UserErrCode {
UserNotLoginYet = 10;
ReadCurrentIdFailed = 11;
WriteCurrentIdFailed = 12;
EmailInvalid = 20;
PasswordInvalid = 21;
UserNameInvalid = 22;
UserWorkspaceInvalid = 23;
UserIdInvalid = 24;
CreateDefaultWorkspaceFailed = 25;
DefaultWorkspaceAlreadyExist = 26;
EmailIsEmpty = 20;
EmailFormatInvalid = 21;
EmailAlreadyExists = 22;
PasswordIsEmpty = 30;
PasswordTooLong = 31;
PasswordContainsForbidCharacters = 32;
PasswordFormatInvalid = 33;
UserNameTooLong = 40;
UserNameContainsForbiddenCharacters = 41;
UserNameIsEmpty = 42;
UserWorkspaceInvalid = 50;
UserIdInvalid = 51;
CreateDefaultWorkspaceFailed = 52;
DefaultWorkspaceAlreadyExist = 53;
NetworkError = 100;
}

View File

@ -0,0 +1 @@
mod user_test;

View File

@ -0,0 +1,13 @@
use flowy_user::prelude::*;
#[tokio::test]
async fn user_register_test() {
let server = UserServerImpl {};
let params = SignUpParams {
email: "annie@appflowy.io".to_string(),
name: "annie".to_string(),
password: "123".to_string(),
};
let result = server.sign_up(params).await.unwrap();
}