Add request hooks to the Serve trait.

This allows plugging in horizontal functionality, such as authorization,
throttling, or latency recording, that should run before and/or after
execution of every request, regardless of the request type.

The tracing example is updated to show off both client stubs as well as
server hooks.

As part of this change, there were some changes to the Serve trait:

1. Serve's output type is now a Result<Response, ServerError>..
   Serve previously did not allow returning ServerErrors, which
   prevented using Serve for horizontal functionality like throttling or
   auth. Now, Serve's output type is Result<Resp, ServerError>, making
   Serve a more natural integration point for horizontal capabilities.
2. Serve's generic Request type changed to an associated type. The
   primary benefit of the generic type is that it allows one type to
   impl a trait multiple times (for example, u64 impls TryFrom<usize>,
   TryFrom<u128>, etc.). In the case of Serve impls, while it is
   theoretically possible to contrive a type that could serve multiple
   request types, in practice I don't expect that to be needed.  Most
   users will use the Serve impl generated by #[tarpc::service], which
   only ever serves one type of request.
This commit is contained in:
Tim Kuehn
2022-11-07 18:37:58 -08:00
committed by Tim
parent 324df5cd15
commit 7c5afa97bb
10 changed files with 781 additions and 77 deletions

View File

@@ -548,9 +548,10 @@ impl<'a> ServiceGenerator<'a> {
} = self;
quote! {
impl<S> tarpc::server::Serve<#request_ident> for #server_ident<S>
impl<S> tarpc::server::Serve for #server_ident<S>
where S: #service_ident
{
type Req = #request_ident;
type Resp = #response_ident;
type Fut = #response_fut_ident<S>;
@@ -670,10 +671,10 @@ impl<'a> ServiceGenerator<'a> {
quote! {
impl<S: #service_ident> std::future::Future for #response_fut_ident<S> {
type Output = #response_ident;
type Output = Result<#response_ident, tarpc::ServerError>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>)
-> std::task::Poll<#response_ident>
-> std::task::Poll<Result<#response_ident, tarpc::ServerError>>
{
unsafe {
match std::pin::Pin::get_unchecked_mut(self) {
@@ -681,7 +682,8 @@ impl<'a> ServiceGenerator<'a> {
#response_fut_ident::#camel_case_idents(resp) =>
std::pin::Pin::new_unchecked(resp)
.poll(cx)
.map(#response_ident::#camel_case_idents),
.map(#response_ident::#camel_case_idents)
.map(Ok),
)*
}
}