config service and handle & add test

This commit is contained in:
appflowy 2021-06-24 23:37:45 +08:00
parent 4d91ed147d
commit 3b10e3c101
12 changed files with 178 additions and 92 deletions

View File

@ -13,3 +13,7 @@ futures-channel = "0.3.15"
futures = "0.3.15"
futures-util = "0.3.15"
bytes = "0.5"
[dev-dependencies]
tokio = { version = "1", features = ["full"] }

View 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) }

View File

@ -0,0 +1,2 @@
pub mod container;
pub mod payload;

View File

@ -1,16 +1,35 @@
use crate::error::Error;
use crate::payload::Payload;
use crate::request::FlowyRequest;
use crate::response::{FlowyResponse, Responder};
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
use crate::util::ready::*;
use crate::{
error::Error,
payload::Payload,
request::FlowyRequest,
response::{FlowyResponse, Responder},
service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
util::ready::*,
};
use futures_core::ready;
use paste::paste;
use pin_project::pin_project;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{
future::Future,
marker::PhantomData,
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>);
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 InitError = InitErr;
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> =
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>
where
@ -54,9 +81,7 @@ where
type Error = S::Error;
type Future = S::Future;
fn call(&self, request: Req) -> S::Future {
(**self).call(request)
}
fn call(&self, request: Req) -> S::Future { (**self).call(request) }
}
struct ServiceWrapper<S> {
@ -64,9 +89,7 @@ struct ServiceWrapper<S> {
}
impl<S> ServiceWrapper<S> {
fn new(inner: S) -> Self {
Self { inner }
}
fn new(inner: S) -> Self { Self { inner } }
}
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
@ -76,11 +99,9 @@ where
{
type Response = Res;
type Error = Err;
type Future = BoxFuture<Result<Res, Err>>;
type Future = LocalBoxFuture<'static, Result<Res, Err>>;
fn call(&self, req: Req) -> Self::Future {
Box::pin(self.inner.call(req))
}
fn call(&self, req: Req) -> Self::Future { Box::pin(self.inner.call(req)) }
}
struct FactoryWrapper<SF>(SF);
@ -98,41 +119,13 @@ where
{
type Response = Res;
type Error = Err;
// type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
type Service = BoxService<Req, Res, Err>;
type InitError = InitErr;
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 {
let f = self.0.new_service(cfg);
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>>,
>,
>;

View File

@ -1,8 +1,16 @@
use crate::error::Error;
use crate::handler::{boxed, BoxServiceFactory, FromRequest, Handler, HandlerService};
use crate::response::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
use std::future::Future;
use crate::{
error::Error,
handler::{boxed, BoxServiceFactory, Handler, HandlerService},
request::FromRequest,
response::Responder,
service::{ServiceRequest, ServiceResponse},
};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub struct HandlerDispatch {
service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
@ -22,15 +30,36 @@ impl HandlerDispatch {
}
}
pub fn not_found() -> String {
"hello".to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extract_string() {
let dispatch = HandlerDispatch::new(not_found);
use crate::{payload::Payload, request::FlowyRequest, service::ServiceFactory};
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
}
}

View File

@ -1,6 +1,6 @@
use crate::error::Error;
use crate::payload::Payload;
use crate::request::FlowyRequest;
use crate::request::{FlowyRequest, FromRequest};
use crate::response::{FlowyResponse, Responder};
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
use crate::util::ready::*;
@ -20,13 +20,6 @@ where
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>
where
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>
where
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!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
}

View File

@ -1,3 +1,4 @@
mod data;
mod error;
mod handler;
mod payload;

View File

@ -1 +1,35 @@
use crate::{
error::Error,
payload::Payload,
util::ready::{ready, Ready},
};
use std::future::Future;
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())) }
}

View File

@ -1,7 +1,8 @@
use crate::error::Error;
use crate::request::FlowyRequest;
use crate::response::FlowyResponseBuilder;
use crate::response::Responder;
use crate::{
error::Error,
request::FlowyRequest,
response::{FlowyResponseBuilder, Responder},
};
use std::future::Future;
#[derive(Clone, Copy)]
@ -48,19 +49,13 @@ impl FlowyResponse {
impl Responder for FlowyResponse {
#[inline]
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
self
}
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse { self }
}
impl std::convert::Into<ResponseData> for String {
fn into(self) -> ResponseData {
ResponseData::Bytes(self.into_bytes())
}
fn into(self) -> ResponseData { ResponseData::Bytes(self.into_bytes()) }
}
impl std::convert::Into<ResponseData> for &str {
fn into(self) -> ResponseData {
self.to_string().into()
}
fn into(self) -> ResponseData { self.to_string().into() }
}

View File

@ -28,6 +28,13 @@ pub struct ServiceRequest {
}
impl ServiceRequest {
pub fn new(req: FlowyRequest, payload: Payload) -> Self {
Self {
req, payload,
}
}
#[inline]
pub fn into_parts(self) -> (FlowyRequest, Payload) {
(self.req, self.payload)

View File

@ -6,7 +6,6 @@ match_block_trailing_comma = true
normalize_comments = true
wrap_comments = true
merge_imports = true
reorder_impl_items = true
use_field_init_shorthand = true
use_try_shorthand = true
normalize_doc_attributes = true