config flowy-user test

This commit is contained in:
appflowy 2021-06-30 23:11:27 +08:00
parent f73b3ded1d
commit 678dd84f93
26 changed files with 368 additions and 144 deletions

View File

@ -11,6 +11,7 @@
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-log/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sdk/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-user/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sdk/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />

View File

@ -1,5 +1,4 @@
use byteorder::{BigEndian, ByteOrder};
use flowy_protobuf::ResponsePacket;
use std::mem::{forget, size_of};
pub fn forget_rust(buf: Vec<u8>) -> *const u8 {

View File

@ -13,23 +13,37 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
return 1;
}
pub struct FFICommand {
event: String,
payload: Vec<u8>,
}
impl FFICommand {
pub fn from_bytes(bytes: Vec<u8>) -> Self { unimplemented!() }
pub fn from_u8_pointer(pointer: *const u8, len: usize) -> Self {
let bytes = unsafe { std::slice::from_raw_parts(pointer, len) }.to_vec();
unimplemented!()
}
}
#[no_mangle]
pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
let bytes = unsafe { std::slice::from_raw_parts(input, len) }.to_vec();
let payload = SenderPayload::from_data(bytes);
let FFICommand { event, payload } = FFICommand::from_u8_pointer(input, len);
let stream_data = SenderData::new(port, payload).callback(Box::new(|_config, response| {
log::info!("async resp: {:?}", response);
}));
let mut request = SenderRequest::new(port, event).callback(|_, resp| {
log::info!("async resp: {:?}", resp);
});
async_send(stream_data);
if !payload.is_empty() {
request = request.payload(Payload::Bytes(bytes));
}
async_send(request);
}
#[no_mangle]
pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 {
let bytes = unsafe { std::slice::from_raw_parts(input, len) }.to_vec();
forget_rust(bytes)
}
pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 { unimplemented!() }
#[inline(never)]
#[no_mangle]

View File

@ -8,3 +8,14 @@ edition = "2018"
[dependencies]
flowy-sys = { path = "../flowy-sys" }
flowy-log = { path = "../flowy-log" }
flowy-user = { path = "../flowy-user" }
log = "0.4.14"
[dev-dependencies]
serde = { version = "1.0", features = ["derive"] }
bincode = { version = "1.3"}
protobuf = {version = "2.24.1"}
claim = "0.5.0"
tokio = { version = "1", features = ["full"]}
futures-util = "0.3.15"

View File

@ -1,21 +1,24 @@
use flowy_sys::prelude::*;
use std::cell::RefCell;
pub mod module;
pub use module::*;
use flowy_sys::prelude::*;
use module::build_modules;
use std::cell::RefCell;
pub struct FlowySDK {}
impl FlowySDK {
pub fn init(path: &str) {
let modules = init_modules();
init_system(modules);
flowy_log::init_log("flowy", "Debug").unwrap();
log::info!("🔥🔥🔥 System start running");
match init_system(build_modules()).run() {
Ok(_) => {},
Err(e) => log::error!("System run fail with error: {:?}", e),
}
}
}
pub fn init_modules() -> Vec<Module> {
let modules = vec![];
modules
}
pub fn init_system<F>(modules: Vec<Module>) {
pub fn init_system(modules: Vec<Module>) -> SystemRunner {
FlowySystem::construct(
|| modules,
|module_map, runtime| {
@ -27,22 +30,20 @@ pub fn init_system<F>(modules: Vec<Module>) {
});
},
)
.run()
.unwrap();
}
thread_local!(
static SENDER: RefCell<Option<Sender<i64>>> = RefCell::new(None);
);
pub fn sync_send(data: SenderData<i64>) -> EventResponse {
pub fn sync_send(data: SenderRequest<i64>) -> EventResponse {
SENDER.with(|cell| match &*cell.borrow() {
Some(stream) => stream.sync_send(data),
None => panic!(""),
})
}
pub fn async_send(data: SenderData<i64>) {
pub fn async_send(data: SenderRequest<i64>) {
SENDER.with(|cell| match &*cell.borrow() {
Some(stream) => {
stream.async_send(data);

View File

@ -0,0 +1,3 @@
use flowy_sys::prelude::Module;
pub fn build_modules() -> Vec<Module> { vec![flowy_user::module::create()] }

View File

@ -0,0 +1,85 @@
use flowy_sdk::module::build_modules;
pub use flowy_sdk::*;
use flowy_sys::prelude::*;
use std::{
fmt::{Debug, Display},
hash::Hash,
sync::Once,
};
static INIT: Once = Once::new();
pub fn run_test_system<F>(f: F)
where
F: FnOnce() + 'static,
{
INIT.call_once(|| {
flowy_log::init_log("flowy", "Debug").unwrap();
});
let mut runner = init_system(build_modules());
runner = runner.spawn(async {
f();
FlowySystem::current().stop();
});
log::info!("🔥🔥🔥 System start running");
match runner.run() {
Ok(_) => {},
Err(e) => log::error!("System run fail with error: {:?}", e),
}
}
pub struct FlowySDKTester {
request: SenderRequest<i64>,
callback: Option<BoxStreamCallback<i64>>,
}
impl FlowySDKTester {
pub fn new<E>(event: E) -> Self
where
E: Eq + Hash + Debug + Clone + Display,
{
Self {
request: SenderRequest::new(1, event),
callback: None,
}
}
#[allow(dead_code)]
pub fn bytes_payload<T>(mut self, payload: T) -> Self
where
T: serde::Serialize,
{
let bytes: Vec<u8> = bincode::serialize(&payload).unwrap();
self.request = self.request.payload(Payload::Bytes(bytes));
self
}
#[allow(dead_code)]
pub fn protobuf_payload<T>(mut self, payload: T) -> Self
where
T: ::protobuf::Message,
{
let bytes: Vec<u8> = payload.write_to_bytes().unwrap();
self.request = self.request.payload(Payload::Bytes(bytes));
self
}
#[allow(dead_code)]
pub fn callback<F>(mut self, callback: F) -> Self
where
F: FnOnce(i64, EventResponse) + 'static + Send + Sync,
{
self.request = self.request.callback(|config, response| {
dbg!(&response);
callback(config, response);
});
self
}
pub fn run(self) {
run_test_system(move || {
async_send(self.request);
});
}
}

View File

@ -0,0 +1,2 @@
mod helper;
mod user_check;

View File

@ -0,0 +1,26 @@
use super::helper::*;
use flowy_sys::prelude::*;
use flowy_user::prelude::*;
#[test]
fn auth_check_no_payload() {
let callback = |_, resp: EventResponse| {
assert_eq!(resp.status, StatusCode::Err);
};
FlowySDKTester::new(AuthCheck).callback(callback).run();
}
#[test]
fn auth_check_with_user_name_email_payload() {
let callback = |_, resp: EventResponse| {
assert_eq!(resp.status, StatusCode::Ok);
};
let user_data = UserData::new("jack".to_owned(), "helloworld@gmail.com".to_owned());
FlowySDKTester::new(AuthCheck)
.bytes_payload(user_data)
.callback(callback)
.run();
}

View File

@ -21,6 +21,7 @@ serde_with = "1.9.4"
thread-id = "3.3.0"
lazy_static = "1.4.0"
dyn-clone = "1.0"
derivative = "2.2.0"
#optional crate
bincode = { version = "1.3", optional = true}

View File

@ -7,7 +7,7 @@ use std::{fmt, option::NoneError};
use tokio::sync::mpsc::error::SendError;
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Serialize, Serializer};
use serde::{Serialize, Serializer};
pub trait Error: fmt::Debug + fmt::Display + DynClone {
fn status_code(&self) -> StatusCode;
@ -18,7 +18,11 @@ pub trait Error: fmt::Debug + fmt::Display + DynClone {
dyn_clone::clone_trait_object!(Error);
impl<T: Error + 'static> From<T> for SystemError {
fn from(err: T) -> SystemError { SystemError { inner: Box::new(err) } }
fn from(err: T) -> SystemError {
SystemError {
inner: Box::new(err),
}
}
}
#[derive(Clone)]
@ -62,6 +66,10 @@ impl From<NoneError> for SystemError {
}
}
impl From<String> for SystemError {
fn from(s: String) -> Self { InternalError { inner: s }.into() }
}
impl From<SystemError> for EventResponse {
fn from(err: SystemError) -> Self { err.inner_error().as_response() }
}
@ -95,7 +103,14 @@ where
{
fn status_code(&self) -> StatusCode { StatusCode::Err }
fn as_response(&self) -> EventResponse { EventResponseBuilder::Err().data(format!("{}", self.inner)).build() }
fn as_response(&self) -> EventResponse {
let error = InternalError {
inner: format!("{}", self.inner),
}
.into();
EventResponseBuilder::Err().error(error).build()
}
}
#[cfg(feature = "use_serde")]

View File

@ -1,8 +1,3 @@
use std::pin::Pin;
use bytes::Bytes;
use futures::Stream;
pub enum PayloadError {}
// TODO: support stream data

View File

@ -3,14 +3,14 @@ use std::future::Future;
use crate::{
error::{InternalError, SystemError},
module::Event,
request::{payload::Payload, PayloadError},
request::payload::Payload,
response::Responder,
util::ready::{ready, Ready},
};
use bytes::Bytes;
use futures_core::{ready, Stream};
use futures_core::ready;
use std::{
fmt::{Debug, Display},
fmt::Debug,
hash::Hash,
ops,
pin::Pin,
@ -57,13 +57,19 @@ impl FromRequest for String {
fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
match &payload {
Payload::None => ready(Err(unexpected_none_payload())),
Payload::None => ready(Err(unexpected_none_payload(req))),
Payload::Bytes(buf) => ready(Ok(String::from_utf8_lossy(buf).into_owned())),
}
}
}
fn unexpected_none_payload() -> SystemError { InternalError::new("Expected string but request had data").into() }
fn unexpected_none_payload(request: &EventRequest) -> SystemError {
log::warn!(
"Event: {:?} expected payload but payload is empty",
&request.event
);
InternalError::new("Expected payload but payload is empty").into()
}
#[doc(hidden)]
impl<T> FromRequest for Result<T, T::Error>
@ -126,7 +132,7 @@ where
#[inline]
fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
match payload {
Payload::None => ready(Err(unexpected_none_payload())),
Payload::None => ready(Err(unexpected_none_payload(req))),
Payload::Bytes(bytes) => {
let data: T = bincode::deserialize(bytes).unwrap();
ready(Ok(In(data)))
@ -146,7 +152,7 @@ where
#[inline]
fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
match payload {
Payload::None => ready(Err(unexpected_none_payload())),
Payload::None => ready(Err(unexpected_none_payload(req))),
Payload::Bytes(bytes) => {
let data: T = ::protobuf::Message::parse_from_bytes(bytes).unwrap();
ready(Ok(In(data)))

View File

@ -30,8 +30,8 @@ impl EventResponseBuilder {
self
}
pub fn error(mut self, error: Option<SystemError>) -> Self {
self.error = error;
pub fn error(mut self, error: SystemError) -> Self {
self.error = Some(error);
self
}

View File

@ -13,7 +13,9 @@ pub trait Responder {
macro_rules! impl_responder {
($res: ty) => {
impl Responder for $res {
fn respond_to(self, _: &EventRequest) -> EventResponse { EventResponseBuilder::Ok().data(self).build() }
fn respond_to(self, _: &EventRequest) -> EventResponse {
EventResponseBuilder::Ok().data(self).build()
}
}
};
}
@ -63,6 +65,14 @@ where
}
}
#[cfg(feature = "use_serde")]
impl<T> std::convert::From<T> for Out<T>
where
T: serde::Serialize,
{
fn from(val: T) -> Self { Out(val) }
}
#[cfg(feature = "use_protobuf")]
impl<T> Responder for Out<T>
where
@ -73,3 +83,11 @@ where
EventResponseBuilder::Ok().data(bytes).build()
}
}
#[cfg(feature = "use_protobuf")]
impl<T> std::convert::From<T> for Out<T>
where
T: ::protobuf::Message,
{
fn from(val: T) -> Self { Out(val) }
}

View File

@ -8,11 +8,11 @@ use crate::{
use serde::{Deserialize, Serialize, Serializer};
use std::{fmt, fmt::Formatter};
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
pub enum StatusCode {
Ok,
Err,
Ok = 0,
Err = 1,
}
// serde user guide: https://serde.rs/field-attrs.html

View File

@ -1,71 +1,99 @@
use crate::{
module::{Event, ModuleRequest},
request::{EventRequest, Payload},
response::EventResponse,
};
use crate::{module::Event, request::Payload, response::EventResponse};
use derivative::*;
use std::{
fmt::{Debug, Display},
hash::Hash,
};
// #[derive(Debug)]
// pub struct SenderPayload {
// pub(crate) payload: Payload,
// pub(crate) event: Event,
// }
//
// impl SenderPayload {
// pub fn new<E>(event: E) -> SenderPayload
// where
// E: Eq + Hash + Debug + Clone + Display,
// {
// Self {
// event: event.into(),
// payload: Payload::None,
// }
// }
//
// pub fn payload(mut self, payload: Payload) -> Self {
// self.payload = payload;
// self
// }
//
// pub fn from_bytes(bytes: Vec<u8>) -> Self { unimplemented!() }
// }
//
// impl std::convert::Into<ModuleRequest> for SenderPayload {
// fn into(self) -> ModuleRequest {
// ModuleRequest::new(self.event).payload(self.payload) } }
//
// impl std::default::Default for SenderPayload {
// fn default() -> Self { SenderPayload::new("").payload(Payload::None) }
// }
//
// impl std::convert::Into<EventRequest> for SenderPayload {
// fn into(self) -> EventRequest { unimplemented!() }
// }
#[derive(Debug)]
pub struct SenderPayload {
pub(crate) payload: Payload,
pub(crate) event: Event,
pub type BoxStreamCallback<T> = Box<dyn FnOnce(T, EventResponse) + 'static + Send + Sync>;
// #[derive(Debug)]
// pub struct SenderRequest2<T, C>
// where
// T: 'static + Debug,
// C: FnOnce(T, EventResponse) + 'static,
// {
// pub config: T,
// pub event: Event,
// pub payload: Option<Payload>,
// pub callback: Box<dyn C>,
// }
#[derive(Derivative)]
#[derivative(Debug)]
pub struct SenderRequest<T>
where
T: 'static + Debug,
{
pub config: T,
pub event: Event,
pub payload: Option<Payload>,
#[derivative(Debug = "ignore")]
pub callback: Option<BoxStreamCallback<T>>,
}
impl SenderPayload {
pub fn new<E>(event: E) -> SenderPayload
impl<T> SenderRequest<T>
where
T: 'static + Debug,
{
pub fn new<E>(config: T, event: E) -> Self
where
E: Eq + Hash + Debug + Clone + Display,
{
Self {
event: event.into(),
payload: Payload::None,
}
}
pub fn payload(mut self, payload: Payload) -> Self {
self.payload = payload;
self
}
pub fn from_bytes(bytes: Vec<u8>) -> Self { unimplemented!() }
}
impl std::convert::Into<ModuleRequest> for SenderPayload {
fn into(self) -> ModuleRequest { ModuleRequest::new(self.event).payload(self.payload) }
}
impl std::default::Default for SenderPayload {
fn default() -> Self { SenderPayload::new("").payload(Payload::None) }
}
impl std::convert::Into<EventRequest> for SenderPayload {
fn into(self) -> EventRequest { unimplemented!() }
}
pub type BoxStreamCallback<T> = Box<dyn FnOnce(T, EventResponse) + 'static + Send + Sync>;
pub struct SenderData<T>
where
T: 'static,
{
pub config: T,
pub payload: SenderPayload,
pub callback: Option<BoxStreamCallback<T>>,
}
impl<T> SenderData<T> {
pub fn new(config: T, payload: SenderPayload) -> Self {
Self {
config,
payload,
payload: None,
event: event.into(),
callback: None,
}
}
pub fn callback(mut self, callback: BoxStreamCallback<T>) -> Self {
self.callback = Some(callback);
pub fn payload(mut self, payload: Payload) -> Self {
self.payload = Some(payload);
self
}
pub fn callback<F>(mut self, callback: F) -> Self
where
F: FnOnce(T, EventResponse) + 'static + Send + Sync,
{
self.callback = Some(Box::new(callback));
self
}
}

View File

@ -1,14 +1,14 @@
use crate::{
error::{InternalError, SystemError},
module::{Event, ModuleRequest},
module::ModuleRequest,
request::{EventRequest, Payload},
response::EventResponse,
sender::{SenderData, SenderPayload},
sender::SenderRequest,
service::{BoxService, Service, ServiceFactory},
system::ModuleMap,
};
use futures_core::{future::LocalBoxFuture, ready, task::Context};
use std::future::Future;
use std::{fmt::Debug, future::Future};
use tokio::{
macros::support::{Pin, Poll},
sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
@ -17,13 +17,13 @@ use tokio::{
macro_rules! service_factor_impl {
($name:ident) => {
#[allow(non_snake_case, missing_docs)]
impl<T> ServiceFactory<SenderData<T>> for $name<T>
impl<T> ServiceFactory<SenderRequest<T>> for $name<T>
where
T: 'static,
T: 'static + Debug,
{
type Response = EventResponse;
type Error = SystemError;
type Service = BoxService<SenderData<T>, Self::Response, Self::Error>;
type Service = BoxService<SenderRequest<T>, Self::Response, Self::Error>;
type Context = ();
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>>;
@ -40,24 +40,27 @@ struct SenderService {
module_map: ModuleMap,
}
impl<T> Service<SenderData<T>> for SenderService
impl<T> Service<SenderRequest<T>> for SenderService
where
T: 'static,
T: 'static + Debug,
{
type Response = EventResponse;
type Error = SystemError;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn call(&self, data: SenderData<T>) -> Self::Future {
fn call(&self, data: SenderRequest<T>) -> Self::Future {
let module_map = self.module_map.clone();
let SenderData {
let SenderRequest {
config,
event,
payload,
callback,
} = data;
let event = payload.event.clone();
let request = payload.into();
let mut request = ModuleRequest::new(event.clone());
if let Some(payload) = payload {
request = request.payload(payload);
}
let fut = async move {
let result = {
@ -87,21 +90,21 @@ where
pub struct Sender<T>
where
T: 'static,
T: 'static + Debug,
{
module_map: ModuleMap,
data_tx: UnboundedSender<SenderData<T>>,
data_rx: Option<UnboundedReceiver<SenderData<T>>>,
data_tx: UnboundedSender<SenderRequest<T>>,
data_rx: Option<UnboundedReceiver<SenderRequest<T>>>,
}
service_factor_impl!(Sender);
impl<T> Sender<T>
where
T: 'static,
T: 'static + Debug,
{
pub fn new(module_map: ModuleMap) -> Self {
let (data_tx, data_rx) = unbounded_channel::<SenderData<T>>();
let (data_tx, data_rx) = unbounded_channel::<SenderRequest<T>>();
Self {
module_map,
data_tx,
@ -109,9 +112,9 @@ where
}
}
pub fn async_send(&self, data: SenderData<T>) { let _ = self.data_tx.send(data); }
pub fn async_send(&self, data: SenderRequest<T>) { let _ = self.data_tx.send(data); }
pub fn sync_send(&self, data: SenderData<T>) -> EventResponse {
pub fn sync_send(&self, data: SenderRequest<T>) -> EventResponse {
let factory = self.new_service(());
futures::executor::block_on(async {
@ -120,31 +123,31 @@ where
})
}
pub fn take_rx(&mut self) -> UnboundedReceiver<SenderData<T>> { self.data_rx.take().unwrap() }
pub fn take_rx(&mut self) -> UnboundedReceiver<SenderRequest<T>> { self.data_rx.take().unwrap() }
}
pub struct SenderRunner<T>
where
T: 'static,
T: 'static + Debug,
{
module_map: ModuleMap,
data_rx: UnboundedReceiver<SenderData<T>>,
data_rx: UnboundedReceiver<SenderRequest<T>>,
}
service_factor_impl!(SenderRunner);
impl<T> SenderRunner<T>
where
T: 'static,
T: 'static + Debug,
{
pub fn new(module_map: ModuleMap, data_rx: UnboundedReceiver<SenderData<T>>) -> Self {
pub fn new(module_map: ModuleMap, data_rx: UnboundedReceiver<SenderRequest<T>>) -> Self {
Self { module_map, data_rx }
}
}
impl<T> Future for SenderRunner<T>
where
T: 'static,
T: 'static + Debug,
{
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {

View File

@ -1,4 +1,4 @@
use flowy_sys::prelude::{EventResponse, FlowySystem, Module, Sender, SenderData, SenderRunner};
use flowy_sys::prelude::{EventResponse, FlowySystem, Module, Sender, SenderRequest, SenderRunner};
use std::{cell::RefCell, sync::Once};
#[allow(dead_code)]
@ -10,24 +10,18 @@ pub fn setup_env() {
});
}
pub struct ExecutorAction {
command: String,
}
pub struct FlowySystemExecutor {}
thread_local!(
static SENDER: RefCell<Option<Sender<i64>>> = RefCell::new(None);
);
pub fn sync_send(data: SenderData<i64>) -> EventResponse {
pub fn sync_send(data: SenderRequest<i64>) -> EventResponse {
SENDER.with(|cell| match &*cell.borrow() {
Some(stream) => stream.sync_send(data),
None => panic!(""),
})
}
pub fn async_send(data: SenderData<i64>) {
pub fn async_send(data: SenderRequest<i64>) {
SENDER.with(|cell| match &*cell.borrow() {
Some(stream) => {
stream.async_send(data);

View File

@ -10,15 +10,12 @@ fn test_init() {
let modules = vec![Module::new().event(event, hello)];
init_system(modules, move || {
let payload = SenderPayload::new(event);
let stream_data = SenderData::new(1, payload).callback(Box::new(|_config, response| {
let request = SenderRequest::new(1, event).callback(|_config, response| {
log::info!("async resp: {:?}", response);
}));
});
let resp = sync_send(stream_data);
let resp = sync_send(request);
log::info!("sync resp: {:?}", resp);
stop_system();
});
}

View File

@ -15,6 +15,7 @@ serde = { version = "1.0", features = ["derive"] }
validator = "0.12.0"
rand = { version = "0.8", features=["std_rng"] }
unicode-segmentation = "1.7.1"
log = "0.4.14"
[dev-dependencies]
quickcheck = "0.9.2"

View File

@ -4,7 +4,10 @@ use derive_more::Display;
pub enum UserEvent {
#[display(fmt = "AuthCheck")]
AuthCheck = 0,
#[display(fmt = "SignIn")]
SignIn = 1,
#[display(fmt = "SignUp")]
SignUp = 2,
#[display(fmt = "SignOut")]
SignOut = 3,
}

View File

@ -12,7 +12,16 @@ use std::convert::TryInto;
name = %data.name
)
)]
pub async fn user_check(data: In<UserData>) -> Out<UserData> { panic!("") }
pub async fn user_check(data: In<UserData>) -> Result<Out<UserStatus>, String> {
let user: User = data.into_inner().try_into()?;
Ok(UserStatus { is_login: false }.into())
}
#[derive(serde::Serialize)]
pub struct UserStatus {
is_login: bool,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct UserData {
@ -20,6 +29,10 @@ pub struct UserData {
email: String,
}
impl UserData {
pub fn new(name: String, email: String) -> Self { Self { name, email } }
}
impl TryInto<User> for UserData {
type Error = String;

View File

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

View File

@ -1,5 +1,13 @@
mod domain;
mod error;
mod event;
pub mod event;
mod handlers;
pub mod module;
pub mod prelude {
pub use crate::{
domain::*,
event::{UserEvent::*, *},
handlers::auth::*,
};
}

View File

@ -1,5 +1,5 @@
# https://rust-lang.github.io/rustfmt/?version=master&search=
max_width = 120
max_width = 100
tab_spaces = 4
fn_single_line = true
match_block_trailing_comma = true