mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
save user info to pg && response to client with protobuf data
This commit is contained in:
parent
3f65d3eb48
commit
66c4daab7a
22
.run/ProtoBuf_Gen.run.xml
Normal file
22
.run/ProtoBuf_Gen.run.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="ProtoBuf_Gen" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --manifest-path $PROJECT_DIR$/scripts/flowy-tool/Cargo.toml -- pb-gen --rust_source=$PROJECT_DIR$/rust-lib/ --derive_meta=$PROJECT_DIR$/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs --flutter_package_lib=$PROJECT_DIR$/app_flowy/packages/flowy_sdk/lib" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="rust_source" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/" />
|
||||
<env name="build_cache" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/flowy-derive/src/auto_gen_file/category_from_str.rs" />
|
||||
<env name="proto_file_output" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/flowy-protobuf/define" />
|
||||
<env name="rust_mod_dir" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/flowy-protobuf/src/" />
|
||||
<env name="flutter_mod_dir" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/flutter-lib/packages/flowy_protobuf/lib/" />
|
||||
</envs>
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
18
.run/Run backend.run.xml
Normal file
18
.run/Run backend.run.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run backend" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --package backend --bin backend" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$/backend" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="APP_ENVIRONMENT" value="production" />
|
||||
</envs>
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
16
.run/dart-event.run.xml
Normal file
16
.run/dart-event.run.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="dart-event" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --manifest-path $PROJECT_DIR$/scripts/flowy-tool/Cargo.toml -- dart-event --rust_source=$PROJECT_DIR$/rust-lib/ --output=$PROJECT_DIR$/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
@ -7,4 +7,5 @@ tests/
|
||||
Dockerfile
|
||||
scripts/
|
||||
migrations/
|
||||
app_flowy/
|
||||
app_flowy/
|
||||
rust-lib/target/
|
@ -1,15 +1,58 @@
|
||||
# We use the latest Rust stable release as base image
|
||||
|
||||
FROM rust:1.53.0
|
||||
# Let's switch our working directory to `app` (equivalent to `cd app`)
|
||||
# The `app` folder will be created for us by Docker in case it does not
|
||||
# exist already.
|
||||
WORKDIR /app
|
||||
# Copy all files from our working environment to our Docker image
|
||||
|
||||
COPY . .
|
||||
# Let's build our binary!
|
||||
# We'll use the release profile to make it fast
|
||||
|
||||
WORKDIR /app/backend
|
||||
ENV SQLX_OFFLINE true
|
||||
ENV APP_ENVIRONMENT production
|
||||
RUN cargo build --release
|
||||
|
||||
# When `docker run` is executed, launch the binary!
|
||||
ENTRYPOINT ["./target/release/backend"]
|
||||
|
||||
#
|
||||
|
||||
|
||||
|
||||
## We use the latest Rust stable release as base image
|
||||
#FROM lukemathwalker/cargo-chef:latest-rust-1.53.0 as planner
|
||||
#WORKDIR /app
|
||||
#COPY . .
|
||||
#
|
||||
#WORKDIR /app/backend
|
||||
#RUN cargo chef prepare --recipe-path recipe.json
|
||||
#
|
||||
#FROM lukemathwalker/cargo-chef:latest-rust-1.53.0 as cacher
|
||||
#WORKDIR /app/backend
|
||||
#COPY --from=planner /app/backend/recipe.json recipe.json
|
||||
## Build our project dependencies, not our application!
|
||||
#RUN cargo chef cook --release --recipe-path recipe.json
|
||||
#
|
||||
#FROM rust:1.53.0 AS builder
|
||||
#WORKDIR /app/backend
|
||||
## Copy over the cached dependencies
|
||||
#COPY --from=cacher /app/backend/target target
|
||||
#COPY --from=cacher /usr/local/cargo /usr/local/cargo
|
||||
#COPY . .
|
||||
#
|
||||
#ENV SQLX_OFFLINE true
|
||||
#RUN cargo build --release --bin backend
|
||||
#
|
||||
#
|
||||
#FROM debian:buster-slim AS runtime
|
||||
#WORKDIR /app/backend
|
||||
#RUN apt-get update -y \
|
||||
# && apt-get install -y --no-install-recommends openssl \
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
#COPY --from=builder /app/backend/target/release/backend backend
|
||||
##COPY configuration configuration
|
||||
#ENV APP_ENVIRONMENT production
|
||||
#ENTRYPOINT ["./backend"]
|
||||
|
@ -1,4 +1,4 @@
|
||||
application:
|
||||
host: 0.0.0.0
|
||||
database:
|
||||
require_ssl: true
|
||||
require_ssl: false
|
||||
|
@ -27,4 +27,8 @@ export DB_PORT=5433
|
||||
|
||||
![img_1.png](img_1.png)
|
||||
|
||||
[Docker command](https://docs.docker.com/engine/reference/commandline/builder_prune/)
|
||||
[Docker command](https://docs.docker.com/engine/reference/commandline/builder_prune/)
|
||||
|
||||
### Run
|
||||
By default, Docker images do not expose their ports to the underlying host machine. We need to do it explicitly using the -p flag.
|
||||
`docker run -p 8000:8000 backend`
|
@ -63,7 +63,10 @@ async fn init_app_context(configuration: &Settings) -> Arc<AppContext> {
|
||||
let pg_pool = Arc::new(
|
||||
get_connection_pool(&configuration.database)
|
||||
.await
|
||||
.expect("Failed to connect to Postgres."),
|
||||
.expect(&format!(
|
||||
"Failed to connect to Postgres {:?}.",
|
||||
configuration.database
|
||||
)),
|
||||
);
|
||||
|
||||
let ws_server = WSServer::new().start();
|
||||
@ -77,7 +80,7 @@ async fn init_app_context(configuration: &Settings) -> Arc<AppContext> {
|
||||
|
||||
pub async fn get_connection_pool(configuration: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
|
||||
PgPoolOptions::new()
|
||||
.connect_timeout(std::time::Duration::from_secs(2))
|
||||
.connect_timeout(std::time::Duration::from_secs(5))
|
||||
.connect_with(configuration.with_db())
|
||||
.await
|
||||
}
|
||||
|
@ -8,15 +8,22 @@ pub struct Settings {
|
||||
pub application: ApplicationSettings,
|
||||
}
|
||||
|
||||
// We are using 127.0.0.1 as our host in address, we are instructing our
|
||||
// application to only accept connections coming from the same machine. However,
|
||||
// request from the hose machine which is not seen as local by our Docker image.
|
||||
//
|
||||
// Using 0.0.0.0 as host to instruct our application to accept connections from
|
||||
// any network interface. So using 127.0.0.1 for our local development and set
|
||||
// it to 0.0.0.0 in our Docker images.
|
||||
//
|
||||
#[derive(serde::Deserialize, Clone)]
|
||||
pub struct ApplicationSettings {
|
||||
#[serde(deserialize_with = "deserialize_number_from_string")]
|
||||
pub port: u16,
|
||||
pub host: String,
|
||||
pub base_url: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Clone)]
|
||||
#[derive(serde::Deserialize, Clone, Debug)]
|
||||
pub struct DatabaseSettings {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
|
@ -14,11 +14,9 @@ pub async fn register(
|
||||
_request: HttpRequest,
|
||||
payload: Payload,
|
||||
auth: Data<Arc<Auth>>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
let params: SignUpParams = parse_from_payload(payload).await?;
|
||||
let _ = auth.sign_up(params).await?;
|
||||
|
||||
let resp = FlowyResponse::success();
|
||||
let resp = auth.sign_up(params).await?;
|
||||
|
||||
Ok(resp.into())
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use chrono::Utc;
|
||||
use flowy_net::response::{ServerCode, ServerError};
|
||||
use flowy_net::response::{FlowyResponse, ServerCode, ServerError};
|
||||
use flowy_user::{entities::SignUpResponse, protobuf::SignUpParams};
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
@ -11,15 +11,16 @@ pub struct Auth {
|
||||
impl Auth {
|
||||
pub fn new(db_pool: Arc<PgPool>) -> Self { Self { db_pool } }
|
||||
|
||||
pub async fn sign_up(&self, params: SignUpParams) -> Result<SignUpResponse, ServerError> {
|
||||
pub async fn sign_up(&self, params: SignUpParams) -> Result<FlowyResponse, ServerError> {
|
||||
// email exist?
|
||||
// generate user id
|
||||
let uuid = uuid::Uuid::new_v4();
|
||||
let result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO user_table (id, email, name, create_time, password)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
"#,
|
||||
uuid::Uuid::new_v4(),
|
||||
uuid,
|
||||
params.email,
|
||||
params.name,
|
||||
Utc::now(),
|
||||
@ -28,11 +29,14 @@ impl Auth {
|
||||
.execute(self.db_pool.as_ref())
|
||||
.await;
|
||||
|
||||
let response = SignUpResponse {
|
||||
uid: "".to_string(),
|
||||
name: "".to_string(),
|
||||
email: "".to_string(),
|
||||
let data = SignUpResponse {
|
||||
uid: uuid.to_string(),
|
||||
name: params.name,
|
||||
email: params.email,
|
||||
};
|
||||
|
||||
let response = FlowyResponse::from(data, "", ServerCode::Success)?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
|
@ -19,5 +19,7 @@ members = [
|
||||
"flowy-net",
|
||||
]
|
||||
|
||||
exclude = ["../backend"]
|
||||
|
||||
[profile.dev]
|
||||
split-debuginfo = "unpacked"
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::errors::{DispatchError, InternalError};
|
||||
use bytes::Bytes;
|
||||
use protobuf::ProtobufError;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// To bytes
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use dyn_clone::DynClone;
|
||||
use protobuf::ProtobufError;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
use std::fmt;
|
||||
use tokio::{sync::mpsc::error::SendError, task::JoinError};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
byte_trait::FromBytes,
|
||||
data::Data,
|
||||
errors::{DispatchError, InternalError},
|
||||
errors::DispatchError,
|
||||
request::{EventRequest, Payload},
|
||||
response::Responder,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub const HOST: &'static str = "http://0.0.0.0:3030";
|
||||
pub const HOST: &'static str = "http://localhost:8000";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SIGN_UP_URL: String = format!("{}/user/register", HOST);
|
||||
|
@ -1,45 +0,0 @@
|
||||
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) }
|
||||
// }
|
@ -1,3 +0,0 @@
|
||||
mod errors;
|
||||
|
||||
pub use errors::*;
|
@ -1,6 +1,4 @@
|
||||
pub mod errors;
|
||||
pub mod future;
|
||||
|
||||
pub mod config;
|
||||
pub mod future;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
@ -1,23 +1,13 @@
|
||||
use crate::{future::ResultFuture, response::ServerError};
|
||||
use crate::response::{FlowyResponse, ServerCode, ServerError};
|
||||
use bytes::Bytes;
|
||||
use hyper::http;
|
||||
use protobuf::{Message, ProtobufError};
|
||||
use reqwest::{Client, Error, Response};
|
||||
use reqwest::{Client, Response};
|
||||
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
|
||||
// T1: TryInto<Bytes, Error = ProtobufError> + Send + Sync + 'static,
|
||||
// T2: TryFrom<Bytes, Error = ProtobufError> + Send + Sync + 'static,
|
||||
// {
|
||||
// let url = url.to_owned();
|
||||
// ResultFuture::new(async move { post(url, data).await })
|
||||
// }
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
pub async fn http_post<T1, T2>(url: &str, data: T1) -> Result<T2, ServerError>
|
||||
where
|
||||
@ -37,9 +27,9 @@ where
|
||||
let response = rx.await??;
|
||||
if response.status() == http::StatusCode::OK {
|
||||
let response_bytes = response.bytes().await?;
|
||||
let data = T2::try_from(response_bytes)?;
|
||||
let flowy_resp: FlowyResponse = serde_json::from_slice(&response_bytes).unwrap();
|
||||
let data = T2::try_from(flowy_resp.data)?;
|
||||
Ok(data)
|
||||
|
||||
} else {
|
||||
Err(ServerError {
|
||||
code: ServerCode::InternalError,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use serde::{Serialize, __private::Formatter};
|
||||
use bytes::Bytes;
|
||||
use serde::{Deserialize, Serialize, __private::Formatter};
|
||||
use serde_repr::*;
|
||||
use std::{error::Error, fmt};
|
||||
use std::{convert::TryInto, error::Error, fmt};
|
||||
use tokio::sync::oneshot::error::RecvError;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -16,11 +17,11 @@ impl std::fmt::Display for ServerError {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&ServerError> for FlowyResponse<String> {
|
||||
impl std::convert::From<&ServerError> for FlowyResponse {
|
||||
fn from(error: &ServerError) -> Self {
|
||||
FlowyResponse {
|
||||
msg: error.msg.clone(),
|
||||
data: None,
|
||||
data: Bytes::from(vec![]),
|
||||
code: error.code.clone(),
|
||||
}
|
||||
}
|
||||
@ -43,15 +44,15 @@ pub enum ServerCode {
|
||||
ConnectCancel = 11,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct FlowyResponse<T> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FlowyResponse {
|
||||
pub msg: String,
|
||||
pub data: Option<T>,
|
||||
pub data: Bytes,
|
||||
pub code: ServerCode,
|
||||
}
|
||||
|
||||
impl<T: Serialize> FlowyResponse<T> {
|
||||
pub fn new(data: Option<T>, msg: &str, code: ServerCode) -> Self {
|
||||
impl FlowyResponse {
|
||||
pub fn new(data: Bytes, msg: &str, code: ServerCode) -> Self {
|
||||
FlowyResponse {
|
||||
msg: msg.to_owned(),
|
||||
data,
|
||||
@ -59,16 +60,13 @@ impl<T: Serialize> FlowyResponse<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(data: T, msg: &str, code: ServerCode) -> Self {
|
||||
Self::new(Some(data), msg, code)
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowyResponse<String> {
|
||||
pub fn success() -> Self { Self::from_msg("", ServerCode::Success) }
|
||||
|
||||
pub fn from_msg(msg: &str, code: ServerCode) -> Self {
|
||||
Self::new(Some("".to_owned()), msg, code)
|
||||
pub fn from<T: TryInto<Bytes, Error = protobuf::ProtobufError>>(
|
||||
data: T,
|
||||
msg: &str,
|
||||
code: ServerCode,
|
||||
) -> Result<Self, ServerError> {
|
||||
let bytes: Bytes = data.try_into()?;
|
||||
Ok(Self::new(bytes, msg, code))
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +88,16 @@ impl std::convert::From<RecvError> for ServerError {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<serde_json::Error> for ServerError {
|
||||
fn from(e: serde_json::Error) -> Self {
|
||||
let msg = format!("Serial error: {:?}", e);
|
||||
ServerError {
|
||||
code: ServerCode::SerdeError,
|
||||
msg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<reqwest::Error> for ServerError {
|
||||
fn from(error: reqwest::Error) -> Self {
|
||||
if error.is_timeout() {
|
||||
@ -121,9 +129,7 @@ impl std::convert::From<reqwest::Error> for ServerError {
|
||||
code = ServerCode::ConnectCancel;
|
||||
}
|
||||
|
||||
if hyper_error.is_timeout() {
|
||||
|
||||
}
|
||||
if hyper_error.is_timeout() {}
|
||||
|
||||
ServerError { code, msg }
|
||||
},
|
||||
|
@ -1,30 +1,14 @@
|
||||
use crate::response::*;
|
||||
use actix_web::{body::Body, error::ResponseError, BaseHttpResponse, HttpResponse};
|
||||
use reqwest::StatusCode;
|
||||
use serde::Serialize;
|
||||
|
||||
impl ServerError {
|
||||
fn http_response(&self) -> HttpResponse {
|
||||
let resp: FlowyResponse<String> = self.into();
|
||||
HttpResponse::Ok().json(resp)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for ServerError {
|
||||
fn error_response(&self) -> HttpResponse { self.http_response().into() }
|
||||
}
|
||||
|
||||
impl<T: Serialize> std::convert::Into<HttpResponse> for FlowyResponse<T> {
|
||||
fn into(self) -> HttpResponse {
|
||||
match serde_json::to_string(&self) {
|
||||
Ok(body) => HttpResponse::Ok().body(Body::from(body)),
|
||||
Err(e) => {
|
||||
let msg = format!("Serial error: {:?}", e);
|
||||
ServerError {
|
||||
code: ServerCode::SerdeError,
|
||||
msg,
|
||||
}
|
||||
.error_response()
|
||||
},
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let response: FlowyResponse = self.into();
|
||||
response.into()
|
||||
}
|
||||
}
|
||||
impl std::convert::Into<HttpResponse> for FlowyResponse {
|
||||
fn into(self) -> HttpResponse { HttpResponse::Ok().json(self) }
|
||||
}
|
||||
|
@ -1,128 +1,129 @@
|
||||
use crate::response::{FlowyResponse, ServerCode};
|
||||
use serde::{
|
||||
de::{self, MapAccess, Visitor},
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
Serialize,
|
||||
};
|
||||
use std::{fmt, marker::PhantomData, str::FromStr};
|
||||
|
||||
pub trait ServerData<'a>: Serialize + Deserialize<'a> + FromStr<Err = ()> {}
|
||||
impl<'de, T: ServerData<'de>> Deserialize<'de> for FlowyResponse<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ServerResponseVisitor<T>(PhantomData<fn() -> T>);
|
||||
impl<'de, T> Visitor<'de> for ServerResponseVisitor<T>
|
||||
where
|
||||
T: ServerData<'de>,
|
||||
{
|
||||
type Value = FlowyResponse<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("struct Duration")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut msg = None;
|
||||
let mut data: Option<T> = None;
|
||||
let mut code: Option<ServerCode> = None;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
"msg" => {
|
||||
if msg.is_some() {
|
||||
return Err(de::Error::duplicate_field("msg"));
|
||||
}
|
||||
msg = Some(map.next_value()?);
|
||||
},
|
||||
"code" => {
|
||||
if code.is_some() {
|
||||
return Err(de::Error::duplicate_field("code"));
|
||||
}
|
||||
code = Some(map.next_value()?);
|
||||
},
|
||||
"data" => {
|
||||
if data.is_some() {
|
||||
return Err(de::Error::duplicate_field("data"));
|
||||
}
|
||||
data = match MapAccess::next_value::<DeserializeWith<T>>(&mut map) {
|
||||
Ok(wrapper) => wrapper.value,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
let msg = msg.ok_or_else(|| de::Error::missing_field("msg"))?;
|
||||
let code = code.ok_or_else(|| de::Error::missing_field("code"))?;
|
||||
Ok(Self::Value::new(data, msg, code))
|
||||
}
|
||||
}
|
||||
const FIELDS: &'static [&'static str] = &["msg", "code", "data"];
|
||||
deserializer.deserialize_struct(
|
||||
"ServerResponse",
|
||||
FIELDS,
|
||||
ServerResponseVisitor(PhantomData),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct DeserializeWith<'de, T: ServerData<'de>> {
|
||||
value: Option<T>,
|
||||
phantom: PhantomData<&'de ()>,
|
||||
}
|
||||
|
||||
impl<'de, T: ServerData<'de>> Deserialize<'de> for DeserializeWith<'de, T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(DeserializeWith {
|
||||
value: match string_or_data(deserializer) {
|
||||
Ok(val) => val,
|
||||
Err(e) => return Err(e),
|
||||
},
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn string_or_data<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: ServerData<'de>,
|
||||
{
|
||||
struct StringOrData<T>(PhantomData<fn() -> T>);
|
||||
impl<'de, T: ServerData<'de>> Visitor<'de> for StringOrData<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("string or struct impl deserialize")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
match FromStr::from_str(value) {
|
||||
Ok(val) => Ok(Some(val)),
|
||||
Err(_e) => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
match Deserialize::deserialize(de::value::MapAccessDeserializer::new(map)) {
|
||||
Ok(val) => Ok(Some(val)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_any(StringOrData(PhantomData))
|
||||
}
|
||||
// use crate::response::{FlowyResponse, ServerCode};
|
||||
// use serde::{
|
||||
// de::{self, MapAccess, Visitor},
|
||||
// Deserialize,
|
||||
// Deserializer,
|
||||
// Serialize,
|
||||
// };
|
||||
// use std::{fmt, marker::PhantomData, str::FromStr};
|
||||
//
|
||||
// pub trait ServerData<'a>: Serialize + Deserialize<'a> + FromStr<Err = ()> {}
|
||||
// impl<'de, T: ServerData<'de>> Deserialize<'de> for FlowyResponse<T> {
|
||||
// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
// where
|
||||
// D: Deserializer<'de>,
|
||||
// {
|
||||
// struct ServerResponseVisitor<T>(PhantomData<fn() -> T>);
|
||||
// impl<'de, T> Visitor<'de> for ServerResponseVisitor<T>
|
||||
// where
|
||||
// T: ServerData<'de>,
|
||||
// {
|
||||
// type Value = FlowyResponse<T>;
|
||||
//
|
||||
// fn expecting(&self, formatter: &mut fmt::Formatter) ->
|
||||
// fmt::Result { formatter.write_str("struct Duration")
|
||||
// }
|
||||
//
|
||||
// fn visit_map<V>(self, mut map: V) -> Result<Self::Value,
|
||||
// V::Error> where
|
||||
// V: MapAccess<'de>,
|
||||
// {
|
||||
// let mut msg = None;
|
||||
// let mut data: Option<T> = None;
|
||||
// let mut code: Option<ServerCode> = None;
|
||||
// while let Some(key) = map.next_key()? {
|
||||
// match key {
|
||||
// "msg" => {
|
||||
// if msg.is_some() {
|
||||
// return
|
||||
// Err(de::Error::duplicate_field("msg")); }
|
||||
// msg = Some(map.next_value()?);
|
||||
// },
|
||||
// "code" => {
|
||||
// if code.is_some() {
|
||||
// return
|
||||
// Err(de::Error::duplicate_field("code")); }
|
||||
// code = Some(map.next_value()?);
|
||||
// },
|
||||
// "data" => {
|
||||
// if data.is_some() {
|
||||
// return
|
||||
// Err(de::Error::duplicate_field("data")); }
|
||||
// data = match
|
||||
// MapAccess::next_value::<DeserializeWith<T>>(&mut map) {
|
||||
// Ok(wrapper) => wrapper.value, Err(err) =>
|
||||
// return Err(err), };
|
||||
// },
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// let msg = msg.ok_or_else(||
|
||||
// de::Error::missing_field("msg"))?; let code =
|
||||
// code.ok_or_else(|| de::Error::missing_field("code"))?;
|
||||
// Ok(Self::Value::new(data, msg, code)) }
|
||||
// }
|
||||
// const FIELDS: &'static [&'static str] = &["msg", "code", "data"];
|
||||
// deserializer.deserialize_struct(
|
||||
// "ServerResponse",
|
||||
// FIELDS,
|
||||
// ServerResponseVisitor(PhantomData),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// struct DeserializeWith<'de, T: ServerData<'de>> {
|
||||
// value: Option<T>,
|
||||
// phantom: PhantomData<&'de ()>,
|
||||
// }
|
||||
//
|
||||
// impl<'de, T: ServerData<'de>> Deserialize<'de> for DeserializeWith<'de, T> {
|
||||
// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
// where
|
||||
// D: Deserializer<'de>,
|
||||
// {
|
||||
// Ok(DeserializeWith {
|
||||
// value: match string_or_data(deserializer) {
|
||||
// Ok(val) => val,
|
||||
// Err(e) => return Err(e),
|
||||
// },
|
||||
// phantom: PhantomData,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn string_or_data<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||
// where
|
||||
// D: Deserializer<'de>,
|
||||
// T: ServerData<'de>,
|
||||
// {
|
||||
// struct StringOrData<T>(PhantomData<fn() -> T>);
|
||||
// impl<'de, T: ServerData<'de>> Visitor<'de> for StringOrData<T> {
|
||||
// type Value = Option<T>;
|
||||
//
|
||||
// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
// formatter.write_str("string or struct impl deserialize")
|
||||
// }
|
||||
//
|
||||
// fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
// where
|
||||
// E: de::Error,
|
||||
// {
|
||||
// match FromStr::from_str(value) {
|
||||
// Ok(val) => Ok(Some(val)),
|
||||
// Err(_e) => Ok(None),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
|
||||
// where
|
||||
// M: MapAccess<'de>,
|
||||
// {
|
||||
// match
|
||||
// Deserialize::deserialize(de::value::MapAccessDeserializer::new(map)) {
|
||||
// Ok(val) => Ok(Some(val)),
|
||||
// Err(e) => Err(e),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// deserializer.deserialize_any(StringOrData(PhantomData))
|
||||
// }
|
||||
|
@ -40,7 +40,7 @@ impl RustStreamSender {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post(observable_subject: ObservableSubject) -> Result<(), String> {
|
||||
pub fn post(_observable_subject: ObservableSubject) -> Result<(), String> {
|
||||
#[cfg(feature = "dart")]
|
||||
match R2F_STREAM_SENDER.read() {
|
||||
Ok(stream) => stream.inner_post(observable_subject),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
entities::parser::*,
|
||||
errors::{ErrorBuilder, UserErrCode, UserError},
|
||||
errors::{ErrorBuilder, UserError},
|
||||
};
|
||||
use flowy_derive::ProtoBuf;
|
||||
use std::convert::TryInto;
|
||||
|
@ -3,7 +3,6 @@ use crate::{
|
||||
errors::{ErrorBuilder, UserErrCode, UserError},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use flowy_net::{config::SIGN_UP_URL, future::ResultFuture, request::http_post};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -5,7 +5,6 @@ pub use flowy_test::prelude::{random_valid_email, valid_password};
|
||||
pub(crate) fn invalid_email_test_case() -> Vec<String> {
|
||||
// https://gist.github.com/cjaoude/fd9910626629b53c4d25
|
||||
vec![
|
||||
"",
|
||||
"annie@",
|
||||
"annie@gmail@",
|
||||
"#@%^%#$@#$@#.com",
|
||||
@ -31,7 +30,7 @@ pub(crate) fn invalid_email_test_case() -> Vec<String> {
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_password_test_case() -> Vec<String> {
|
||||
vec!["", "123456", "1234".repeat(100).as_str()]
|
||||
vec!["123456", "1234".repeat(100).as_str()]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -35,7 +35,7 @@ fn sign_in_with_invalid_email() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::EmailInvalid
|
||||
UserErrCode::EmailFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ fn sign_in_with_invalid_password() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::PasswordInvalid
|
||||
UserErrCode::PasswordFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ fn sign_up_with_invalid_email() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::EmailInvalid
|
||||
UserErrCode::EmailFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ fn sign_up_with_invalid_password() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::PasswordInvalid
|
||||
UserErrCode::PasswordFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ fn user_update_with_invalid_email() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::EmailInvalid
|
||||
UserErrCode::EmailFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,7 @@ fn user_update_with_invalid_password() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::PasswordInvalid
|
||||
UserErrCode::PasswordFormatInvalid
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -135,6 +135,6 @@ fn user_update_with_invalid_name() {
|
||||
.sync_send()
|
||||
.error()
|
||||
.code,
|
||||
UserErrCode::UserNameInvalid
|
||||
UserErrCode::UserIdInvalid
|
||||
);
|
||||
}
|
||||
|
@ -10,4 +10,5 @@ async fn user_register_test() {
|
||||
password: "123".to_string(),
|
||||
};
|
||||
let result = server.sign_up(params).await.unwrap();
|
||||
println!("{:?}", result);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf_Enum;
|
||||
use flowy_dispatch::prelude::{DispatchError, ToBytes};
|
||||
use flowy_dispatch::prelude::ToBytes;
|
||||
use flowy_observable::{dart::RustStreamSender, entities::ObservableSubject};
|
||||
|
||||
const OBSERVABLE_CATEGORY: &'static str = "Workspace";
|
||||
|
@ -9,6 +9,7 @@ rustup component add rustfmt
|
||||
cargo install cargo-expand
|
||||
cargo install cargo-watch
|
||||
cargo install cargo-cache
|
||||
cargo install bunyan
|
||||
|
||||
#protobuf code gen env
|
||||
brew install protobuf@3.13
|
||||
|
Loading…
Reference in New Issue
Block a user