pub trait Serve {
type Req;
type Resp;
// Required method
async fn serve(
self,
ctx: Context,
req: Self::Req
) -> Result<Self::Resp, ServerError>;
// Provided methods
fn method(&self, _request: &Self::Req) -> Option<&'static str> { ... }
fn before<Hook>(self, hook: Hook) -> BeforeRequestHook<Self, Hook>
where Hook: BeforeRequest<Self::Req>,
Self: Sized { ... }
fn after<Hook>(self, hook: Hook) -> AfterRequestHook<Self, Hook>
where Hook: AfterRequest<Self::Resp>,
Self: Sized { ... }
fn before_and_after<Hook>(
self,
hook: Hook
) -> BeforeAndAfterRequestHook<Self::Req, Self::Resp, Self, Hook>
where Hook: BeforeRequest<Self::Req> + AfterRequest<Self::Resp>,
Self: Sized { ... }
}
Expand description
Equivalent to a FnOnce(Req) -> impl Future<Output = Resp>
.
Required Associated Types§
Required Methods§
Provided Methods§
sourcefn method(&self, _request: &Self::Req) -> Option<&'static str>
fn method(&self, _request: &Self::Req) -> Option<&'static str>
Extracts a method name from the request.
sourcefn before<Hook>(self, hook: Hook) -> BeforeRequestHook<Self, Hook>
fn before<Hook>(self, hook: Hook) -> BeforeRequestHook<Self, Hook>
Runs a hook before execution of the request.
If the hook returns an error, the request will not be executed and the error will be returned instead.
The hook can also modify the request context. This could be used, for example, to enforce a maximum deadline on all requests.
Any type that implements BeforeRequest
can be used as the hook. Types that implement
FnMut(&mut Context, &RequestType) -> impl Future<Output = Result<(), ServerError>>
can
also be used.
Example
use futures::{executor::block_on, future};
use tarpc::{context, ServerError, server::{Serve, serve}};
use std::io;
let serve = serve(|_ctx, i| async move { Ok(i + 1) })
.before(|_ctx: &mut context::Context, req: &i32| {
future::ready(
if *req == 1 {
Err(ServerError::new(
io::ErrorKind::Other,
format!("I don't like {req}")))
} else {
Ok(())
})
});
let response = serve.serve(context::current(), 1);
assert!(block_on(response).is_err());
sourcefn after<Hook>(self, hook: Hook) -> AfterRequestHook<Self, Hook>
fn after<Hook>(self, hook: Hook) -> AfterRequestHook<Self, Hook>
Runs a hook after completion of a request.
The hook can modify the request context and the response.
Any type that implements AfterRequest
can be used as the hook. Types that implement
FnMut(&mut Context, &mut Result<ResponseType, ServerError>) -> impl Future<Output = ()>
can also be used.
Example
use futures::{executor::block_on, future};
use tarpc::{context, ServerError, server::{Serve, serve}};
use std::io;
let serve = serve(
|_ctx, i| async move {
if i == 1 {
Err(ServerError::new(
io::ErrorKind::Other,
format!("{i} is the loneliest number")))
} else {
Ok(i + 1)
}
})
.after(|_ctx: &mut context::Context, resp: &mut Result<i32, ServerError>| {
if let Err(e) = resp {
eprintln!("server error: {e:?}");
}
future::ready(())
});
let response = serve.serve(context::current(), 1);
assert!(block_on(response).is_err());
sourcefn before_and_after<Hook>(
self,
hook: Hook
) -> BeforeAndAfterRequestHook<Self::Req, Self::Resp, Self, Hook>
fn before_and_after<Hook>( self, hook: Hook ) -> BeforeAndAfterRequestHook<Self::Req, Self::Resp, Self, Hook>
Runs a hook before and after execution of the request.
If the hook returns an error, the request will not be executed and the error will be returned instead.
The hook can also modify the request context and the response. This could be used, for example, to enforce a maximum deadline on all requests.
Example
use futures::{executor::block_on, future};
use tarpc::{
context, ServerError, server::{Serve, serve, request_hook::{BeforeRequest, AfterRequest}}
};
use std::{io, time::Instant};
struct PrintLatency(Instant);
impl<Req> BeforeRequest<Req> for PrintLatency {
async fn before(&mut self, _: &mut context::Context, _: &Req) -> Result<(), ServerError> {
self.0 = Instant::now();
Ok(())
}
}
impl<Resp> AfterRequest<Resp> for PrintLatency {
async fn after(
&mut self,
_: &mut context::Context,
_: &mut Result<Resp, ServerError>,
) {
tracing::info!("Elapsed: {:?}", self.0.elapsed());
}
}
let serve = serve(|_ctx, i| async move {
Ok(i + 1)
}).before_and_after(PrintLatency(Instant::now()));
let response = serve.serve(context::current(), 1);
assert!(block_on(response).is_ok());