diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d05573..9df56c67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,10 +31,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Users who are just using the simple `Field::set_values` method or the various `IntoField` / `IntoOptField` traits should not be affected. - Update MSRV to 1.81 +- Bump arrow dependency to 56.0 +- Bump darling dependency to 0.21.0 - Bump itertools dependency to 0.14.0 - Bump prometheus dependency to 0.14.0 - Bump thiserror dependency to 2.0.11 -- Bump tonic, tonic-build and tonic-health dependencies to 0.13.0 +- Bump prost, tonic, tonic-build and tonic-health dependencies to 0.14.2; added tonic-prost dependency - Bump tracing-serde dependency to 0.2.0 ## [0.5.0] - 2024-09-17 @@ -52,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - the type of plugin (`PluginType::App` or `PluginType::Datasource`) The simplest way to do so is to use the `GrafanaPlugin` derive macro exporter from the library's prelude: - + ```rust use std::collections::HashMap; @@ -64,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 max_retries: usize, other_custom_setting: String, } - + #[derive(Debug, GrafanaPlugin)] #[grafana_plugin( type = "datasource", diff --git a/crates/grafana-plugin-sdk-macros/Cargo.toml b/crates/grafana-plugin-sdk-macros/Cargo.toml index 09fabfc1..8cb2314c 100644 --- a/crates/grafana-plugin-sdk-macros/Cargo.toml +++ b/crates/grafana-plugin-sdk-macros/Cargo.toml @@ -11,7 +11,7 @@ description = "Convenience macros for the Grafana backend plugin SDK." proc-macro = true [dependencies] -darling = "0.20.3" +darling = "0.21.3" proc-macro2 = "1.0.60" quote = "1.0.28" syn = { version = "2.0.18", features = ["full"] } diff --git a/crates/grafana-plugin-sdk/Cargo.toml b/crates/grafana-plugin-sdk/Cargo.toml index f9a8b6a2..00151b85 100644 --- a/crates/grafana-plugin-sdk/Cargo.toml +++ b/crates/grafana-plugin-sdk/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/grafana/grafana-plugin-sdk-rust" description = "SDK for building Grafana backend plugins." [dependencies] -arrow = { version = "55.0.0", default-features = false, features = ["ipc"] } +arrow = { version = "56.2.0", default-features = false, features = ["ipc"] } cfg-if = "1.0.0" chrono = "0.4.26" futures-core = "0.3.28" @@ -18,7 +18,7 @@ grafana-plugin-sdk-macros = { version = "0.5.0", path = "../grafana-plugin-sdk-m http = "1.0.0" itertools = "0.14.0" num-traits = "0.2.15" -prost = "0.13.2" +prost = "0.14.1" reqwest_lib = { package = "reqwest", version = "0.12.7", optional = true } serde = { version = "1.0.164", features = ["derive"] } serde_json = { version = "1.0.96", features = ["float_roundtrip", "raw_value"] } @@ -27,8 +27,9 @@ thiserror = "2.0.11" time = { version = "0.3.22", features = ["formatting", "macros"] } tokio = { version = "1.28.2", features = ["rt-multi-thread"] } tokio-stream = { version = "0.1.14", features = ["net"] } -tonic = "0.13.0" -tonic-health = "0.13.0" +tonic = "0.14.2" +tonic-health = "0.14.2" +tonic-prost = "0.14.2" tracing = "0.1.37" tracing-core = "0.1.31" tracing-log = "0.2.0" @@ -50,8 +51,7 @@ tokio = { version = "1.28.2", features = ["rt-multi-thread"] } tokio-stream = "0.1.14" [build-dependencies] -prost-build = { version = "0.13.2", optional = true } -tonic-build = { version = "0.13.0", optional = true } +tonic-prost-build = { version = "0.14.2", optional = true } # docs.rs-specific configuration [package.metadata.docs.rs] @@ -66,4 +66,4 @@ reqwest = ["reqwest_lib"] # because it requires protoc. The generated code is instead checked in to source # control. To regenerate code in the case of updated .proto definitions, build # with this feature enabled. -gen-proto = ["dep:tonic-build", "dep:prost-build"] +gen-proto = ["dep:tonic-prost-build"] diff --git a/crates/grafana-plugin-sdk/build.rs b/crates/grafana-plugin-sdk/build.rs index 64ab2c28..2c26481d 100644 --- a/crates/grafana-plugin-sdk/build.rs +++ b/crates/grafana-plugin-sdk/build.rs @@ -1,16 +1,16 @@ fn main() -> Result<(), Box> { #[cfg(feature = "gen-proto")] { - let mut config = prost_build::Config::new(); + let mut config = tonic_prost_build::Config::new(); config.bytes([ ".pluginv2.CallResourceRequest", ".pluginv2.CallResourceResponse", ".pluginv2.RunStreamRequest", ".pluginv2.SubscribeStreamRequest", ]); - Ok(tonic_build::configure() + Ok(tonic_prost_build::configure() .out_dir("src/pluginv2") - .compile_protos_with_config( + .compile_with_config( config, &["./vendor/proto/backend.proto"], &["./vendor/proto"], diff --git a/crates/grafana-plugin-sdk/src/pluginv2/pluginv2.rs b/crates/grafana-plugin-sdk/src/pluginv2/pluginv2.rs index 316f00bd..f63a533c 100644 --- a/crates/grafana-plugin-sdk/src/pluginv2/pluginv2.rs +++ b/crates/grafana-plugin-sdk/src/pluginv2/pluginv2.rs @@ -50,7 +50,7 @@ pub struct DataSourceInstanceSettings { #[prost(string, tag = "12")] pub api_version: ::prost::alloc::string::String, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct User { #[prost(string, tag = "1")] pub login: ::prost::alloc::string::String, @@ -106,7 +106,7 @@ pub struct PluginContext { #[prost(string, tag = "9")] pub api_version: ::prost::alloc::string::String, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StringList { #[prost(string, repeated, tag = "1")] pub values: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, @@ -138,14 +138,14 @@ pub struct CallResourceResponse { #[prost(bytes = "bytes", tag = "3")] pub body: ::prost::bytes::Bytes, } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TimeRange { #[prost(int64, tag = "1")] pub from_epoch_ms: i64, #[prost(int64, tag = "2")] pub to_epoch_ms: i64, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DataQuery { #[prost(string, tag = "1")] pub ref_id: ::prost::alloc::string::String, @@ -184,7 +184,7 @@ pub struct QueryDataResponse { DataResponse, >, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DataResponse { /// Arrow encoded DataFrames /// Frame has its own meta, warnings, and repeats refId @@ -210,14 +210,14 @@ pub struct CollectMetricsRequest { #[prost(message, optional, tag = "1")] pub plugin_context: ::core::option::Option, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct CollectMetricsResponse { #[prost(message, optional, tag = "1")] pub metrics: ::core::option::Option, } /// Nested message and enum types in `CollectMetricsResponse`. pub mod collect_metrics_response { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Payload { #[prost(bytes = "vec", tag = "1")] pub prometheus: ::prost::alloc::vec::Vec, @@ -234,7 +234,7 @@ pub struct CheckHealthRequest { ::prost::alloc::string::String, >, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct CheckHealthResponse { #[prost(enumeration = "check_health_response::HealthStatus", tag = "1")] pub status: i32, @@ -297,7 +297,7 @@ pub struct SubscribeStreamRequest { #[prost(bytes = "bytes", tag = "3")] pub data: ::prost::bytes::Bytes, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct SubscribeStreamResponse { /// status of subscribe response. #[prost(enumeration = "subscribe_stream_response::Status", tag = "1")] @@ -362,7 +362,7 @@ pub struct PublishStreamRequest { #[prost(bytes = "vec", tag = "3")] pub data: ::prost::alloc::vec::Vec, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PublishStreamResponse { /// status of publish response. #[prost(enumeration = "publish_stream_response::Status", tag = "1")] @@ -429,14 +429,14 @@ pub struct RunStreamRequest { #[prost(bytes = "bytes", tag = "3")] pub data: ::prost::bytes::Bytes, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StreamPacket { /// JSON-encoded data to publish into a channel. #[prost(bytes = "vec", tag = "1")] pub data: ::prost::alloc::vec::Vec, } /// Identify the Object properties -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GroupVersionKind { #[prost(string, tag = "1")] pub group: ::prost::alloc::string::String, @@ -509,7 +509,7 @@ pub mod admission_request { } } /// Check if an object can be admitted -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ValidationResponse { /// Allowed indicates whether or not the admission request was permitted. #[prost(bool, tag = "1")] @@ -528,7 +528,7 @@ pub struct ValidationResponse { pub warnings: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// Return a mutated copy of the object in a form that can be admitted -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct MutationResponse { /// Allowed indicates whether or not the admission request was permitted. #[prost(bool, tag = "1")] @@ -550,7 +550,7 @@ pub struct MutationResponse { pub object_bytes: ::prost::alloc::vec::Vec, } /// GroupVersion represents the API group and version of a resource. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GroupVersion { #[prost(string, tag = "1")] pub group: ::prost::alloc::string::String, @@ -558,7 +558,7 @@ pub struct GroupVersion { pub version: ::prost::alloc::string::String, } /// RawObject contains a resource serialized into a byte array with a content type -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RawObject { /// Raw is the serialized object #[prost(bytes = "vec", tag = "1")] @@ -604,7 +604,7 @@ pub struct ConversionResponse { } /// Status structure is copied from: /// -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StatusResult { /// Status of the operation. /// One of: "Success" or "Failure". @@ -734,7 +734,7 @@ pub mod resource_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/pluginv2.Resource/CallResource", ); @@ -745,8 +745,8 @@ pub mod resource_client { } } } -/// Generated client implementations. -pub mod data_client { +/// Generated server implementations. +pub mod resource_server { #![allow( unused_variables, dead_code, @@ -755,69 +755,63 @@ pub mod data_client { clippy::let_unit_value, )] use tonic::codegen::*; - use tonic::codegen::http::Uri; - #[derive(Debug, Clone)] - pub struct DataClient { - inner: tonic::client::Grpc, + /// Generated trait containing gRPC methods that should be implemented for use with ResourceServer. + #[async_trait] + pub trait Resource: std::marker::Send + std::marker::Sync + 'static { + /// Server streaming response type for the CallResource method. + type CallResourceStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + + std::marker::Send + + 'static; + async fn call_resource( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } - impl DataClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } + #[derive(Debug)] + pub struct ResourceServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, } - impl DataClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::Send, - { + impl ResourceServer { pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } + Self::from_arc(Arc::new(inner)) } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } } pub fn with_interceptor( inner: T, interceptor: F, - ) -> DataClient> + ) -> InterceptedService where F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, { - DataClient::new(InterceptedService::new(inner, interceptor)) + InterceptedService::new(Self::new(inner), interceptor) } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. + /// Enable decompressing requests with the given encoding. #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); self } - /// Enable decompressing responses. + /// Compress responses with the given encoding, if the client supports it. #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); self } /// Limits the maximum size of a decoded message. @@ -825,7 +819,7 @@ pub mod data_client { /// Default: `4MB` #[must_use] pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); + self.max_decoding_message_size = Some(limit); self } /// Limits the maximum size of an encoded message. @@ -833,34 +827,115 @@ pub mod data_client { /// Default: `usize::MAX` #[must_use] pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); + self.max_encoding_message_size = Some(limit); self } - pub async fn query_data( + } + impl tonic::codegen::Service> for ResourceServer + where + T: Resource, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/pluginv2.Data/QueryData"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("pluginv2.Data", "QueryData")); - self.inner.unary(req, path, codec).await + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/pluginv2.Resource/CallResource" => { + #[allow(non_camel_case_types)] + struct CallResourceSvc(pub Arc); + impl< + T: Resource, + > tonic::server::ServerStreamingService + for CallResourceSvc { + type Response = super::CallResourceResponse; + type ResponseStream = T::CallResourceStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::call_resource(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = CallResourceSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new( + tonic::body::Body::default(), + ); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for ResourceServer { + 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, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } } } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "pluginv2.Resource"; + impl tonic::server::NamedService for ResourceServer { + const NAME: &'static str = SERVICE_NAME; + } } /// Generated client implementations. -pub mod diagnostics_client { +pub mod data_client { #![allow( unused_variables, dead_code, @@ -871,10 +946,10 @@ pub mod diagnostics_client { use tonic::codegen::*; use tonic::codegen::http::Uri; #[derive(Debug, Clone)] - pub struct DiagnosticsClient { + pub struct DataClient { inner: tonic::client::Grpc, } - impl DiagnosticsClient { + impl DataClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result where @@ -885,7 +960,7 @@ pub mod diagnostics_client { Ok(Self::new(conn)) } } - impl DiagnosticsClient + impl DataClient where T: tonic::client::GrpcService, T::Error: Into, @@ -903,7 +978,7 @@ pub mod diagnostics_client { pub fn with_interceptor( inner: T, interceptor: F, - ) -> DiagnosticsClient> + ) -> DataClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, @@ -917,7 +992,7 @@ pub mod diagnostics_client { http::Request, >>::Error: Into + std::marker::Send + std::marker::Sync, { - DiagnosticsClient::new(InterceptedService::new(inner, interceptor)) + DataClient::new(InterceptedService::new(inner, interceptor)) } /// Compress requests with the given encoding. /// @@ -950,11 +1025,11 @@ pub mod diagnostics_client { self.inner = self.inner.max_encoding_message_size(limit); self } - pub async fn check_health( + pub async fn query_data( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner @@ -965,490 +1040,16 @@ pub mod diagnostics_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.Diagnostics/CheckHealth", - ); + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/pluginv2.Data/QueryData"); let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("pluginv2.Diagnostics", "CheckHealth")); - self.inner.unary(req, path, codec).await - } - pub async fn collect_metrics( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.Diagnostics/CollectMetrics", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("pluginv2.Diagnostics", "CollectMetrics")); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated client implementations. -pub mod stream_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - #[derive(Debug, Clone)] - pub struct StreamClient { - inner: tonic::client::Grpc, - } - impl StreamClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl StreamClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::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, - ) -> StreamClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, - { - StreamClient::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 - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// SubscribeStream called when a user tries to subscribe to a plugin/datasource - /// managed channel path – thus plugin can check subscribe permissions and communicate - /// options with Grafana Core. When the first subscriber joins a channel, RunStream - /// will be called. - pub async fn subscribe_stream( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.Stream/SubscribeStream", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("pluginv2.Stream", "SubscribeStream")); - self.inner.unary(req, path, codec).await - } - /// RunStream will be initiated by Grafana to consume a stream. RunStream will be - /// called once for the first client successfully subscribed to a channel path. - /// When Grafana detects that there are no longer any subscribers inside a channel, - /// the call will be terminated until next active subscriber appears. Call termination - /// can happen with a delay. - pub async fn run_stream( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.Stream/RunStream", - ); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("pluginv2.Stream", "RunStream")); - self.inner.server_streaming(req, path, codec).await - } - /// PublishStream called when a user tries to publish to a plugin/datasource - /// managed channel path. Here plugin can check publish permissions and - /// modify publication data if required. - pub async fn publish_stream( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.Stream/PublishStream", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("pluginv2.Stream", "PublishStream")); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated client implementations. -pub mod admission_control_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// Admission control is a service based on the kubernetes admission webhook patterns. - /// This service can be used to verify if objects are valid and convert between versions - /// See: https://github.com/kubernetes/kubernetes/blob/v1.30.0/pkg/apis/admission/types.go#L41 - /// And: https://github.com/grafana/grafana-app-sdk/blob/main/resource/admission.go#L14 - #[derive(Debug, Clone)] - pub struct AdmissionControlClient { - inner: tonic::client::Grpc, - } - impl AdmissionControlClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl AdmissionControlClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::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, - ) -> AdmissionControlClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, - { - AdmissionControlClient::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 - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// Validate a resource -- the response is a simple yes/no - pub async fn validate_admission( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.AdmissionControl/ValidateAdmission", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new("pluginv2.AdmissionControl", "ValidateAdmission"), - ); - self.inner.unary(req, path, codec).await - } - /// Return a modified copy of the request that can be saved or a descriptive error - pub async fn mutate_admission( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.AdmissionControl/MutateAdmission", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("pluginv2.AdmissionControl", "MutateAdmission")); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated client implementations. -pub mod resource_conversion_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// ResourceConversion is a service that can be used to convert resources between versions - /// See: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-request-and-response - #[derive(Debug, Clone)] - pub struct ResourceConversionClient { - inner: tonic::client::Grpc, - } - impl ResourceConversionClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl ResourceConversionClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::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, - ) -> ResourceConversionClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, - { - ResourceConversionClient::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 - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// Convert objects to a target version - pub async fn convert_objects( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/pluginv2.ResourceConversion/ConvertObjects", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new("pluginv2.ResourceConversion", "ConvertObjects"), - ); + req.extensions_mut().insert(GrpcMethod::new("pluginv2.Data", "QueryData")); self.inner.unary(req, path, codec).await } } } /// Generated server implementations. -pub mod resource_server { +pub mod data_server { #![allow( unused_variables, dead_code, @@ -1457,32 +1058,26 @@ pub mod resource_server { clippy::let_unit_value, )] use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with ResourceServer. + /// Generated trait containing gRPC methods that should be implemented for use with DataServer. #[async_trait] - pub trait Resource: std::marker::Send + std::marker::Sync + 'static { - /// Server streaming response type for the CallResource method. - type CallResourceStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > - + std::marker::Send - + 'static; - async fn call_resource( + pub trait Data: std::marker::Send + std::marker::Sync + 'static { + async fn query_data( &self, - request: tonic::Request, + request: tonic::Request, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, >; } #[derive(Debug)] - pub struct ResourceServer { + pub struct DataServer { inner: Arc, accept_compression_encodings: EnabledCompressionEncodings, send_compression_encodings: EnabledCompressionEncodings, max_decoding_message_size: Option, max_encoding_message_size: Option, } - impl ResourceServer { + impl DataServer { pub fn new(inner: T) -> Self { Self::from_arc(Arc::new(inner)) } @@ -1533,9 +1128,9 @@ pub mod resource_server { self } } - impl tonic::codegen::Service> for ResourceServer + impl tonic::codegen::Service> for DataServer where - T: Resource, + T: Data, B: Body + std::marker::Send + 'static, B::Error: Into + std::marker::Send + 'static, { @@ -1550,26 +1145,23 @@ pub mod resource_server { } fn call(&mut self, req: http::Request) -> Self::Future { match req.uri().path() { - "/pluginv2.Resource/CallResource" => { + "/pluginv2.Data/QueryData" => { #[allow(non_camel_case_types)] - struct CallResourceSvc(pub Arc); - impl< - T: Resource, - > tonic::server::ServerStreamingService - for CallResourceSvc { - type Response = super::CallResourceResponse; - type ResponseStream = T::CallResourceStream; + struct QueryDataSvc(pub Arc); + impl tonic::server::UnaryService + for QueryDataSvc { + type Response = super::QueryDataResponse; type Future = BoxFuture< - tonic::Response, + tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::call_resource(&inner, request).await + ::query_data(&inner, request).await }; Box::pin(fut) } @@ -1580,8 +1172,8 @@ pub mod resource_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = CallResourceSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let method = QueryDataSvc(inner); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -1591,7 +1183,7 @@ pub mod resource_server { max_decoding_message_size, max_encoding_message_size, ); - let res = grpc.server_streaming(method, req).await; + let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) @@ -1618,7 +1210,7 @@ pub mod resource_server { } } } - impl Clone for ResourceServer { + impl Clone for DataServer { fn clone(&self) -> Self { let inner = self.inner.clone(); Self { @@ -1631,13 +1223,13 @@ pub mod resource_server { } } /// Generated gRPC service name - pub const SERVICE_NAME: &str = "pluginv2.Resource"; - impl tonic::server::NamedService for ResourceServer { + pub const SERVICE_NAME: &str = "pluginv2.Data"; + impl tonic::server::NamedService for DataServer { const NAME: &'static str = SERVICE_NAME; } } -/// Generated server implementations. -pub mod data_server { +/// Generated client implementations. +pub mod diagnostics_client { #![allow( unused_variables, dead_code, @@ -1646,57 +1238,69 @@ pub mod data_server { clippy::let_unit_value, )] use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with DataServer. - #[async_trait] - pub trait Data: std::marker::Send + std::marker::Sync + 'static { - async fn query_data( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct DiagnosticsClient { + inner: tonic::client::Grpc, } - #[derive(Debug)] - pub struct DataServer { - inner: Arc, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, + impl DiagnosticsClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } } - impl DataServer { + impl DiagnosticsClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) + let inner = tonic::client::Grpc::new(inner); + Self { inner } } - pub fn from_arc(inner: Arc) -> Self { - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } + 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, - ) -> InterceptedService + ) -> DiagnosticsClient> where F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, { - InterceptedService::new(Self::new(inner), interceptor) + DiagnosticsClient::new(InterceptedService::new(inner, interceptor)) } - /// Enable decompressing requests with the given encoding. + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); self } - /// Compress responses with the given encoding, if the client supports it. + /// Enable decompressing responses. #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); self } /// Limits the maximum size of a decoded message. @@ -1704,7 +1308,7 @@ pub mod data_server { /// Default: `4MB` #[must_use] pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); + self.inner = self.inner.max_decoding_message_size(limit); self } /// Limits the maximum size of an encoded message. @@ -1712,109 +1316,58 @@ pub mod data_server { /// Default: `usize::MAX` #[must_use] pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); + self.inner = self.inner.max_encoding_message_size(limit); self } - } - impl tonic::codegen::Service> for DataServer - where - T: Data, - B: Body + std::marker::Send + 'static, - B::Error: Into + std::marker::Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( + pub async fn check_health( &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - match req.uri().path() { - "/pluginv2.Data/QueryData" => { - #[allow(non_camel_case_types)] - struct QueryDataSvc(pub Arc); - impl tonic::server::UnaryService - for QueryDataSvc { - type Response = super::QueryDataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::query_data(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = QueryDataSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => { - Box::pin(async move { - let mut response = http::Response::new( - tonic::body::Body::default(), - ); - let headers = response.headers_mut(); - headers - .insert( - tonic::Status::GRPC_STATUS, - (tonic::Code::Unimplemented as i32).into(), - ); - headers - .insert( - http::header::CONTENT_TYPE, - tonic::metadata::GRPC_CONTENT_TYPE, - ); - Ok(response) - }) - } - } + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.Diagnostics/CheckHealth", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("pluginv2.Diagnostics", "CheckHealth")); + self.inner.unary(req, path, codec).await } - } - impl Clone for DataServer { - 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, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } + pub async fn collect_metrics( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.Diagnostics/CollectMetrics", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("pluginv2.Diagnostics", "CollectMetrics")); + self.inner.unary(req, path, codec).await } } - /// Generated gRPC service name - pub const SERVICE_NAME: &str = "pluginv2.Data"; - impl tonic::server::NamedService for DataServer { - const NAME: &'static str = SERVICE_NAME; - } } /// Generated server implementations. pub mod diagnostics_server { @@ -1950,7 +1503,7 @@ pub mod diagnostics_server { let inner = self.inner.clone(); let fut = async move { let method = CheckHealthSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -1995,7 +1548,7 @@ pub mod diagnostics_server { let inner = self.inner.clone(); let fut = async move { let method = CollectMetricsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2050,6 +1603,182 @@ pub mod diagnostics_server { const NAME: &'static str = SERVICE_NAME; } } +/// Generated client implementations. +pub mod stream_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct StreamClient { + inner: tonic::client::Grpc, + } + impl StreamClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl StreamClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::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, + ) -> StreamClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + StreamClient::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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// SubscribeStream called when a user tries to subscribe to a plugin/datasource + /// managed channel path – thus plugin can check subscribe permissions and communicate + /// options with Grafana Core. When the first subscriber joins a channel, RunStream + /// will be called. + pub async fn subscribe_stream( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.Stream/SubscribeStream", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("pluginv2.Stream", "SubscribeStream")); + self.inner.unary(req, path, codec).await + } + /// RunStream will be initiated by Grafana to consume a stream. RunStream will be + /// called once for the first client successfully subscribed to a channel path. + /// When Grafana detects that there are no longer any subscribers inside a channel, + /// the call will be terminated until next active subscriber appears. Call termination + /// can happen with a delay. + pub async fn run_stream( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.Stream/RunStream", + ); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("pluginv2.Stream", "RunStream")); + self.inner.server_streaming(req, path, codec).await + } + /// PublishStream called when a user tries to publish to a plugin/datasource + /// managed channel path. Here plugin can check publish permissions and + /// modify publication data if required. + pub async fn publish_stream( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.Stream/PublishStream", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("pluginv2.Stream", "PublishStream")); + self.inner.unary(req, path, codec).await + } + } +} /// Generated server implementations. pub mod stream_server { #![allow( @@ -2206,7 +1935,7 @@ pub mod stream_server { let inner = self.inner.clone(); let fut = async move { let method = SubscribeStreamSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2252,7 +1981,7 @@ pub mod stream_server { let inner = self.inner.clone(); let fut = async move { let method = RunStreamSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2297,7 +2026,7 @@ pub mod stream_server { let inner = self.inner.clone(); let fut = async move { let method = PublishStreamSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2334,22 +2063,171 @@ pub mod stream_server { } } } - impl Clone for StreamServer { - 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, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } + impl Clone for StreamServer { + 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, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "pluginv2.Stream"; + impl tonic::server::NamedService for StreamServer { + const NAME: &'static str = SERVICE_NAME; + } +} +/// Generated client implementations. +pub mod admission_control_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Admission control is a service based on the kubernetes admission webhook patterns. + /// This service can be used to verify if objects are valid and convert between versions + /// See: https://github.com/kubernetes/kubernetes/blob/v1.30.0/pkg/apis/admission/types.go#L41 + /// And: https://github.com/grafana/grafana-app-sdk/blob/main/resource/admission.go#L14 + #[derive(Debug, Clone)] + pub struct AdmissionControlClient { + inner: tonic::client::Grpc, + } + impl AdmissionControlClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl AdmissionControlClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::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, + ) -> AdmissionControlClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + AdmissionControlClient::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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Validate a resource -- the response is a simple yes/no + pub async fn validate_admission( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.AdmissionControl/ValidateAdmission", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("pluginv2.AdmissionControl", "ValidateAdmission"), + ); + self.inner.unary(req, path, codec).await + } + /// Return a modified copy of the request that can be saved or a descriptive error + pub async fn mutate_admission( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.AdmissionControl/MutateAdmission", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("pluginv2.AdmissionControl", "MutateAdmission")); + self.inner.unary(req, path, codec).await } - } - /// Generated gRPC service name - pub const SERVICE_NAME: &str = "pluginv2.Stream"; - impl tonic::server::NamedService for StreamServer { - const NAME: &'static str = SERVICE_NAME; } } /// Generated server implementations. @@ -2493,7 +2371,7 @@ pub mod admission_control_server { let inner = self.inner.clone(); let fut = async move { let method = ValidateAdmissionSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2539,7 +2417,7 @@ pub mod admission_control_server { let inner = self.inner.clone(); let fut = async move { let method = MutateAdmissionSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -2594,6 +2472,128 @@ pub mod admission_control_server { const NAME: &'static str = SERVICE_NAME; } } +/// Generated client implementations. +pub mod resource_conversion_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// ResourceConversion is a service that can be used to convert resources between versions + /// See: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-request-and-response + #[derive(Debug, Clone)] + pub struct ResourceConversionClient { + inner: tonic::client::Grpc, + } + impl ResourceConversionClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl ResourceConversionClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::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, + ) -> ResourceConversionClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + ResourceConversionClient::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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Convert objects to a target version + pub async fn convert_objects( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/pluginv2.ResourceConversion/ConvertObjects", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("pluginv2.ResourceConversion", "ConvertObjects"), + ); + self.inner.unary(req, path, codec).await + } + } +} /// Generated server implementations. pub mod resource_conversion_server { #![allow( @@ -2725,7 +2725,7 @@ pub mod resource_conversion_server { let inner = self.inner.clone(); let fut = async move { let method = ConvertObjectsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings,