diff --git a/tonic-health/Cargo.toml b/tonic-health/Cargo.toml index 5b89de287..c3bc5236a 100644 --- a/tonic-health/Cargo.toml +++ b/tonic-health/Cargo.toml @@ -16,7 +16,7 @@ version = "0.7.0" [features] default = ["transport"] -transport = ["tonic/transport", "tonic-build/transport"] +transport = ["tonic/transport"] [dependencies] async-stream = "0.3" @@ -28,6 +28,4 @@ tonic = {version = "0.8", path = "../tonic", features = ["codegen", "prost"]} [dev-dependencies] tokio = {version = "1.0", features = ["rt-multi-thread", "macros"]} - -[build-dependencies] tonic-build = {version = "0.8", path = "../tonic-build", features = ["prost"]} diff --git a/tonic-health/build.rs b/tonic-health/build.rs deleted file mode 100644 index 5b04330ef..000000000 --- a/tonic-health/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::env; -use std::path::PathBuf; - -fn main() -> Result<(), Box> { - let grpc_health_v1_descriptor_set_path: PathBuf = - PathBuf::from(env::var("OUT_DIR").unwrap()).join("grpc_health_v1.bin"); - tonic_build::configure() - .file_descriptor_set_path(grpc_health_v1_descriptor_set_path) - .build_server(true) - .build_client(true) - .compile(&["proto/health.proto"], &["proto/"])?; - - Ok(()) -} diff --git a/tonic-health/src/generated/grpc.health.v1.rs b/tonic-health/src/generated/grpc.health.v1.rs new file mode 100644 index 000000000..634201e52 --- /dev/null +++ b/tonic-health/src/generated/grpc.health.v1.rs @@ -0,0 +1,379 @@ +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealthCheckRequest { + #[prost(string, tag="1")] + pub service: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealthCheckResponse { + #[prost(enumeration="health_check_response::ServingStatus", tag="1")] + pub status: i32, +} +/// Nested message and enum types in `HealthCheckResponse`. +pub mod health_check_response { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum ServingStatus { + Unknown = 0, + Serving = 1, + NotServing = 2, + /// Used only by the Watch method. + ServiceUnknown = 3, + } + impl ServingStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ServingStatus::Unknown => "UNKNOWN", + ServingStatus::Serving => "SERVING", + ServingStatus::NotServing => "NOT_SERVING", + ServingStatus::ServiceUnknown => "SERVICE_UNKNOWN", + } + } + } +} +/// Generated client implementations. +pub mod health_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct HealthClient { + inner: tonic::client::Grpc, + } + impl HealthClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl HealthClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> HealthClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + HealthClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// If the requested service is unknown, the call will fail with status + /// NOT_FOUND. + pub async fn check( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/grpc.health.v1.Health/Check", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// Performs a watch for the serving status of the requested service. + /// The server will immediately send back a message indicating the current + /// serving status. It will then subsequently send a new message whenever + /// the service's serving status changes. + /// + /// If the requested service is unknown when the call is received, the + /// server will send a message setting the serving status to + /// SERVICE_UNKNOWN but will *not* terminate the call. If at some + /// future point, the serving status of the service becomes known, the + /// server will send a new message with the service's serving status. + /// + /// If the call terminates with status UNIMPLEMENTED, then clients + /// should assume this method is not supported and should not retry the + /// call. If the call terminates with any other status (including OK), + /// clients should retry the call with appropriate exponential backoff. + pub async fn watch( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/grpc.health.v1.Health/Watch", + ); + self.inner.server_streaming(request.into_request(), path, codec).await + } + } +} +/// Generated server implementations. +pub mod health_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + ///Generated trait containing gRPC methods that should be implemented for use with HealthServer. + #[async_trait] + pub trait Health: Send + Sync + 'static { + /// If the requested service is unknown, the call will fail with status + /// NOT_FOUND. + async fn check( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + ///Server streaming response type for the Watch method. + type WatchStream: futures_core::Stream< + Item = Result, + > + + Send + + 'static; + /// Performs a watch for the serving status of the requested service. + /// The server will immediately send back a message indicating the current + /// serving status. It will then subsequently send a new message whenever + /// the service's serving status changes. + /// + /// If the requested service is unknown when the call is received, the + /// server will send a message setting the serving status to + /// SERVICE_UNKNOWN but will *not* terminate the call. If at some + /// future point, the serving status of the service becomes known, the + /// server will send a new message with the service's serving status. + /// + /// If the call terminates with status UNIMPLEMENTED, then clients + /// should assume this method is not supported and should not retry the + /// call. If the call terminates with any other status (including OK), + /// clients should retry the call with appropriate exponential backoff. + async fn watch( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + } + #[derive(Debug)] + pub struct HealthServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + } + struct _Inner(Arc); + impl HealthServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + } + impl tonic::codegen::Service> for HealthServer + where + T: Health, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/grpc.health.v1.Health/Check" => { + #[allow(non_camel_case_types)] + struct CheckSvc(pub Arc); + impl< + T: Health, + > tonic::server::UnaryService + for CheckSvc { + type Response = super::HealthCheckResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).check(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 = CheckSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + 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) + }; + Box::pin(fut) + } + "/grpc.health.v1.Health/Watch" => { + #[allow(non_camel_case_types)] + struct WatchSvc(pub Arc); + impl< + T: Health, + > tonic::server::ServerStreamingService + for WatchSvc { + type Response = super::HealthCheckResponse; + type ResponseStream = T::WatchStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).watch(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 = WatchSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + 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) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for HealthServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for HealthServer { + const NAME: &'static str = "grpc.health.v1.Health"; + } +} diff --git a/tonic-health/src/generated/grpc_health_v1.bin b/tonic-health/src/generated/grpc_health_v1.bin new file mode 100644 index 000000000..52efb3122 Binary files /dev/null and b/tonic-health/src/generated/grpc_health_v1.bin differ diff --git a/tonic-health/src/lib.rs b/tonic-health/src/lib.rs index 59aab1649..f29dc340c 100644 --- a/tonic-health/src/lib.rs +++ b/tonic-health/src/lib.rs @@ -23,14 +23,14 @@ use std::fmt::{Display, Formatter}; -/// Generated protobuf types from the `grpc.healthy.v1` package. +/// Generated protobuf types from the `grpc.health.v1` package. pub mod proto { #![allow(unreachable_pub)] #![allow(missing_docs)] - tonic::include_proto!("grpc.health.v1"); + include!("generated/grpc.health.v1.rs"); pub const GRPC_HEALTH_V1_FILE_DESCRIPTOR_SET: &[u8] = - tonic::include_file_descriptor_set!("grpc_health_v1"); + include_bytes!("generated/grpc_health_v1.bin"); } pub mod server; diff --git a/tonic-health/tests/bootstrap.rs b/tonic-health/tests/bootstrap.rs new file mode 100644 index 000000000..bbf4f9cfa --- /dev/null +++ b/tonic-health/tests/bootstrap.rs @@ -0,0 +1,30 @@ +use std::{path::PathBuf, process::Command}; + +#[test] +fn bootstrap() { + let iface_files = &["proto/health.proto"]; + let dirs = &["proto"]; + + let out_dir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("generated"); + + tonic_build::configure() + .build_client(true) + .build_server(true) + .out_dir(format!("{}", out_dir.display())) + .compile(iface_files, dirs) + .unwrap(); + + let status = Command::new("git") + .arg("diff") + .arg("--exit-code") + .arg("--") + .arg(format!("{}", out_dir.display())) + .status() + .unwrap(); + + if !status.success() { + panic!("You should commit the protobuf files"); + } +}