mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
config service and handle & add test
This commit is contained in:
parent
4d91ed147d
commit
3b10e3c101
12 changed files with 178 additions and 92 deletions
|
@ -12,4 +12,8 @@ paste = "1"
|
||||||
futures-channel = "0.3.15"
|
futures-channel = "0.3.15"
|
||||||
futures = "0.3.15"
|
futures = "0.3.15"
|
||||||
futures-util = "0.3.15"
|
futures-util = "0.3.15"
|
||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
28
rust-lib/flowy-sys/src/data/container.rs
Normal file
28
rust-lib/flowy-sys/src/data/container.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
collections::HashMap,
|
||||||
|
fmt,
|
||||||
|
mem,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DataContainer {
|
||||||
|
map: HashMap<TypeId, Box<dyn Any>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataContainer {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> DataContainer {
|
||||||
|
DataContainer {
|
||||||
|
map: HashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
|
||||||
|
self.map
|
||||||
|
.insert(TypeId::of::<T>(), Box::new(val))
|
||||||
|
.and_then(downcast_owned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast_owned<T: 'static>(boxed: Box<dyn Any>) -> Option<T> { boxed.downcast().ok().map(|boxed| *boxed) }
|
2
rust-lib/flowy-sys/src/data/mod.rs
Normal file
2
rust-lib/flowy-sys/src/data/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod container;
|
||||||
|
pub mod payload;
|
|
@ -1,16 +1,35 @@
|
||||||
use crate::error::Error;
|
use crate::{
|
||||||
use crate::payload::Payload;
|
error::Error,
|
||||||
use crate::request::FlowyRequest;
|
payload::Payload,
|
||||||
use crate::response::{FlowyResponse, Responder};
|
request::FlowyRequest,
|
||||||
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
|
response::{FlowyResponse, Responder},
|
||||||
use crate::util::ready::*;
|
service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
||||||
|
util::ready::*,
|
||||||
|
};
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use std::future::Future;
|
use std::{
|
||||||
use std::marker::PhantomData;
|
future::Future,
|
||||||
use std::pin::Pin;
|
marker::PhantomData,
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
|
pub fn factory<SF, Req>(factory: SF) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error, SF::InitError>
|
||||||
|
where
|
||||||
|
SF: ServiceFactory<Req> + 'static,
|
||||||
|
Req: 'static,
|
||||||
|
SF::Response: 'static,
|
||||||
|
SF::Service: 'static,
|
||||||
|
SF::Future: 'static,
|
||||||
|
SF::Error: 'static,
|
||||||
|
SF::InitError: 'static,
|
||||||
|
{
|
||||||
|
BoxServiceFactory(Box::new(FactoryWrapper(factory)))
|
||||||
|
}
|
||||||
|
|
||||||
pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
|
pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
|
||||||
impl<C, Req, Res, Err, InitErr> ServiceFactory<Req> for BoxServiceFactory<C, Req, Res, Err, InitErr>
|
impl<C, Req, Res, Err, InitErr> ServiceFactory<Req> for BoxServiceFactory<C, Req, Res, Err, InitErr>
|
||||||
|
@ -25,17 +44,25 @@ where
|
||||||
type Service = BoxService<Req, Res, Err>;
|
type Service = BoxService<Req, Res, Err>;
|
||||||
type InitError = InitErr;
|
type InitError = InitErr;
|
||||||
type Config = C;
|
type Config = C;
|
||||||
|
type Future = LocalBoxFuture<'static, Result<Self::Service, InitErr>>;
|
||||||
|
|
||||||
type Future = BoxFuture<Result<Self::Service, InitErr>>;
|
fn new_service(&self, cfg: C) -> Self::Future { self.0.new_service(cfg) }
|
||||||
|
|
||||||
fn new_service(&self, cfg: C) -> Self::Future {
|
|
||||||
self.0.new_service(cfg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
|
type Inner<C, Req, Res, Err, InitErr> = Box<
|
||||||
|
dyn ServiceFactory<
|
||||||
|
Req,
|
||||||
|
Config = C,
|
||||||
|
Response = Res,
|
||||||
|
Error = Err,
|
||||||
|
InitError = InitErr,
|
||||||
|
Service = BoxService<Req, Res, Err>,
|
||||||
|
Future = LocalBoxFuture<'static, Result<BoxService<Req, Res, Err>, InitErr>>,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
pub type BoxService<Req, Res, Err> =
|
pub type BoxService<Req, Res, Err> =
|
||||||
Box<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<Result<Res, Err>>>>;
|
Box<dyn Service<Req, Response = Res, Error = Err, Future = LocalBoxFuture<'static, Result<Res, Err>>>>;
|
||||||
|
|
||||||
pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -54,9 +81,7 @@ where
|
||||||
type Error = S::Error;
|
type Error = S::Error;
|
||||||
type Future = S::Future;
|
type Future = S::Future;
|
||||||
|
|
||||||
fn call(&self, request: Req) -> S::Future {
|
fn call(&self, request: Req) -> S::Future { (**self).call(request) }
|
||||||
(**self).call(request)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ServiceWrapper<S> {
|
struct ServiceWrapper<S> {
|
||||||
|
@ -64,9 +89,7 @@ struct ServiceWrapper<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ServiceWrapper<S> {
|
impl<S> ServiceWrapper<S> {
|
||||||
fn new(inner: S) -> Self {
|
fn new(inner: S) -> Self { Self { inner } }
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
|
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
|
||||||
|
@ -76,11 +99,9 @@ where
|
||||||
{
|
{
|
||||||
type Response = Res;
|
type Response = Res;
|
||||||
type Error = Err;
|
type Error = Err;
|
||||||
type Future = BoxFuture<Result<Res, Err>>;
|
type Future = LocalBoxFuture<'static, Result<Res, Err>>;
|
||||||
|
|
||||||
fn call(&self, req: Req) -> Self::Future {
|
fn call(&self, req: Req) -> Self::Future { Box::pin(self.inner.call(req)) }
|
||||||
Box::pin(self.inner.call(req))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FactoryWrapper<SF>(SF);
|
struct FactoryWrapper<SF>(SF);
|
||||||
|
@ -98,41 +119,13 @@ where
|
||||||
{
|
{
|
||||||
type Response = Res;
|
type Response = Res;
|
||||||
type Error = Err;
|
type Error = Err;
|
||||||
// type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
|
|
||||||
type Service = BoxService<Req, Res, Err>;
|
type Service = BoxService<Req, Res, Err>;
|
||||||
type InitError = InitErr;
|
type InitError = InitErr;
|
||||||
type Config = Cfg;
|
type Config = Cfg;
|
||||||
type Future = BoxFuture<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
||||||
let f = self.0.new_service(cfg);
|
let f = self.0.new_service(cfg);
|
||||||
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
|
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn factory<SF, Req>(
|
|
||||||
factory: SF,
|
|
||||||
) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error, SF::InitError>
|
|
||||||
where
|
|
||||||
SF: ServiceFactory<Req> + 'static,
|
|
||||||
Req: 'static,
|
|
||||||
SF::Response: 'static,
|
|
||||||
SF::Service: 'static,
|
|
||||||
SF::Future: 'static,
|
|
||||||
SF::Error: 'static,
|
|
||||||
SF::InitError: 'static,
|
|
||||||
{
|
|
||||||
BoxServiceFactory(Box::new(FactoryWrapper(factory)))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Inner<C, Req, Res, Err, InitErr> = Box<
|
|
||||||
dyn ServiceFactory<
|
|
||||||
Req,
|
|
||||||
Config = C,
|
|
||||||
Response = Res,
|
|
||||||
Error = Err,
|
|
||||||
InitError = InitErr,
|
|
||||||
Service = BoxService<Req, Res, Err>,
|
|
||||||
Future = BoxFuture<Result<BoxService<Req, Res, Err>, InitErr>>,
|
|
||||||
>,
|
|
||||||
>;
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
use crate::error::Error;
|
use crate::{
|
||||||
use crate::handler::{boxed, BoxServiceFactory, FromRequest, Handler, HandlerService};
|
error::Error,
|
||||||
use crate::response::Responder;
|
handler::{boxed, BoxServiceFactory, Handler, HandlerService},
|
||||||
use crate::service::{ServiceRequest, ServiceResponse};
|
request::FromRequest,
|
||||||
use std::future::Future;
|
response::Responder,
|
||||||
|
service::{ServiceRequest, ServiceResponse},
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct HandlerDispatch {
|
pub struct HandlerDispatch {
|
||||||
service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
|
service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
|
||||||
|
@ -22,15 +30,36 @@ impl HandlerDispatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_found() -> String {
|
|
||||||
"hello".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
use crate::{payload::Payload, request::FlowyRequest, service::ServiceFactory};
|
||||||
fn extract_string() {
|
|
||||||
let dispatch = HandlerDispatch::new(not_found);
|
pub async fn no_params() -> String {
|
||||||
|
println!("no params");
|
||||||
|
"hello".to_string()
|
||||||
|
}
|
||||||
|
#[tokio::test]
|
||||||
|
async fn extract_no_params() {
|
||||||
|
let dispatch = HandlerDispatch::new(no_params);
|
||||||
|
let resp = response_from_dispatch(dispatch).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn one_params(s: String) -> String {
|
||||||
|
println!("one params");
|
||||||
|
"hello".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn extract_one_params() {
|
||||||
|
let dispatch = HandlerDispatch::new(one_params);
|
||||||
|
let resp = response_from_dispatch(dispatch).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn response_from_dispatch(dispatch: HandlerDispatch) -> ServiceResponse {
|
||||||
|
let service = dispatch.service.new_service(()).await.unwrap();
|
||||||
|
let service_request = ServiceRequest::new(FlowyRequest::default(), Payload::None);
|
||||||
|
let resp = service.call(service_request).await.unwrap();
|
||||||
|
resp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
use crate::request::FlowyRequest;
|
use crate::request::{FlowyRequest, FromRequest};
|
||||||
use crate::response::{FlowyResponse, Responder};
|
use crate::response::{FlowyResponse, Responder};
|
||||||
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
|
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
|
||||||
use crate::util::ready::*;
|
use crate::util::ready::*;
|
||||||
|
@ -20,13 +20,6 @@ where
|
||||||
fn call(&self, param: T) -> R;
|
fn call(&self, param: T) -> R;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromRequest: Sized {
|
|
||||||
type Error: Into<Error>;
|
|
||||||
type Future: Future<Output = Result<Self, Self::Error>>;
|
|
||||||
|
|
||||||
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HandlerService<H, T, R>
|
pub struct HandlerService<H, T, R>
|
||||||
where
|
where
|
||||||
H: Handler<T, R>,
|
H: Handler<T, R>,
|
||||||
|
@ -87,7 +80,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HandlerService is both it's ServiceFactory and Service Type.
|
|
||||||
impl<H, T, R> Service<ServiceRequest> for HandlerService<H, T, R>
|
impl<H, T, R> Service<ServiceRequest> for HandlerService<H, T, R>
|
||||||
where
|
where
|
||||||
H: Handler<T, R>,
|
H: Handler<T, R>,
|
||||||
|
@ -247,3 +239,5 @@ mod m {
|
||||||
tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
|
tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
|
||||||
tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
|
tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod data;
|
||||||
mod error;
|
mod error;
|
||||||
mod handler;
|
mod handler;
|
||||||
mod payload;
|
mod payload;
|
||||||
|
|
|
@ -1 +1,35 @@
|
||||||
|
use crate::{
|
||||||
|
error::Error,
|
||||||
|
payload::Payload,
|
||||||
|
util::ready::{ready, Ready},
|
||||||
|
};
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
pub struct FlowyRequest {}
|
pub struct FlowyRequest {}
|
||||||
|
|
||||||
|
impl std::default::Default for FlowyRequest {
|
||||||
|
fn default() -> Self { Self {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromRequest: Sized {
|
||||||
|
type Error: Into<Error>;
|
||||||
|
type Future: Future<Output = Result<Self, Self::Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl FromRequest for () {
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Ready<Result<(), Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future { ready(Ok(())) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl FromRequest for String {
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Ready<Result<String, Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future { ready(Ok("".to_string())) }
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::error::Error;
|
use crate::{
|
||||||
use crate::request::FlowyRequest;
|
error::Error,
|
||||||
use crate::response::FlowyResponseBuilder;
|
request::FlowyRequest,
|
||||||
use crate::response::Responder;
|
response::{FlowyResponseBuilder, Responder},
|
||||||
|
};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -48,19 +49,13 @@ impl FlowyResponse {
|
||||||
|
|
||||||
impl Responder for FlowyResponse {
|
impl Responder for FlowyResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
|
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<ResponseData> for String {
|
impl std::convert::Into<ResponseData> for String {
|
||||||
fn into(self) -> ResponseData {
|
fn into(self) -> ResponseData { ResponseData::Bytes(self.into_bytes()) }
|
||||||
ResponseData::Bytes(self.into_bytes())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<ResponseData> for &str {
|
impl std::convert::Into<ResponseData> for &str {
|
||||||
fn into(self) -> ResponseData {
|
fn into(self) -> ResponseData { self.to_string().into() }
|
||||||
self.to_string().into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,13 @@ pub struct ServiceRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceRequest {
|
impl ServiceRequest {
|
||||||
|
|
||||||
|
pub fn new(req: FlowyRequest, payload: Payload) -> Self {
|
||||||
|
Self {
|
||||||
|
req, payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_parts(self) -> (FlowyRequest, Payload) {
|
pub fn into_parts(self) -> (FlowyRequest, Payload) {
|
||||||
(self.req, self.payload)
|
(self.req, self.payload)
|
||||||
|
|
|
@ -6,7 +6,6 @@ match_block_trailing_comma = true
|
||||||
normalize_comments = true
|
normalize_comments = true
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
merge_imports = true
|
merge_imports = true
|
||||||
reorder_impl_items = true
|
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
use_try_shorthand = true
|
use_try_shorthand = true
|
||||||
normalize_doc_attributes = true
|
normalize_doc_attributes = true
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue