summer-boot 1.0.0

summer boot
Documentation
//! HTTP server
use crate::gateway;
use crate::log;
use crate::tcp;
use crate::utils;
use crate::{Request, Route};
use super::endpoint::Endpoint;

use async_std::io;
use async_std::sync::Arc;

use gateway::router::{Router, Selection};
use tcp::{Listener, ToListener};
use utils::middleware::{Middleware, Next};

// use summer_boot_autoconfigure;

/// HTTP服务器。
///
/// 服务器由 *state*, *endpoints* 和 *middleware* 组成。
///
/// - 服务器状态是用户定义的,通过 [`summer_boot::Server::with_state`] 函数使用. 这个
/// 状态可以用于所有应用 endpoints 共享引用.
///
/// - Endpoints 提供与指定URL [`summer_boot::Server::at`] 创建一个 *路由*
/// 然后可以用于绑定注册到 endpoints
/// 对于指定HTTP请求类型进行使用
///
/// - Middleware 通过附加request或
/// response 处理, 例如压缩、默认请求头或日志记录。到
/// 中间件添加到应用程序中,使用 [`summer_boot::Server::middleware`] 方法.
pub struct Server<State> {
    router: Arc<Router<State>>,
    state: State,
    /// 保存 middleware 堆栈 这里用了多线程引用计数.
    ///
    /// Vec允许我们在运行时添加中间件。
    /// 内部 Arc-s 允许在内部克隆 MiddlewareEndpoint-s 。
    /// 在这里不在Vec使用互斥体,因为在执行期间添加中间件应该是一个错误。
    #[allow(clippy::rc_buffer)]
    middleware: Arc<Vec<Arc<dyn Middleware<State>>>>,
}

impl Server<()> {
    /// 创建一个summer boot web2 server.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use async_std::task::block_on;
    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
    /// #
    /// let mut app = summer_boot::new();
    /// app.at("/").get(|_| async { Ok("Hello, world!") });
    /// app.listen("127.0.0.1:8080").await?;
    /// #
    /// # Ok(()) }) }
    /// ```
    #[must_use]
    pub fn new() -> Self {
        Self::with_state(())
    }

    /// 创建一个summer boot web2 server.
    ///
    /// 默认开启日志记录
    /// 读取yml然后绑定监听
    ///
    /// 目前把他移动到macro扫描里面去了
    pub fn run() -> Self {
        log::start();
        let server = Self::with_state(());

        // let mut listener_addr = String::from("0.0.0.0:");

        // let config = summer_boot_autoconfigure::load_conf();

        // if let Some(config) = config {
        //     let read_server = serde_json::to_string(&config.server).unwrap();

        //     let v: Value = serde_json::from_str(&read_server).unwrap();
        //     let port = v["port"].to_string();
        //     listener_addr.push_str(&port);
        // }

        // server.listen(listener_addr).await.unwrap();

        server
    }
}

impl Default for Server<()> {
    fn default() -> Self {
        Self::new()
    }
}

