mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-02-23 15:49:54 +01:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9c86ce157 | ||
|
|
d4f579542d | ||
|
|
5011dbe057 | ||
|
|
4aa90ee933 | ||
|
|
eb91000fed | ||
|
|
006a9f3af1 | ||
|
|
a3d00b07da | ||
|
|
d62706e62c | ||
|
|
b92dd154bc | ||
|
|
a6758fd1f9 | ||
|
|
2c241cc809 |
@@ -118,13 +118,8 @@ implement it for our Server struct.
|
|||||||
struct HelloServer;
|
struct HelloServer;
|
||||||
|
|
||||||
impl World for HelloServer {
|
impl World for HelloServer {
|
||||||
// Each defined rpc generates two items in the trait, a fn that serves the RPC, and
|
async fn hello(self, _: context::Context, name: String) -> String {
|
||||||
// an associated type representing the future output by the fn.
|
format!("Hello, {name}!")
|
||||||
|
|
||||||
type HelloFut = Ready<String>;
|
|
||||||
|
|
||||||
fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
|
|
||||||
future::ready(format!("Hello, {name}!"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
- Request hooks are added to the serve trait, so that it's easy to hook in cross-cutting
|
- Request hooks are added to the serve trait, so that it's easy to hook in cross-cutting
|
||||||
functionality look throttling, authorization, etc.
|
functionality like throttling, authorization, etc.
|
||||||
- The Client trait is back! This makes it possible to hook in generic client functionality like load
|
- The Client trait is back! This makes it possible to hook in generic client functionality like load
|
||||||
balancing, retries, etc.
|
balancing, retries, etc.
|
||||||
|
|
||||||
|
|||||||
@@ -220,15 +220,15 @@ impl Parse for DeriveSerde {
|
|||||||
/// Adds the following annotations to the annotated item:
|
/// Adds the following annotations to the annotated item:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// #[derive(tarpc::serde::Serialize, tarpc::serde::Deserialize)]
|
/// #[derive(::tarpc::serde::Serialize, ::tarpc::serde::Deserialize)]
|
||||||
/// #[serde(crate = "tarpc::serde")]
|
/// #[serde(crate = "tarpc::serde")]
|
||||||
/// # struct Foo;
|
/// # struct Foo;
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn derive_serde(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn derive_serde(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let mut gen: proc_macro2::TokenStream = quote! {
|
let mut gen: proc_macro2::TokenStream = quote! {
|
||||||
#[derive(tarpc::serde::Serialize, tarpc::serde::Deserialize)]
|
#[derive(::tarpc::serde::Serialize, ::tarpc::serde::Deserialize)]
|
||||||
#[serde(crate = "tarpc::serde")]
|
#[serde(crate = "::tarpc::serde")]
|
||||||
};
|
};
|
||||||
gen.extend(proc_macro2::TokenStream::from(item));
|
gen.extend(proc_macro2::TokenStream::from(item));
|
||||||
proc_macro::TokenStream::from(gen)
|
proc_macro::TokenStream::from(gen)
|
||||||
@@ -259,8 +259,8 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
let args: &[&[PatType]] = &rpcs.iter().map(|rpc| &*rpc.args).collect::<Vec<_>>();
|
let args: &[&[PatType]] = &rpcs.iter().map(|rpc| &*rpc.args).collect::<Vec<_>>();
|
||||||
let derive_serialize = if derive_serde.0 {
|
let derive_serialize = if derive_serde.0 {
|
||||||
Some(
|
Some(
|
||||||
quote! {#[derive(tarpc::serde::Serialize, tarpc::serde::Deserialize)]
|
quote! {#[derive(::tarpc::serde::Serialize, ::tarpc::serde::Deserialize)]
|
||||||
#[serde(crate = "tarpc::serde")]},
|
#[serde(crate = "::tarpc::serde")]},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -357,7 +357,7 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
)| {
|
)| {
|
||||||
quote! {
|
quote! {
|
||||||
#( #attrs )*
|
#( #attrs )*
|
||||||
async fn #ident(self, context: tarpc::context::Context, #( #args ),*) -> #output;
|
async fn #ident(self, context: ::tarpc::context::Context, #( #args ),*) -> #output;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -365,22 +365,22 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
let stub_doc = format!("The stub trait for service [`{service_ident}`].");
|
let stub_doc = format!("The stub trait for service [`{service_ident}`].");
|
||||||
quote! {
|
quote! {
|
||||||
#( #attrs )*
|
#( #attrs )*
|
||||||
#vis trait #service_ident: Sized {
|
#vis trait #service_ident: ::core::marker::Sized {
|
||||||
#( #rpc_fns )*
|
#( #rpc_fns )*
|
||||||
|
|
||||||
/// Returns a serving function to use with
|
/// Returns a serving function to use with
|
||||||
/// [InFlightRequest::execute](tarpc::server::InFlightRequest::execute).
|
/// [InFlightRequest::execute](::tarpc::server::InFlightRequest::execute).
|
||||||
fn serve(self) -> #server_ident<Self> {
|
fn serve(self) -> #server_ident<Self> {
|
||||||
#server_ident { service: self }
|
#server_ident { service: self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc = #stub_doc]
|
#[doc = #stub_doc]
|
||||||
#vis trait #client_stub_ident: tarpc::client::stub::Stub<Req = #request_ident, Resp = #response_ident> {
|
#vis trait #client_stub_ident: ::tarpc::client::stub::Stub<Req = #request_ident, Resp = #response_ident> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> #client_stub_ident for S
|
impl<S> #client_stub_ident for S
|
||||||
where S: tarpc::client::stub::Stub<Req = #request_ident, Resp = #response_ident>
|
where S: ::tarpc::client::stub::Stub<Req = #request_ident, Resp = #response_ident>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,7 +392,7 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
/// A serving function to use with [tarpc::server::InFlightRequest::execute].
|
/// A serving function to use with [::tarpc::server::InFlightRequest::execute].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#vis struct #server_ident<S> {
|
#vis struct #server_ident<S> {
|
||||||
service: S,
|
service: S,
|
||||||
@@ -414,14 +414,14 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl<S> tarpc::server::Serve for #server_ident<S>
|
impl<S> ::tarpc::server::Serve for #server_ident<S>
|
||||||
where S: #service_ident
|
where S: #service_ident
|
||||||
{
|
{
|
||||||
type Req = #request_ident;
|
type Req = #request_ident;
|
||||||
type Resp = #response_ident;
|
type Resp = #response_ident;
|
||||||
|
|
||||||
fn method(&self, req: &#request_ident) -> Option<&'static str> {
|
fn method(&self, req: &#request_ident) -> ::core::option::Option<&'static str> {
|
||||||
Some(match req {
|
::core::option::Option::Some(match req {
|
||||||
#(
|
#(
|
||||||
#request_ident::#camel_case_idents{..} => {
|
#request_ident::#camel_case_idents{..} => {
|
||||||
#request_names
|
#request_names
|
||||||
@@ -430,12 +430,12 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn serve(self, ctx: tarpc::context::Context, req: #request_ident)
|
async fn serve(self, ctx: ::tarpc::context::Context, req: #request_ident)
|
||||||
-> Result<#response_ident, tarpc::ServerError> {
|
-> ::core::result::Result<#response_ident, ::tarpc::ServerError> {
|
||||||
match req {
|
match req {
|
||||||
#(
|
#(
|
||||||
#request_ident::#camel_case_idents{ #( #arg_pats ),* } => {
|
#request_ident::#camel_case_idents{ #( #arg_pats ),* } => {
|
||||||
Ok(#response_ident::#camel_case_idents(
|
::core::result::Result::Ok(#response_ident::#camel_case_idents(
|
||||||
#service_ident::#method_idents(
|
#service_ident::#method_idents(
|
||||||
self.service, ctx, #( #arg_pats ),*
|
self.service, ctx, #( #arg_pats ),*
|
||||||
).await
|
).await
|
||||||
@@ -503,9 +503,9 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// The client stub that makes RPC calls to the server. All request methods return
|
/// The client stub that makes RPC calls to the server. All request methods return
|
||||||
/// [Futures](std::future::Future).
|
/// [Futures](::core::future::Future).
|
||||||
#vis struct #client_ident<
|
#vis struct #client_ident<
|
||||||
Stub = tarpc::client::Channel<#request_ident, #response_ident>
|
Stub = ::tarpc::client::Channel<#request_ident, #response_ident>
|
||||||
>(Stub);
|
>(Stub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,24 +522,24 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
quote! {
|
quote! {
|
||||||
impl #client_ident {
|
impl #client_ident {
|
||||||
/// Returns a new client stub that sends requests over the given transport.
|
/// Returns a new client stub that sends requests over the given transport.
|
||||||
#vis fn new<T>(config: tarpc::client::Config, transport: T)
|
#vis fn new<T>(config: ::tarpc::client::Config, transport: T)
|
||||||
-> tarpc::client::NewClient<
|
-> ::tarpc::client::NewClient<
|
||||||
Self,
|
Self,
|
||||||
tarpc::client::RequestDispatch<#request_ident, #response_ident, T>
|
::tarpc::client::RequestDispatch<#request_ident, #response_ident, T>
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: tarpc::Transport<tarpc::ClientMessage<#request_ident>, tarpc::Response<#response_ident>>
|
T: ::tarpc::Transport<::tarpc::ClientMessage<#request_ident>, ::tarpc::Response<#response_ident>>
|
||||||
{
|
{
|
||||||
let new_client = tarpc::client::new(config, transport);
|
let new_client = ::tarpc::client::new(config, transport);
|
||||||
tarpc::client::NewClient {
|
::tarpc::client::NewClient {
|
||||||
client: #client_ident(new_client.client),
|
client: #client_ident(new_client.client),
|
||||||
dispatch: new_client.dispatch,
|
dispatch: new_client.dispatch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Stub> From<Stub> for #client_ident<Stub>
|
impl<Stub> ::core::convert::From<Stub> for #client_ident<Stub>
|
||||||
where Stub: tarpc::client::stub::Stub<
|
where Stub: ::tarpc::client::stub::Stub<
|
||||||
Req = #request_ident,
|
Req = #request_ident,
|
||||||
Resp = #response_ident>
|
Resp = #response_ident>
|
||||||
{
|
{
|
||||||
@@ -570,21 +570,21 @@ impl<'a> ServiceGenerator<'a> {
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl<Stub> #client_ident<Stub>
|
impl<Stub> #client_ident<Stub>
|
||||||
where Stub: tarpc::client::stub::Stub<
|
where Stub: ::tarpc::client::stub::Stub<
|
||||||
Req = #request_ident,
|
Req = #request_ident,
|
||||||
Resp = #response_ident>
|
Resp = #response_ident>
|
||||||
{
|
{
|
||||||
#(
|
#(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#( #method_attrs )*
|
#( #method_attrs )*
|
||||||
#vis fn #method_idents(&self, ctx: tarpc::context::Context, #( #args ),*)
|
#vis fn #method_idents(&self, ctx: ::tarpc::context::Context, #( #args ),*)
|
||||||
-> impl std::future::Future<Output = Result<#return_types, tarpc::client::RpcError>> + '_ {
|
-> impl ::core::future::Future<Output = ::core::result::Result<#return_types, ::tarpc::client::RpcError>> + '_ {
|
||||||
let request = #request_ident::#camel_case_idents { #( #arg_pats ),* };
|
let request = #request_ident::#camel_case_idents { #( #arg_pats ),* };
|
||||||
let resp = self.0.call(ctx, #request_names, request);
|
let resp = self.0.call(ctx, #request_names, request);
|
||||||
async move {
|
async move {
|
||||||
match resp.await? {
|
match resp.await? {
|
||||||
#response_ident::#camel_case_idents(msg) => std::result::Result::Ok(msg),
|
#response_ident::#camel_case_idents(msg) => ::core::result::Result::Ok(msg),
|
||||||
_ => unreachable!(),
|
_ => ::core::unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ use tarpc::{
|
|||||||
context, serde_transport,
|
context, serde_transport,
|
||||||
server::{
|
server::{
|
||||||
incoming::{spawn_incoming, Incoming},
|
incoming::{spawn_incoming, Incoming},
|
||||||
BaseChannel, Serve,
|
request_hook::{self, BeforeRequestList},
|
||||||
|
BaseChannel,
|
||||||
},
|
},
|
||||||
tokio_serde::formats::Json,
|
tokio_serde::formats::Json,
|
||||||
ClientMessage, Response, ServerError, Transport,
|
ClientMessage, Response, ServerError, Transport,
|
||||||
@@ -141,19 +142,21 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let (add_listener1, addr1) = listen_on_random_port().await?;
|
let (add_listener1, addr1) = listen_on_random_port().await?;
|
||||||
let (add_listener2, addr2) = listen_on_random_port().await?;
|
let (add_listener2, addr2) = listen_on_random_port().await?;
|
||||||
let something_bad_happened = Arc::new(AtomicBool::new(false));
|
let something_bad_happened = Arc::new(AtomicBool::new(false));
|
||||||
let server = AddServer.serve().before(move |_: &mut _, _: &_| {
|
let server = request_hook::before()
|
||||||
let something_bad_happened = something_bad_happened.clone();
|
.then_fn(move |_: &mut _, _: &_| {
|
||||||
async move {
|
let something_bad_happened = something_bad_happened.clone();
|
||||||
if something_bad_happened.fetch_xor(true, Ordering::Relaxed) {
|
async move {
|
||||||
Err(ServerError::new(
|
if something_bad_happened.fetch_xor(true, Ordering::Relaxed) {
|
||||||
io::ErrorKind::NotFound,
|
Err(ServerError::new(
|
||||||
"Gamma Ray!".into(),
|
io::ErrorKind::NotFound,
|
||||||
))
|
"Gamma Ray!".into(),
|
||||||
} else {
|
))
|
||||||
Ok(())
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
.serving(AddServer.serve());
|
||||||
let add_server = add_listener1
|
let add_server = add_listener1
|
||||||
.chain(add_listener2)
|
.chain(add_listener2)
|
||||||
.map(BaseChannel::with_defaults);
|
.map(BaseChannel::with_defaults);
|
||||||
|
|||||||
@@ -210,7 +210,19 @@ pub mod tcp {
|
|||||||
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
||||||
CodecFn: Fn() -> Codec,
|
CodecFn: Fn() -> Codec,
|
||||||
{
|
{
|
||||||
let listener = TcpListener::bind(addr).await?;
|
listen_on(TcpListener::bind(addr).await?, codec_fn).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap accepted connections from `listener` in TCP transports.
|
||||||
|
pub async fn listen_on<Item, SinkItem, Codec, CodecFn>(
|
||||||
|
listener: TcpListener,
|
||||||
|
codec_fn: CodecFn,
|
||||||
|
) -> io::Result<Incoming<Item, SinkItem, Codec, CodecFn>>
|
||||||
|
where
|
||||||
|
Item: for<'de> Deserialize<'de>,
|
||||||
|
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
||||||
|
CodecFn: Fn() -> Codec,
|
||||||
|
{
|
||||||
let local_addr = listener.local_addr()?;
|
let local_addr = listener.local_addr()?;
|
||||||
Ok(Incoming {
|
Ok(Incoming {
|
||||||
listener,
|
listener,
|
||||||
@@ -364,7 +376,19 @@ pub mod unix {
|
|||||||
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
||||||
CodecFn: Fn() -> Codec,
|
CodecFn: Fn() -> Codec,
|
||||||
{
|
{
|
||||||
let listener = UnixListener::bind(path)?;
|
listen_on(UnixListener::bind(path)?, codec_fn).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap accepted connections from `listener` in Unix Domain Socket transports.
|
||||||
|
pub async fn listen_on<Item, SinkItem, Codec, CodecFn>(
|
||||||
|
listener: UnixListener,
|
||||||
|
codec_fn: CodecFn,
|
||||||
|
) -> io::Result<Incoming<Item, SinkItem, Codec, CodecFn>>
|
||||||
|
where
|
||||||
|
Item: for<'de> Deserialize<'de>,
|
||||||
|
Codec: Serializer<SinkItem> + Deserializer<Item>,
|
||||||
|
CodecFn: Fn() -> Codec,
|
||||||
|
{
|
||||||
let local_addr = listener.local_addr()?;
|
let local_addr = listener.local_addr()?;
|
||||||
Ok(Incoming {
|
Ok(Incoming {
|
||||||
listener,
|
listener,
|
||||||
@@ -537,7 +561,7 @@ pub mod unix {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::Transport;
|
use super::Transport;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use futures::{task::*, Sink, Stream};
|
use futures::{task::*, Sink, SinkExt, Stream, StreamExt};
|
||||||
use pin_utils::pin_mut;
|
use pin_utils::pin_mut;
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Cursor},
|
io::{self, Cursor},
|
||||||
@@ -631,7 +655,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(tcp)]
|
#[cfg(feature = "tcp")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn tcp() -> io::Result<()> {
|
async fn tcp() -> io::Result<()> {
|
||||||
use super::tcp;
|
use super::tcp;
|
||||||
@@ -650,11 +674,30 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tcp")]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn tcp_on_existing_transport() -> io::Result<()> {
|
||||||
|
use super::tcp;
|
||||||
|
|
||||||
|
let transport = tokio::net::TcpListener::bind("0.0.0.0:0").await?;
|
||||||
|
let mut listener = tcp::listen_on(transport, SymmetricalJson::<String>::default).await?;
|
||||||
|
let addr = listener.local_addr();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut transport = listener.next().await.unwrap().unwrap();
|
||||||
|
let message = transport.next().await.unwrap().unwrap();
|
||||||
|
transport.send(message).await.unwrap();
|
||||||
|
});
|
||||||
|
let mut transport = tcp::connect(addr, SymmetricalJson::<String>::default).await?;
|
||||||
|
transport.send(String::from("test")).await?;
|
||||||
|
assert_matches!(transport.next().await, Some(Ok(s)) if s == "test");
|
||||||
|
assert_matches!(transport.next().await, None);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "unix"))]
|
#[cfg(all(unix, feature = "unix"))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn uds() -> io::Result<()> {
|
async fn uds() -> io::Result<()> {
|
||||||
use super::unix;
|
use super::unix;
|
||||||
use super::*;
|
|
||||||
|
|
||||||
let sock = unix::TempPathBuf::with_random("uds");
|
let sock = unix::TempPathBuf::with_random("uds");
|
||||||
let mut listener = unix::listen(&sock, SymmetricalJson::<String>::default).await?;
|
let mut listener = unix::listen(&sock, SymmetricalJson::<String>::default).await?;
|
||||||
@@ -669,4 +712,24 @@ mod tests {
|
|||||||
assert_matches!(transport.next().await, None);
|
assert_matches!(transport.next().await, None);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "unix"))]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn uds_on_existing_transport() -> io::Result<()> {
|
||||||
|
use super::unix;
|
||||||
|
|
||||||
|
let sock = unix::TempPathBuf::with_random("uds");
|
||||||
|
let transport = tokio::net::UnixListener::bind(&sock)?;
|
||||||
|
let mut listener = unix::listen_on(transport, SymmetricalJson::<String>::default).await?;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut transport = listener.next().await.unwrap().unwrap();
|
||||||
|
let message = transport.next().await.unwrap().unwrap();
|
||||||
|
transport.send(message).await.unwrap();
|
||||||
|
});
|
||||||
|
let mut transport = unix::connect(&sock, SymmetricalJson::<String>::default).await?;
|
||||||
|
transport.send(String::from("test")).await?;
|
||||||
|
assert_matches!(transport.next().await, Some(Ok(s)) if s == "test");
|
||||||
|
assert_matches!(transport.next().await, None);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub mod limits;
|
|||||||
pub mod incoming;
|
pub mod incoming;
|
||||||
|
|
||||||
use request_hook::{
|
use request_hook::{
|
||||||
AfterRequest, AfterRequestHook, BeforeAndAfterRequestHook, BeforeRequest, BeforeRequestHook,
|
AfterRequest, BeforeRequest, HookThenServe, HookThenServeThenHook, ServeThenHook,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Settings that control the behavior of [channels](Channel).
|
/// Settings that control the behavior of [channels](Channel).
|
||||||
@@ -116,12 +116,12 @@ pub trait Serve {
|
|||||||
/// let response = serve.serve(context::current(), 1);
|
/// let response = serve.serve(context::current(), 1);
|
||||||
/// assert!(block_on(response).is_err());
|
/// assert!(block_on(response).is_err());
|
||||||
/// ```
|
/// ```
|
||||||
fn before<Hook>(self, hook: Hook) -> BeforeRequestHook<Self, Hook>
|
fn before<Hook>(self, hook: Hook) -> HookThenServe<Self, Hook>
|
||||||
where
|
where
|
||||||
Hook: BeforeRequest<Self::Req>,
|
Hook: BeforeRequest<Self::Req>,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
BeforeRequestHook::new(self, hook)
|
HookThenServe::new(self, hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs a hook after completion of a request.
|
/// Runs a hook after completion of a request.
|
||||||
@@ -159,12 +159,12 @@ pub trait Serve {
|
|||||||
/// let response = serve.serve(context::current(), 1);
|
/// let response = serve.serve(context::current(), 1);
|
||||||
/// assert!(block_on(response).is_err());
|
/// assert!(block_on(response).is_err());
|
||||||
/// ```
|
/// ```
|
||||||
fn after<Hook>(self, hook: Hook) -> AfterRequestHook<Self, Hook>
|
fn after<Hook>(self, hook: Hook) -> ServeThenHook<Self, Hook>
|
||||||
where
|
where
|
||||||
Hook: AfterRequest<Self::Resp>,
|
Hook: AfterRequest<Self::Resp>,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
AfterRequestHook::new(self, hook)
|
ServeThenHook::new(self, hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs a hook before and after execution of the request.
|
/// Runs a hook before and after execution of the request.
|
||||||
@@ -212,12 +212,12 @@ pub trait Serve {
|
|||||||
fn before_and_after<Hook>(
|
fn before_and_after<Hook>(
|
||||||
self,
|
self,
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
) -> BeforeAndAfterRequestHook<Self::Req, Self::Resp, Self, Hook>
|
) -> HookThenServeThenHook<Self::Req, Self::Resp, Self, Hook>
|
||||||
where
|
where
|
||||||
Hook: BeforeRequest<Self::Req> + AfterRequest<Self::Resp>,
|
Hook: BeforeRequest<Self::Req> + AfterRequest<Self::Resp>,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
BeforeAndAfterRequestHook::new(self, hook)
|
HookThenServeThenHook::new(self, hook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ mod after;
|
|||||||
mod before_and_after;
|
mod before_and_after;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
after::{AfterRequest, AfterRequestHook},
|
after::{AfterRequest, ServeThenHook},
|
||||||
before::{BeforeRequest, BeforeRequestHook},
|
before::{
|
||||||
before_and_after::BeforeAndAfterRequestHook,
|
before, BeforeRequest, BeforeRequestCons, BeforeRequestList, BeforeRequestNil,
|
||||||
|
HookThenServe,
|
||||||
|
},
|
||||||
|
before_and_after::HookThenServeThenHook,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A Service function that runs a hook after request execution.
|
/// A Service function that runs a hook after request execution.
|
||||||
pub struct AfterRequestHook<Serv, Hook> {
|
pub struct ServeThenHook<Serv, Hook> {
|
||||||
serve: Serv,
|
serve: Serv,
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Serv, Hook> AfterRequestHook<Serv, Hook> {
|
impl<Serv, Hook> ServeThenHook<Serv, Hook> {
|
||||||
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
||||||
Self { serve, hook }
|
Self { serve, hook }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Serv: Clone, Hook: Clone> Clone for AfterRequestHook<Serv, Hook> {
|
impl<Serv: Clone, Hook: Clone> Clone for ServeThenHook<Serv, Hook> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
serve: self.serve.clone(),
|
serve: self.serve.clone(),
|
||||||
@@ -49,7 +49,7 @@ impl<Serv: Clone, Hook: Clone> Clone for AfterRequestHook<Serv, Hook> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Serv, Hook> Serve for AfterRequestHook<Serv, Hook>
|
impl<Serv, Hook> Serve for ServeThenHook<Serv, Hook>
|
||||||
where
|
where
|
||||||
Serv: Serve,
|
Serv: Serve,
|
||||||
Hook: AfterRequest<Serv::Resp>,
|
Hook: AfterRequest<Serv::Resp>,
|
||||||
@@ -62,7 +62,7 @@ where
|
|||||||
mut ctx: context::Context,
|
mut ctx: context::Context,
|
||||||
req: Serv::Req,
|
req: Serv::Req,
|
||||||
) -> Result<Serv::Resp, ServerError> {
|
) -> Result<Serv::Resp, ServerError> {
|
||||||
let AfterRequestHook {
|
let ServeThenHook {
|
||||||
serve, mut hook, ..
|
serve, mut hook, ..
|
||||||
} = self;
|
} = self;
|
||||||
let mut resp = serve.serve(ctx, req).await;
|
let mut resp = serve.serve(ctx, req).await;
|
||||||
|
|||||||
@@ -22,6 +22,38 @@ pub trait BeforeRequest<Req> {
|
|||||||
async fn before(&mut self, ctx: &mut context::Context, req: &Req) -> Result<(), ServerError>;
|
async fn before(&mut self, ctx: &mut context::Context, req: &Req) -> Result<(), ServerError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A list of hooks that run in order before request execution.
|
||||||
|
pub trait BeforeRequestList<Req>: BeforeRequest<Req> {
|
||||||
|
/// The hook returned by `BeforeRequestList::then`.
|
||||||
|
type Then<Next>: BeforeRequest<Req>
|
||||||
|
where
|
||||||
|
Next: BeforeRequest<Req>;
|
||||||
|
|
||||||
|
/// Returns a hook that, when run, runs two hooks, first `self` and then `next`.
|
||||||
|
fn then<Next: BeforeRequest<Req>>(self, next: Next) -> Self::Then<Next>;
|
||||||
|
|
||||||
|
/// Same as `then`, but helps the compiler with type inference when Next is a closure.
|
||||||
|
fn then_fn<
|
||||||
|
Next: FnMut(&mut context::Context, &Req) -> Fut,
|
||||||
|
Fut: Future<Output = Result<(), ServerError>>,
|
||||||
|
>(
|
||||||
|
self,
|
||||||
|
next: Next,
|
||||||
|
) -> Self::Then<Next>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.then(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The service fn returned by `BeforeRequestList::serving`.
|
||||||
|
type Serve<S: Serve<Req = Req>>: Serve<Req = Req>;
|
||||||
|
|
||||||
|
/// Runs the list of request hooks before execution of the given serve fn.
|
||||||
|
/// This is equivalent to `serve.before(before_request_chain)` but may be syntactically nicer.
|
||||||
|
fn serving<S: Serve<Req = Req>>(self, serve: S) -> Self::Serve<S>;
|
||||||
|
}
|
||||||
|
|
||||||
impl<F, Fut, Req> BeforeRequest<Req> for F
|
impl<F, Fut, Req> BeforeRequest<Req> for F
|
||||||
where
|
where
|
||||||
F: FnMut(&mut context::Context, &Req) -> Fut,
|
F: FnMut(&mut context::Context, &Req) -> Fut,
|
||||||
@@ -33,27 +65,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A Service function that runs a hook before request execution.
|
/// A Service function that runs a hook before request execution.
|
||||||
pub struct BeforeRequestHook<Serv, Hook> {
|
#[derive(Clone)]
|
||||||
|
pub struct HookThenServe<Serv, Hook> {
|
||||||
serve: Serv,
|
serve: Serv,
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Serv, Hook> BeforeRequestHook<Serv, Hook> {
|
impl<Serv, Hook> HookThenServe<Serv, Hook> {
|
||||||
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
||||||
Self { serve, hook }
|
Self { serve, hook }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Serv: Clone, Hook: Clone> Clone for BeforeRequestHook<Serv, Hook> {
|
impl<Serv, Hook> Serve for HookThenServe<Serv, Hook>
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
serve: self.serve.clone(),
|
|
||||||
hook: self.hook.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Serv, Hook> Serve for BeforeRequestHook<Serv, Hook>
|
|
||||||
where
|
where
|
||||||
Serv: Serve,
|
Serv: Serve,
|
||||||
Hook: BeforeRequest<Serv::Req>,
|
Hook: BeforeRequest<Serv::Req>,
|
||||||
@@ -66,10 +90,121 @@ where
|
|||||||
mut ctx: context::Context,
|
mut ctx: context::Context,
|
||||||
req: Self::Req,
|
req: Self::Req,
|
||||||
) -> Result<Serv::Resp, ServerError> {
|
) -> Result<Serv::Resp, ServerError> {
|
||||||
let BeforeRequestHook {
|
let HookThenServe {
|
||||||
serve, mut hook, ..
|
serve, mut hook, ..
|
||||||
} = self;
|
} = self;
|
||||||
hook.before(&mut ctx, &req).await?;
|
hook.before(&mut ctx, &req).await?;
|
||||||
serve.serve(ctx, req).await
|
serve.serve(ctx, req).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a request hook builder that runs a series of hooks before request execution.
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use futures::{executor::block_on, future};
|
||||||
|
/// use tarpc::{context, ServerError, server::{Serve, serve, request_hook::{self,
|
||||||
|
/// BeforeRequest, BeforeRequestList}}};
|
||||||
|
/// use std::{cell::Cell, io};
|
||||||
|
///
|
||||||
|
/// let i = Cell::new(0);
|
||||||
|
/// let serve = request_hook::before()
|
||||||
|
/// .then_fn(|_, _| async {
|
||||||
|
/// assert!(i.get() == 0);
|
||||||
|
/// i.set(1);
|
||||||
|
/// Ok(())
|
||||||
|
/// })
|
||||||
|
/// .then_fn(|_, _| async {
|
||||||
|
/// assert!(i.get() == 1);
|
||||||
|
/// i.set(2);
|
||||||
|
/// Ok(())
|
||||||
|
/// })
|
||||||
|
/// .serving(serve(|_ctx, i| async move { Ok(i + 1) }));
|
||||||
|
/// let response = serve.clone().serve(context::current(), 1);
|
||||||
|
/// assert!(block_on(response).is_ok());
|
||||||
|
/// assert!(i.get() == 2);
|
||||||
|
/// ```
|
||||||
|
pub fn before() -> BeforeRequestNil {
|
||||||
|
BeforeRequestNil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A list of hooks that run in order before a request is executed.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct BeforeRequestCons<First, Rest>(First, Rest);
|
||||||
|
|
||||||
|
/// A noop hook that runs before a request is executed.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct BeforeRequestNil;
|
||||||
|
|
||||||
|
impl<Req, First: BeforeRequest<Req>, Rest: BeforeRequest<Req>> BeforeRequest<Req>
|
||||||
|
for BeforeRequestCons<First, Rest>
|
||||||
|
{
|
||||||
|
async fn before(&mut self, ctx: &mut context::Context, req: &Req) -> Result<(), ServerError> {
|
||||||
|
let BeforeRequestCons(first, rest) = self;
|
||||||
|
first.before(ctx, req).await?;
|
||||||
|
rest.before(ctx, req).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Req> BeforeRequest<Req> for BeforeRequestNil {
|
||||||
|
async fn before(&mut self, _: &mut context::Context, _: &Req) -> Result<(), ServerError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Req, First: BeforeRequest<Req>, Rest: BeforeRequestList<Req>> BeforeRequestList<Req>
|
||||||
|
for BeforeRequestCons<First, Rest>
|
||||||
|
{
|
||||||
|
type Then<Next> = BeforeRequestCons<First, Rest::Then<Next>> where Next: BeforeRequest<Req>;
|
||||||
|
|
||||||
|
fn then<Next: BeforeRequest<Req>>(self, next: Next) -> Self::Then<Next> {
|
||||||
|
let BeforeRequestCons(first, rest) = self;
|
||||||
|
BeforeRequestCons(first, rest.then(next))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Serve<S: Serve<Req = Req>> = HookThenServe<S, Self>;
|
||||||
|
|
||||||
|
fn serving<S: Serve<Req = Req>>(self, serve: S) -> Self::Serve<S> {
|
||||||
|
HookThenServe::new(serve, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Req> BeforeRequestList<Req> for BeforeRequestNil {
|
||||||
|
type Then<Next> = BeforeRequestCons<Next, BeforeRequestNil> where Next: BeforeRequest<Req>;
|
||||||
|
|
||||||
|
fn then<Next: BeforeRequest<Req>>(self, next: Next) -> Self::Then<Next> {
|
||||||
|
BeforeRequestCons(next, BeforeRequestNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Serve<S: Serve<Req = Req>> = S;
|
||||||
|
|
||||||
|
fn serving<S: Serve<Req = Req>>(self, serve: S) -> S {
|
||||||
|
serve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn before_request_list() {
|
||||||
|
use crate::server::serve;
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
let i = Cell::new(0);
|
||||||
|
let serve = before()
|
||||||
|
.then_fn(|_, _| async {
|
||||||
|
assert!(i.get() == 0);
|
||||||
|
i.set(1);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.then_fn(|_, _| async {
|
||||||
|
assert!(i.get() == 1);
|
||||||
|
i.set(2);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.serving(serve(|_ctx, i| async move { Ok(i + 1) }));
|
||||||
|
let response = serve.clone().serve(context::current(), 1);
|
||||||
|
assert!(block_on(response).is_ok());
|
||||||
|
assert!(i.get() == 2);
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ use crate::{context, server::Serve, ServerError};
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A Service function that runs a hook both before and after request execution.
|
/// A Service function that runs a hook both before and after request execution.
|
||||||
pub struct BeforeAndAfterRequestHook<Req, Resp, Serv, Hook> {
|
pub struct HookThenServeThenHook<Req, Resp, Serv, Hook> {
|
||||||
serve: Serv,
|
serve: Serv,
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
fns: PhantomData<(fn(Req), fn(Resp))>,
|
fns: PhantomData<(fn(Req), fn(Resp))>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Req, Resp, Serv, Hook> BeforeAndAfterRequestHook<Req, Resp, Serv, Hook> {
|
impl<Req, Resp, Serv, Hook> HookThenServeThenHook<Req, Resp, Serv, Hook> {
|
||||||
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
pub(crate) fn new(serve: Serv, hook: Hook) -> Self {
|
||||||
Self {
|
Self {
|
||||||
serve,
|
serve,
|
||||||
@@ -27,9 +27,7 @@ impl<Req, Resp, Serv, Hook> BeforeAndAfterRequestHook<Req, Resp, Serv, Hook> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Req, Resp, Serv: Clone, Hook: Clone> Clone
|
impl<Req, Resp, Serv: Clone, Hook: Clone> Clone for HookThenServeThenHook<Req, Resp, Serv, Hook> {
|
||||||
for BeforeAndAfterRequestHook<Req, Resp, Serv, Hook>
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
serve: self.serve.clone(),
|
serve: self.serve.clone(),
|
||||||
@@ -39,7 +37,7 @@ impl<Req, Resp, Serv: Clone, Hook: Clone> Clone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Req, Resp, Serv, Hook> Serve for BeforeAndAfterRequestHook<Req, Resp, Serv, Hook>
|
impl<Req, Resp, Serv, Hook> Serve for HookThenServeThenHook<Req, Resp, Serv, Hook>
|
||||||
where
|
where
|
||||||
Serv: Serve<Req = Req, Resp = Resp>,
|
Serv: Serve<Req = Req, Resp = Resp>,
|
||||||
Hook: BeforeRequest<Req> + AfterRequest<Resp>,
|
Hook: BeforeRequest<Req> + AfterRequest<Resp>,
|
||||||
@@ -48,7 +46,7 @@ where
|
|||||||
type Resp = Resp;
|
type Resp = Resp;
|
||||||
|
|
||||||
async fn serve(self, mut ctx: context::Context, req: Req) -> Result<Serv::Resp, ServerError> {
|
async fn serve(self, mut ctx: context::Context, req: Req) -> Result<Serv::Resp, ServerError> {
|
||||||
let BeforeAndAfterRequestHook {
|
let HookThenServeThenHook {
|
||||||
serve, mut hook, ..
|
serve, mut hook, ..
|
||||||
} = self;
|
} = self;
|
||||||
hook.before(&mut ctx, &req).await?;
|
hook.before(&mut ctx, &req).await?;
|
||||||
|
|||||||
17
tarpc/tests/proc_macro_hygene.rs
Normal file
17
tarpc/tests/proc_macro_hygene.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#![no_implicit_prelude]
|
||||||
|
extern crate tarpc as some_random_other_name;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde1")]
|
||||||
|
mod serde1_feature {
|
||||||
|
#[::tarpc::derive_serde]
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum TestData {
|
||||||
|
Black,
|
||||||
|
White,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[::tarpc::service]
|
||||||
|
pub trait ColorProtocol {
|
||||||
|
async fn get_opposite_color(color: u8) -> u8;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user