#async-networking #async-io #non-blocking #async #service #future #client-server

motore

Motore is a library of modular and reusable components for building robust clients and servers. Motore is greatly inspired by Tower.

10 releases

0.4.1 Apr 3, 2024
0.4.0 Oct 23, 2023
0.3.3 Apr 13, 2023
0.3.2 Feb 15, 2023
0.0.0 Jun 7, 2022

#59 in Asynchronous

Download history 2310/week @ 2024-08-12 1971/week @ 2024-08-19 1356/week @ 2024-08-26 1906/week @ 2024-09-02 1578/week @ 2024-09-09 1118/week @ 2024-09-16 1641/week @ 2024-09-23 533/week @ 2024-09-30 1278/week @ 2024-10-07 1024/week @ 2024-10-14 1511/week @ 2024-10-21 1898/week @ 2024-10-28 1300/week @ 2024-11-04 1653/week @ 2024-11-11 1625/week @ 2024-11-18 2172/week @ 2024-11-25

6,804 downloads per month
Used in 14 crates (5 directly)

MIT/Apache

57KB
1K SLoC

Motore

Crates.io Documentation License Build Status

Motore is an async middleware abstraction powered by AFIT and RPITIT.

Around Motore, we build modular and reusable components for building robust networking clients and servers.

Motore is greatly inspired by Tower.

Overview

Motore uses AFIT and RPITIT to reduce the mental burden of writing asynchronous code, especially to avoid the overhead of Box to make people less anxious.

The core abstraciton of Motore is the Service trait:

pub trait Service<Cx, Request> {
    /// Responses given by the service.
    type Response;
    /// Errors produced by the service.
    type Error;

    /// Process the request and return the response asynchronously.
    async fn call(&self, cx: &mut Cx, req: Request) -> Result<Self::Response, Self::Error>;
}

Getting Started

Combing AFIT and RPITIT together, we can write asynchronous code in a very concise and readable way.

pub struct Timeout<S> {
    inner: S,
    duration: Duration,
}

impl<Cx, Req, S> Service<Cx, Req> for Timeout<S>
where
    Req: 'static + Send,
    S: Service<Cx, Req> + 'static + Send + Sync,
    Cx: 'static + Send,
    S::Error: Send + Sync + Into<BoxError>,
{
    type Response = S::Response;

    type Error = BoxError;

    async fn call(&self, cx: &mut Cx, req: Req) -> Result<Self::Response, Self::Error> {
        let sleep = tokio::time::sleep(self.duration);
        tokio::select! {
            r = self.inner.call(cx, req) => {
                r.map_err(Into::into)
            },
            _ = sleep => Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "service time out").into()),
        }
    }
}

We also provided the #[motore::service] macro to make writing a Serivce more async-native:

use motore::service;

pub struct S<I> {
    inner: I,
}

#[service]
impl<Cx, Req, I> Service<Cx, Req> for S<I>
where
   Req: Send + 'static,
   I: Service<Cx, Req> + Send + 'static + Sync,
   Cx: Send + 'static,
{
    async fn call(&self, cx: &mut Cx, req: Req) -> Result<I::Response, I::Error> {
        self.inner.call(cx, req).await
    }
}

FAQ

Where's the poll_ready(a.k.a. backpressure)?

https://www.cloudwego.io/zh/docs/motore/faq/q1_pull_ready/

License

Motore is dual-licensed under the MIT license and the Apache License (Version 2.0).

See LICENSE-MIT and LICENSE-APACHE for details.

Credits

We have used some third party components, and we thank them for their work.

For the full list, you may refer to the CREDITS.md file.

Community

Dependencies

~3–10MB
~80K SLoC