impl<State> Server<State>
where
    State: Clone + Send + Sync + 'static,
{
    /// 创建一个可以共享应用程序作用域状态到新服务.
    ///
    // /应用程序范围的状态对于存储有用
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use async_std::task::block_on;
    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
    /// #
    /// use summer_boot::Request;
    ///
    /// /// 共享应用程序状态
    /// #[derive(Clone)]
    /// struct State {
    ///     name: String,
    /// }
    ///
    /// // 定义状态新的一个实例
    /// let state = State {
    ///     name: "James".to_string()
    /// };
    ///
    /// // 使用状态初始化应用程序
    /// let mut app = summer_boot::with_state(state);
    /// app.at("/").get(|req: Request<State>| async move {
    ///     Ok(format!("Hello, {}!", &req.state().name))
    /// });
    /// app.listen("127.0.0.1:8080").await?;
    /// #
    /// # Ok(()) }) }
    /// ```
    pub fn with_state(state: State) -> Self {
        Self {
            router: Arc::new(Router::new()),
            middleware: Arc::new(vec![
                // 暂时没有使用到cookies
                Arc::new(log::LoggingSystem::new()),
            ]),
            state,
        }
    }

    /// 在给定的 `path`(相对于根)处添加新路由。
    ///
    /// 路由意味着将HTTP请求映射到endpoints。
    /// 一种“目录”方法,可以方便地查看总体
    /// 应用程序结构。Endpoints仅由path和HTTP方法选择
    /// 请求:路径决定资源和HTTP请求所选资源的各个endpoints。
    ///
    /// #Example:
    ///
    /// ```rust,no_run
    /// # let mut app = summer_boot::new();
    /// app.at("/").get(|_| async { Ok("Hello, world!") });
    /// ```
    ///
    /// 路径由零个或多个段组成,即非空字符串,由 '/' 分隔。
    ///
    /// 或者可以使用通配符
    /// `*path` 代表使用通配符配置路由
    /// 以下是一些基于HTTP的endpoints 路由选择的示例:
    ///
    /// ```rust,no_run
    /// # let mut app = summer_boot::new();
    /// app.at("/");
    /// app.at("/hello");
    /// app.at("add_two/:num");
    /// app.at("files/:user/*");
    /// app.at("static/*path");
    /// app.at("static/:context/:");
    /// ```
    ///
    /// 没有备用路由匹配,即资源已满
    /// 匹配和没有匹配,意味着添加资源的顺序没有
    pub fn at<'a>(&'a mut self, path: &str) -> Route<'a, State> {
        let router = Arc::get_mut(&mut self.router).expect("服务器启动后无法注册路由");
        Route::new(router, path.to_owned())
    }

    /// 向应用程序添加中间件。
    ///
    /// 中间件提供请求/响应
    /// 日志记录或标题修改。中间件在处理请求时被调用,并且可以
    /// 继续处理(可能修改响应)或立即返回响应
    /// 响应。有关详细信息,请参考 [`Middleware`] trait
    ///
    /// 中间件只能在应用程序的 `顶层` 添加,并使用应用顺序
    pub fn with<M>(&mut self, middleware: M) -> &mut Self
    where
        M: Middleware<State>,
    {
        log::trace!("正在添加中间件 {}", middleware.name());
        let m = Arc::get_mut(&mut self.middleware)
            .expect("服务器启动后无法注册中间件");
        m.push(Arc::new(middleware));
        self
    }

    /// 使用提供的侦听器异步为应用程序提供服务。
    ///
    /// 这是调用 `summer_boot::Server::bind`, 记录`ListenInfo` 实例
    /// 通过实例 `Listener::info`, 然后调用 `Listener::accept`.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use async_std::task::block_on;
    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
    /// #
    /// let mut app = summer_boot::new();
    /// app.at("/").get(|_| async { Ok("Hello, world!") });
    /// app.listen("127.0.0.1:8080").await?;
    /// #
    /// # Ok(()) }) }
    /// ```
    pub async fn listen<L: ToListener<State>>(self, listener: L) -> io::Result<()> {
        let mut listener = listener.to_listener()?;
        listener.bind(self).await?;
        for info in listener.info().iter() {
            log::info!("Server listening on {}", info);
        }
        listener.accept().await?;
        Ok(())
    }

    /// 开发中 todo
    ///
    /// 异步绑定侦听器。
    ///
    /// 绑定侦听器。这将打开网络端口,但没有接受传入的连接。
    /// 应调用 `Listener::listen` 开始连接
    ///
    /// 调用 `Listener::info` 的时候可能出现多个 `ListenInfo` 实例返回
    /// 这在使用例如 `ConcurrentListener` 时很有用
    /// 因为它可以让单个服务器能够侦听多个端口。
    ///
    /// # Examples
    ///
    pub async fn bind<L: ToListener<State>>(
        self,
        listener: L,
    ) -> io::Result<<L as ToListener<State>>::Listener> {
        let mut listener = listener.to_listener()?;
        listener.bind(self).await?;
        Ok(listener)
    }

    /// 响应 `Request`
    ///
    /// 此方法对于直接测试endpoints
    /// 或者通过自定义传输创建服务器。
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # #[async_std::main]
    /// # async fn main() -> http_types::Result<()> {
    /// #
    /// use http_types::{Url, Method, Request, Response};
    ///
    /// let mut app = summer_boot::new();
    /// app.at("/").get(|_| async { Ok("hello world") });
    ///
    /// let req = Request::new(Method::Get, Url::parse("https://example.com")?);
    /// let res: Response = app.respond(req).await?;
    ///
    /// assert_eq!(res.status(), 200);
    /// #
    /// # Ok(()) }
    /// ```
    pub async fn respond<Req, Res>(&self, req: Req) -> http_types::Result<Res>
    where
        Req: Into<http_types::Request>,
        Res: From<http_types::Response>,
    {
        let req = req.into();
        let Self {
            router,
            state,
            middleware,
        } = self.clone();

        let method = req.method().to_owned();
        let Selection { endpoint, params } = router.route(&req.url().path(), method);
        let route_params = vec![params];
        let req = Request::new(state, req, route_params);

        let next = Next {
            endpoint,
            next_middleware: &middleware,
        };

        let res = next.run(req).await;
        let res: http_types::Response = res.into();
        Ok(res.into())
    }

    /// 获取对服务器状态的引用。用于测试和嵌套:
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[derive(Clone)] struct SomeAppState;
    /// let mut app = summer_boot::with_state(SomeAppState);
    /// let mut admin = summer_boot::with_state(app.state().clone());
    /// admin.at("/").get(|_| async { Ok("nested app with cloned state") });
    /// app.at("/").nest(admin);
    /// ```
    pub fn state(&self) -> &State {
        &self.state
    }
}

impl<State: Send + Sync + 'static> std::fmt::Debug for Server<State> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Server").finish()
    }
}

impl<State: Clone> Clone for Server<State> {
    fn clone(&self) -> Self {
        Self {
            router: self.router.clone(),
            state: self.state.clone(),
            middleware: self.middleware.clone(),
        }
    }
}

#[async_trait::async_trait]
impl<State: Clone + Sync + Send + 'static, InnerState: Clone + Sync + Send + 'static>
    Endpoint<State> for Server<InnerState>
{
    async fn call(&self, req: Request<State>) -> crate::Result {
        let Request {
            req,
            mut route_params,
            ..
        } = req;
        let path = req.url().path().to_owned();
        let method = req.method().to_owned();
        let router = self.router.clone();
        let middleware = self.middleware.clone();
        let state = self.state.clone();

        let Selection { endpoint, params } = router.route(&path, method);
        route_params.push(params);
        let req = Request::new(state, req, route_params);

        let next = Next {
            endpoint,
            next_middleware: &middleware,
        };

        Ok(next.run(req).await)
    }
}

#[cfg(test)]
mod test {
    use crate as summer_boot;

    #[test]
    fn allow_nested_server_with_same_state() {
        let inner = summer_boot::new();
        let mut outer = summer_boot::new();
        outer.at("/foo").get(inner);
    }

    #[test]
    fn allow_nested_server_with_different_state() {
        let inner = summer_boot::with_state(1);
        let mut outer = summer_boot::new();
        outer.at("/foo").get(inner);
    }
}