feat(codec): compression support (#692)

* Initial compression support

* Support configuring compression on `Server`

* Minor clean up

* Test that compression is actually happening

* Clean up some todos

* channels compressing requests

* Move compression to be on the codecs

* Test sending compressed request to server that doesn't support it

* Clean up a bit

* Compress server streams

* Compress client streams

* Bidirectional streaming compression

* Handle receiving unsupported encoding

* Clean up

* Add note to future self

* Support disabling compression for individual responses

* Add docs

* Add compression examples

* Disable compression behind feature flag

* Add some docs

* Make flate2 optional dependency

* Fix docs wording

* Format

* Reply with which encodings are supported

* Convert tests to use mocked io

* Fix lints

* Use separate counters

* Don't make a long stream

* Address review feedback
This commit is contained in:
David Pedersen
2021-07-02 11:25:03 -04:00
committed by GitHub
parent 7677ad6476
commit 0583cff80f
30 changed files with 2191 additions and 98 deletions
+56 -7
View File
@@ -36,6 +36,32 @@ pub fn generate<T: Service>(
);
let transport = generate_transport(&server_service, &server_trait, &path);
let compression_enabled = cfg!(feature = "compression");
let compression_config_ty = if compression_enabled {
quote! { EnabledCompressionEncodings }
} else {
quote! { () }
};
let configure_compression_methods = if compression_enabled {
quote! {
/// Enable decompressing requests with `gzip`.
pub fn accept_gzip(mut self) -> Self {
self.accept_compression_encodings.enable_gzip();
self
}
/// Compress responses with `gzip`, if the client supports it.
pub fn send_gzip(mut self) -> Self {
self.send_compression_encodings.enable_gzip();
self
}
}
} else {
quote! {}
};
quote! {
/// Generated server implementations.
pub mod #server_mod {
@@ -48,6 +74,8 @@ pub fn generate<T: Service>(
#[derive(Debug)]
pub struct #server_service<T: #server_trait> {
inner: _Inner<T>,
accept_compression_encodings: #compression_config_ty,
send_compression_encodings: #compression_config_ty,
}
struct _Inner<T>(Arc<T>);
@@ -56,7 +84,11 @@ pub fn generate<T: Service>(
pub fn new(inner: T) -> Self {
let inner = Arc::new(inner);
let inner = _Inner(inner);
Self { inner }
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
}
}
pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
@@ -65,6 +97,8 @@ pub fn generate<T: Service>(
{
InterceptedService::new(Self::new(inner), interceptor)
}
#configure_compression_methods
}
impl<T, B> Service<http::Request<B>> for #server_service<T>
@@ -102,7 +136,11 @@ pub fn generate<T: Service>(
impl<T: #server_trait> Clone for #server_service<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self { inner }
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
}
}
}
@@ -335,13 +373,16 @@ fn generate_unary<T: Method>(
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = #service_ident(inner);
let codec = #codec_name::default();
let mut grpc = tonic::server::Grpc::new(codec);
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(accept_compression_encodings, send_compression_encodings);
let res = grpc.unary(method, req).await;
Ok(res)
@@ -379,19 +420,21 @@ fn generate_server_streaming<T: Method>(
let inner = self.0.clone();
let fut = async move {
(*inner).#method_ident(request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = #service_ident(inner);
let codec = #codec_name::default();
let mut grpc = tonic::server::Grpc::new(codec);
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(accept_compression_encodings, send_compression_encodings);
let res = grpc.server_streaming(method, req).await;
Ok(res)
@@ -432,13 +475,16 @@ fn generate_client_streaming<T: Method>(
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = #service_ident(inner);
let codec = #codec_name::default();
let mut grpc = tonic::server::Grpc::new(codec);
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(accept_compression_encodings, send_compression_encodings);
let res = grpc.client_streaming(method, req).await;
Ok(res)
@@ -482,13 +528,16 @@ fn generate_streaming<T: Method>(
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = #service_ident(inner);
let codec = #codec_name::default();
let mut grpc = tonic::server::Grpc::new(codec);
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(accept_compression_encodings, send_compression_encodings);
let res = grpc.streaming(method, req).await;
Ok(res)