diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dca806..0e8e6e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,5 +119,6 @@ jobs: with: toolchain: nightly-2023-04-18 command: doc + args: --all-features env: RUSTDOCFLAGS: "--cfg docsrs" diff --git a/Cargo.lock b/Cargo.lock index 2c38500..42d3178 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.20" @@ -44,17 +59,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "async-channel" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -150,6 +154,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -236,15 +255,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "convert_case" version = "0.4.0" @@ -267,15 +277,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - [[package]] name = "cxx" version = "1.0.94" @@ -349,12 +350,6 @@ dependencies = [ "regex", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "fnv" version = "1.0.7" @@ -476,6 +471,12 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "h2" version = "0.3.18" @@ -595,7 +596,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -755,16 +756,24 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -815,6 +824,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -867,9 +885,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -909,9 +927,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1110,6 +1128,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1320,6 +1344,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -1522,20 +1556,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1550,9 +1584,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -1952,7 +1986,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -1970,37 +2004,13 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -2104,10 +2114,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "ya-gcp" -version = "0.11.0" +version = "0.11.1" dependencies = [ "approx", - "async-channel", "async-stream", "cfg-if", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 8e30f0c..d124b4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ya-gcp" -version = "0.11.0" +version = "0.11.1" authors = ["Renar Narubin "] edition = "2021" description = "APIs for using Google Cloud Platform services" @@ -39,7 +39,7 @@ webpki-roots = ["dep:webpki-roots", "tonic?/tls-webpki-roots"] grpc = ["tonic", "prost", "prost-types", "tower", "derive_more"] bigtable = ["async-stream", "grpc", "prost", "tower"] -pubsub = ["grpc", "uuid", "async-stream", "pin-project", "async-channel", "tokio/time"] +pubsub = ["grpc", "uuid", "async-stream", "pin-project", "tokio/sync"] storage = ["tame-gcs", "tower"] # whether to include service emulator implementations. useful for testing @@ -57,12 +57,11 @@ rand = "0.8" rustls = "0.21.8" serde = { version = "1", features = ["derive"] } thiserror = "1" -tokio = { version = "1", features = ["time"] } +tokio = { version = "1.34", features = ["time"] } tracing = "0.1.37" yup-oauth2 = "8.3.0" async-stream = { version = "0.3", optional = true } -async-channel = { version = "1", optional = true } derive_more = { version = "0.99", optional = true } pin-project = { version = "1.0.11", optional = true } prost = { version = "0.12.3", optional = true } @@ -82,7 +81,7 @@ quickcheck = "1" quickcheck_macros = "1" serde_json = "1" structopt = "0.3" # for examples -tokio = { version = "1.4.0", features = ["rt-multi-thread", "time", "test-util"] } +tokio = { version = "1.34.0", features = ["rt-multi-thread", "time", "test-util"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-tree = "0.2" diff --git a/generators/src/grpc.rs b/generators/src/grpc.rs index a6bc095..55d8648 100644 --- a/generators/src/grpc.rs +++ b/generators/src/grpc.rs @@ -76,7 +76,9 @@ fn main() -> Result<(), Error> { tonic_build::configure() .build_client(true) - .build_server(false) + .build_server(true) // build servers for tests + .server_mod_attribute(".", "#[cfg(test)]") + .generate_default_stubs(true) .out_dir(&args.output_dir) .compile_with_config( prost_config, diff --git a/src/bigtable/mod.rs b/src/bigtable/mod.rs index cdf1540..97fdba9 100644 --- a/src/bigtable/mod.rs +++ b/src/bigtable/mod.rs @@ -30,7 +30,12 @@ pub use mutation::{MutateRowRequest, MutateRowsError, MutateRowsRequest}; #[cfg_attr(docsrs, doc(cfg(feature = "emulators")))] pub mod emulator; -#[allow(rustdoc::broken_intra_doc_links, rustdoc::bare_urls, missing_docs)] +#[allow( + rustdoc::broken_intra_doc_links, + rustdoc::bare_urls, + missing_docs, + unreachable_pub +)] pub mod api { pub mod rpc { include!("../generated/google.rpc.rs"); diff --git a/src/generated/google.bigtable.admin.v2.rs b/src/generated/google.bigtable.admin.v2.rs index 6c0a186..08cb0df 100644 --- a/src/generated/google.bigtable.admin.v2.rs +++ b/src/generated/google.bigtable.admin.v2.rs @@ -2469,3 +2469,1632 @@ pub mod bigtable_table_admin_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod bigtable_table_admin_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 BigtableTableAdminServer. + #[async_trait] + pub trait BigtableTableAdmin: Send + Sync + 'static { + /// Creates a new table in the specified instance. + /// The table can be created with a full set of initial column families, + /// specified in the request. + async fn create_table( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Creates a new table from the specified snapshot. The target table must + /// not exist. The snapshot and the table must be in the same instance. + /// + /// Note: This is a private alpha release of Cloud Bigtable snapshots. This + /// feature is not currently available to most Cloud Bigtable customers. This + /// feature might be changed in backward-incompatible ways and is not + /// recommended for production use. It is not subject to any SLA or deprecation + /// policy. + async fn create_table_from_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists all tables served from a specified instance. + async fn list_tables( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets metadata information about the specified table. + async fn get_table( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Updates a specified table. + async fn update_table( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Permanently deletes a specified table and all of its data. + async fn delete_table( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Restores a specified table which was accidentally deleted. + async fn undelete_table( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Performs a series of column family modifications on the specified table. + /// Either all or none of the modifications will occur before this method + /// returns, but data requests received prior to that point may see a table + /// where only some modifications have taken effect. + async fn modify_column_families( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Permanently drop/delete a row range from a specified table. The request can + /// specify whether to delete all rows in a table, or only those that match a + /// particular prefix. + async fn drop_row_range( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Generates a consistency token for a Table, which can be used in + /// CheckConsistency to check whether mutations to the table that finished + /// before this call started have been replicated. The tokens will be available + /// for 90 days. + async fn generate_consistency_token( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Checks replication consistency based on a consistency token, that is, if + /// replication has caught up based on the conditions specified in the token + /// and the check request. + async fn check_consistency( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Creates a new snapshot in the specified cluster from the specified + /// source table. The cluster and the table must be in the same instance. + /// + /// Note: This is a private alpha release of Cloud Bigtable snapshots. This + /// feature is not currently available to most Cloud Bigtable customers. This + /// feature might be changed in backward-incompatible ways and is not + /// recommended for production use. It is not subject to any SLA or deprecation + /// policy. + async fn snapshot_table( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets metadata information about the specified snapshot. + /// + /// Note: This is a private alpha release of Cloud Bigtable snapshots. This + /// feature is not currently available to most Cloud Bigtable customers. This + /// feature might be changed in backward-incompatible ways and is not + /// recommended for production use. It is not subject to any SLA or deprecation + /// policy. + async fn get_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists all snapshots associated with the specified cluster. + /// + /// Note: This is a private alpha release of Cloud Bigtable snapshots. This + /// feature is not currently available to most Cloud Bigtable customers. This + /// feature might be changed in backward-incompatible ways and is not + /// recommended for production use. It is not subject to any SLA or deprecation + /// policy. + async fn list_snapshots( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Permanently deletes the specified snapshot. + /// + /// Note: This is a private alpha release of Cloud Bigtable snapshots. This + /// feature is not currently available to most Cloud Bigtable customers. This + /// feature might be changed in backward-incompatible ways and is not + /// recommended for production use. It is not subject to any SLA or deprecation + /// policy. + async fn delete_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Starts creating a new Cloud Bigtable Backup. The returned backup + /// [long-running operation][google.longrunning.Operation] can be used to + /// track creation of the backup. The + /// [metadata][google.longrunning.Operation.metadata] field type is + /// [CreateBackupMetadata][google.bigtable.admin.v2.CreateBackupMetadata]. The + /// [response][google.longrunning.Operation.response] field type is + /// [Backup][google.bigtable.admin.v2.Backup], if successful. Cancelling the + /// returned operation will stop the creation and delete the backup. + async fn create_backup( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets metadata on a pending or completed Cloud Bigtable Backup. + async fn get_backup( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Updates a pending or completed Cloud Bigtable Backup. + async fn update_backup( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes a pending or completed Cloud Bigtable backup. + async fn delete_backup( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists Cloud Bigtable backups. Returns both completed and pending + /// backups. + async fn list_backups( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Create a new table by restoring from a completed backup. The + /// returned table [long-running operation][google.longrunning.Operation] can + /// be used to track the progress of the operation, and to cancel it. The + /// [metadata][google.longrunning.Operation.metadata] field type is + /// [RestoreTableMetadata][google.bigtable.admin.RestoreTableMetadata]. The + /// [response][google.longrunning.Operation.response] type is + /// [Table][google.bigtable.admin.v2.Table], if successful. + async fn restore_table( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Copy a Cloud Bigtable backup to a new backup in the destination cluster + /// located in the destination instance and project. + async fn copy_backup( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the access control policy for a Table or Backup resource. + /// Returns an empty policy if the resource exists but does not have a policy + /// set. + async fn get_iam_policy( + &self, + request: tonic::Request< + super::super::super::super::iam::v1::GetIamPolicyRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Sets the access control policy on a Table or Backup resource. + /// Replaces any existing policy. + async fn set_iam_policy( + &self, + request: tonic::Request< + super::super::super::super::iam::v1::SetIamPolicyRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Returns permissions that the caller has on the specified Table or Backup + /// resource. + async fn test_iam_permissions( + &self, + request: tonic::Request< + super::super::super::super::iam::v1::TestIamPermissionsRequest, + >, + ) -> std::result::Result< + tonic::Response< + super::super::super::super::iam::v1::TestIamPermissionsResponse, + >, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// Service for creating, configuring, and deleting Cloud Bigtable tables. + /// + /// + /// Provides access to the table schemas only, not the data stored within + /// the tables. + #[derive(Debug)] + pub struct BigtableTableAdminServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl BigtableTableAdminServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for BigtableTableAdminServer + where + T: BigtableTableAdmin, + 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() { + "/google.bigtable.admin.v2.BigtableTableAdmin/CreateTable" => { + #[allow(non_camel_case_types)] + struct CreateTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for CreateTableSvc { + type Response = super::Table; + 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 { + ::create_table(&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 inner = inner.0; + let method = CreateTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/CreateTableFromSnapshot" => { + #[allow(non_camel_case_types)] + struct CreateTableFromSnapshotSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for CreateTableFromSnapshotSvc { + type Response = super::super::super::super::longrunning::Operation; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::CreateTableFromSnapshotRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::create_table_from_snapshot( + &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 inner = inner.0; + let method = CreateTableFromSnapshotSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/ListTables" => { + #[allow(non_camel_case_types)] + struct ListTablesSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for ListTablesSvc { + type Response = super::ListTablesResponse; + 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 { + ::list_tables(&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 inner = inner.0; + let method = ListTablesSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/GetTable" => { + #[allow(non_camel_case_types)] + struct GetTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for GetTableSvc { + type Response = super::Table; + 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 { + ::get_table(&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 inner = inner.0; + let method = GetTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/UpdateTable" => { + #[allow(non_camel_case_types)] + struct UpdateTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for UpdateTableSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::update_table(&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 inner = inner.0; + let method = UpdateTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/DeleteTable" => { + #[allow(non_camel_case_types)] + struct DeleteTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for DeleteTableSvc { + type Response = (); + 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 { + ::delete_table(&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 inner = inner.0; + let method = DeleteTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/UndeleteTable" => { + #[allow(non_camel_case_types)] + struct UndeleteTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for UndeleteTableSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::undelete_table(&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 inner = inner.0; + let method = UndeleteTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/ModifyColumnFamilies" => { + #[allow(non_camel_case_types)] + struct ModifyColumnFamiliesSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for ModifyColumnFamiliesSvc { + type Response = super::Table; + 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 { + ::modify_column_families( + &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 inner = inner.0; + let method = ModifyColumnFamiliesSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/DropRowRange" => { + #[allow(non_camel_case_types)] + struct DropRowRangeSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for DropRowRangeSvc { + type Response = (); + 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 { + ::drop_row_range(&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 inner = inner.0; + let method = DropRowRangeSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/GenerateConsistencyToken" => { + #[allow(non_camel_case_types)] + struct GenerateConsistencyTokenSvc( + pub Arc, + ); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for GenerateConsistencyTokenSvc { + type Response = super::GenerateConsistencyTokenResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::GenerateConsistencyTokenRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::generate_consistency_token( + &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 inner = inner.0; + let method = GenerateConsistencyTokenSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/CheckConsistency" => { + #[allow(non_camel_case_types)] + struct CheckConsistencySvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for CheckConsistencySvc { + type Response = super::CheckConsistencyResponse; + 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 { + ::check_consistency( + &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 inner = inner.0; + let method = CheckConsistencySvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/SnapshotTable" => { + #[allow(non_camel_case_types)] + struct SnapshotTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for SnapshotTableSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::snapshot_table(&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 inner = inner.0; + let method = SnapshotTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/GetSnapshot" => { + #[allow(non_camel_case_types)] + struct GetSnapshotSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for GetSnapshotSvc { + type Response = super::Snapshot; + 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 { + ::get_snapshot(&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 inner = inner.0; + let method = GetSnapshotSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/ListSnapshots" => { + #[allow(non_camel_case_types)] + struct ListSnapshotsSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for ListSnapshotsSvc { + type Response = super::ListSnapshotsResponse; + 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 { + ::list_snapshots(&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 inner = inner.0; + let method = ListSnapshotsSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/DeleteSnapshot" => { + #[allow(non_camel_case_types)] + struct DeleteSnapshotSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for DeleteSnapshotSvc { + type Response = (); + 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 { + ::delete_snapshot(&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 inner = inner.0; + let method = DeleteSnapshotSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/CreateBackup" => { + #[allow(non_camel_case_types)] + struct CreateBackupSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for CreateBackupSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::create_backup(&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 inner = inner.0; + let method = CreateBackupSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/GetBackup" => { + #[allow(non_camel_case_types)] + struct GetBackupSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for GetBackupSvc { + type Response = super::Backup; + 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 { + ::get_backup(&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 inner = inner.0; + let method = GetBackupSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/UpdateBackup" => { + #[allow(non_camel_case_types)] + struct UpdateBackupSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for UpdateBackupSvc { + type Response = super::Backup; + 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 { + ::update_backup(&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 inner = inner.0; + let method = UpdateBackupSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/DeleteBackup" => { + #[allow(non_camel_case_types)] + struct DeleteBackupSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for DeleteBackupSvc { + type Response = (); + 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 { + ::delete_backup(&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 inner = inner.0; + let method = DeleteBackupSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/ListBackups" => { + #[allow(non_camel_case_types)] + struct ListBackupsSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for ListBackupsSvc { + type Response = super::ListBackupsResponse; + 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 { + ::list_backups(&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 inner = inner.0; + let method = ListBackupsSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/RestoreTable" => { + #[allow(non_camel_case_types)] + struct RestoreTableSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for RestoreTableSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::restore_table(&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 inner = inner.0; + let method = RestoreTableSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/CopyBackup" => { + #[allow(non_camel_case_types)] + struct CopyBackupSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService + for CopyBackupSvc { + type Response = super::super::super::super::longrunning::Operation; + 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 { + ::copy_backup(&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 inner = inner.0; + let method = CopyBackupSvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/GetIamPolicy" => { + #[allow(non_camel_case_types)] + struct GetIamPolicySvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService< + super::super::super::super::iam::v1::GetIamPolicyRequest, + > for GetIamPolicySvc { + type Response = super::super::super::super::iam::v1::Policy; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::super::super::super::iam::v1::GetIamPolicyRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_iam_policy(&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 inner = inner.0; + let method = GetIamPolicySvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/SetIamPolicy" => { + #[allow(non_camel_case_types)] + struct SetIamPolicySvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService< + super::super::super::super::iam::v1::SetIamPolicyRequest, + > for SetIamPolicySvc { + type Response = super::super::super::super::iam::v1::Policy; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::super::super::super::iam::v1::SetIamPolicyRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_iam_policy(&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 inner = inner.0; + let method = SetIamPolicySvc(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) + } + "/google.bigtable.admin.v2.BigtableTableAdmin/TestIamPermissions" => { + #[allow(non_camel_case_types)] + struct TestIamPermissionsSvc(pub Arc); + impl< + T: BigtableTableAdmin, + > tonic::server::UnaryService< + super::super::super::super::iam::v1::TestIamPermissionsRequest, + > for TestIamPermissionsSvc { + type Response = super::super::super::super::iam::v1::TestIamPermissionsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::super::super::super::iam::v1::TestIamPermissionsRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::test_iam_permissions( + &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 inner = inner.0; + let method = TestIamPermissionsSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for BigtableTableAdminServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 BigtableTableAdminServer { + const NAME: &'static str = "google.bigtable.admin.v2.BigtableTableAdmin"; + } +} diff --git a/src/generated/google.bigtable.v2.rs b/src/generated/google.bigtable.v2.rs index c228efc..95820d9 100644 --- a/src/generated/google.bigtable.v2.rs +++ b/src/generated/google.bigtable.v2.rs @@ -1880,3 +1880,678 @@ pub mod bigtable_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod bigtable_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 BigtableServer. + #[async_trait] + pub trait Bigtable: Send + Sync + 'static { + /// Streams back the contents of all requested rows in key order, optionally + /// applying the same Reader filter to each. Depending on their size, + /// rows and cells may be broken up across multiple responses, but + /// atomicity of each row will still be preserved. See the + /// ReadRowsResponse documentation for details. + async fn read_rows( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Returns a sample of row keys in the table. The returned row keys will + /// delimit contiguous sections of the table of approximately equal size, + /// which can be used to break up the data for distributed tasks like + /// mapreduces. + async fn sample_row_keys( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Mutates a row atomically. Cells already present in the row are left + /// unchanged unless explicitly changed by `mutation`. + async fn mutate_row( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Mutates multiple rows in a batch. Each individual row is mutated + /// atomically as in MutateRow, but the entire batch is not executed + /// atomically. + async fn mutate_rows( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Mutates a row atomically based on the output of a predicate Reader filter. + async fn check_and_mutate_row( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Warm up associated instance metadata for this connection. + /// This call is not required but may be useful for connection keep-alive. + async fn ping_and_warm( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Modifies a row atomically on the server. The method reads the latest + /// existing timestamp and value from the specified columns and writes a new + /// entry based on pre-defined read/modify/write rules. The new value for the + /// timestamp is the greater of the existing timestamp or the current server + /// time. The method returns the new contents of all modified cells. + async fn read_modify_write_row( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// NOTE: This API is intended to be used by Apache Beam BigtableIO. + /// Returns the current list of partitions that make up the table's + /// change stream. The union of partitions will cover the entire keyspace. + /// Partitions can be read with `ReadChangeStream`. + async fn generate_initial_change_stream_partitions( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response< + BoxStream, + >, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// NOTE: This API is intended to be used by Apache Beam BigtableIO. + /// Reads changes from a table's change stream. Changes will + /// reflect both user-initiated mutations and mutations that are caused by + /// garbage collection. + async fn read_change_stream( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// Service for reading from and writing to existing Bigtable tables. + #[derive(Debug)] + pub struct BigtableServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl BigtableServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for BigtableServer + where + T: Bigtable, + 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() { + "/google.bigtable.v2.Bigtable/ReadRows" => { + #[allow(non_camel_case_types)] + struct ReadRowsSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::ServerStreamingService + for ReadRowsSvc { + type Response = super::ReadRowsResponse; + type ResponseStream = BoxStream; + 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 { + ::read_rows(&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 inner = inner.0; + let method = ReadRowsSvc(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.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/google.bigtable.v2.Bigtable/SampleRowKeys" => { + #[allow(non_camel_case_types)] + struct SampleRowKeysSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::ServerStreamingService + for SampleRowKeysSvc { + type Response = super::SampleRowKeysResponse; + type ResponseStream = BoxStream; + 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 { + ::sample_row_keys(&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 inner = inner.0; + let method = SampleRowKeysSvc(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.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/google.bigtable.v2.Bigtable/MutateRow" => { + #[allow(non_camel_case_types)] + struct MutateRowSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::UnaryService + for MutateRowSvc { + type Response = super::MutateRowResponse; + 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 { + ::mutate_row(&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 inner = inner.0; + let method = MutateRowSvc(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) + } + "/google.bigtable.v2.Bigtable/MutateRows" => { + #[allow(non_camel_case_types)] + struct MutateRowsSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::ServerStreamingService + for MutateRowsSvc { + type Response = super::MutateRowsResponse; + type ResponseStream = BoxStream; + 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 { + ::mutate_rows(&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 inner = inner.0; + let method = MutateRowsSvc(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.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/google.bigtable.v2.Bigtable/CheckAndMutateRow" => { + #[allow(non_camel_case_types)] + struct CheckAndMutateRowSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::UnaryService + for CheckAndMutateRowSvc { + type Response = super::CheckAndMutateRowResponse; + 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 { + ::check_and_mutate_row(&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 inner = inner.0; + let method = CheckAndMutateRowSvc(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) + } + "/google.bigtable.v2.Bigtable/PingAndWarm" => { + #[allow(non_camel_case_types)] + struct PingAndWarmSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::UnaryService + for PingAndWarmSvc { + type Response = super::PingAndWarmResponse; + 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 { + ::ping_and_warm(&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 inner = inner.0; + let method = PingAndWarmSvc(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) + } + "/google.bigtable.v2.Bigtable/ReadModifyWriteRow" => { + #[allow(non_camel_case_types)] + struct ReadModifyWriteRowSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::UnaryService + for ReadModifyWriteRowSvc { + type Response = super::ReadModifyWriteRowResponse; + 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 { + ::read_modify_write_row(&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 inner = inner.0; + let method = ReadModifyWriteRowSvc(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) + } + "/google.bigtable.v2.Bigtable/GenerateInitialChangeStreamPartitions" => { + #[allow(non_camel_case_types)] + struct GenerateInitialChangeStreamPartitionsSvc( + pub Arc, + ); + impl< + T: Bigtable, + > tonic::server::ServerStreamingService< + super::GenerateInitialChangeStreamPartitionsRequest, + > for GenerateInitialChangeStreamPartitionsSvc { + type Response = super::GenerateInitialChangeStreamPartitionsResponse; + type ResponseStream = BoxStream< + super::GenerateInitialChangeStreamPartitionsResponse, + >; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::GenerateInitialChangeStreamPartitionsRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::generate_initial_change_stream_partitions( + &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 inner = inner.0; + let method = GenerateInitialChangeStreamPartitionsSvc(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.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/google.bigtable.v2.Bigtable/ReadChangeStream" => { + #[allow(non_camel_case_types)] + struct ReadChangeStreamSvc(pub Arc); + impl< + T: Bigtable, + > tonic::server::ServerStreamingService< + super::ReadChangeStreamRequest, + > for ReadChangeStreamSvc { + type Response = super::ReadChangeStreamResponse; + type ResponseStream = BoxStream; + 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 { + ::read_change_stream(&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 inner = inner.0; + let method = ReadChangeStreamSvc(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.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 BigtableServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 BigtableServer { + const NAME: &'static str = "google.bigtable.v2.Bigtable"; + } +} diff --git a/src/generated/google.iam.v1.rs b/src/generated/google.iam.v1.rs index c1ab902..bcc034d 100644 --- a/src/generated/google.iam.v1.rs +++ b/src/generated/google.iam.v1.rs @@ -652,3 +652,332 @@ pub mod iam_policy_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod iam_policy_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 IamPolicyServer. + #[async_trait] + pub trait IamPolicy: Send + Sync + 'static { + /// Sets the access control policy on the specified resource. Replaces any + /// existing policy. + /// + /// Can return `NOT_FOUND`, `INVALID_ARGUMENT`, and `PERMISSION_DENIED` errors. + async fn set_iam_policy( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the access control policy for a resource. + /// Returns an empty policy if the resource exists and does not have a policy + /// set. + async fn get_iam_policy( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Returns permissions that a caller has on the specified resource. + /// If the resource does not exist, this will return an empty set of + /// permissions, not a `NOT_FOUND` error. + /// + /// Note: This operation is designed to be used for building permission-aware + /// UIs and command-line tools, not for authorization checking. This operation + /// may "fail open" without warning. + async fn test_iam_permissions( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// API Overview + /// + /// + /// Manages Identity and Access Management (IAM) policies. + /// + /// Any implementation of an API that offers access control features + /// implements the google.iam.v1.IAMPolicy interface. + /// + /// ## Data model + /// + /// Access control is applied when a principal (user or service account), takes + /// some action on a resource exposed by a service. Resources, identified by + /// URI-like names, are the unit of access control specification. Service + /// implementations can choose the granularity of access control and the + /// supported permissions for their resources. + /// For example one database service may allow access control to be + /// specified only at the Table level, whereas another might allow access control + /// to also be specified at the Column level. + /// + /// ## Policy Structure + /// + /// See google.iam.v1.Policy + /// + /// This is intentionally not a CRUD style API because access control policies + /// are created and deleted implicitly with the resources to which they are + /// attached. + #[derive(Debug)] + pub struct IamPolicyServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl IamPolicyServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for IamPolicyServer + where + T: IamPolicy, + 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() { + "/google.iam.v1.IAMPolicy/SetIamPolicy" => { + #[allow(non_camel_case_types)] + struct SetIamPolicySvc(pub Arc); + impl< + T: IamPolicy, + > tonic::server::UnaryService + for SetIamPolicySvc { + type Response = super::Policy; + 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 { + ::set_iam_policy(&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 inner = inner.0; + let method = SetIamPolicySvc(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) + } + "/google.iam.v1.IAMPolicy/GetIamPolicy" => { + #[allow(non_camel_case_types)] + struct GetIamPolicySvc(pub Arc); + impl< + T: IamPolicy, + > tonic::server::UnaryService + for GetIamPolicySvc { + type Response = super::Policy; + 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 { + ::get_iam_policy(&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 inner = inner.0; + let method = GetIamPolicySvc(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) + } + "/google.iam.v1.IAMPolicy/TestIamPermissions" => { + #[allow(non_camel_case_types)] + struct TestIamPermissionsSvc(pub Arc); + impl< + T: IamPolicy, + > tonic::server::UnaryService + for TestIamPermissionsSvc { + type Response = super::TestIamPermissionsResponse; + 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 { + ::test_iam_permissions(&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 inner = inner.0; + let method = TestIamPermissionsSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for IamPolicyServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 IamPolicyServer { + const NAME: &'static str = "google.iam.v1.IAMPolicy"; + } +} diff --git a/src/generated/google.longrunning.rs b/src/generated/google.longrunning.rs index cd10e2a..d1b1880 100644 --- a/src/generated/google.longrunning.rs +++ b/src/generated/google.longrunning.rs @@ -411,3 +411,440 @@ pub mod operations_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod operations_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 OperationsServer. + #[async_trait] + pub trait Operations: Send + Sync + 'static { + /// Lists operations that match the specified filter in the request. If the + /// server doesn't support this method, it returns `UNIMPLEMENTED`. + /// + /// NOTE: the `name` binding allows API services to override the binding + /// to use different resource name schemes, such as `users/*/operations`. To + /// override the binding, API services can add a binding such as + /// `"/v1/{name=users/*}/operations"` to their service configuration. + /// For backwards compatibility, the default name includes the operations + /// collection id, however overriding users must ensure the name binding + /// is the parent resource, without the operations collection id. + async fn list_operations( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the latest state of a long-running operation. Clients can use this + /// method to poll the operation result at intervals as recommended by the API + /// service. + async fn get_operation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes a long-running operation. This method indicates that the client is + /// no longer interested in the operation result. It does not cancel the + /// operation. If the server doesn't support this method, it returns + /// `google.rpc.Code.UNIMPLEMENTED`. + async fn delete_operation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Starts asynchronous cancellation on a long-running operation. The server + /// makes a best effort to cancel the operation, but success is not + /// guaranteed. If the server doesn't support this method, it returns + /// `google.rpc.Code.UNIMPLEMENTED`. Clients can use + /// [Operations.GetOperation][google.longrunning.Operations.GetOperation] or + /// other methods to check whether the cancellation succeeded or whether the + /// operation completed despite cancellation. On successful cancellation, + /// the operation is not deleted; instead, it becomes an operation with + /// an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, + /// corresponding to `Code.CANCELLED`. + async fn cancel_operation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Waits until the specified long-running operation is done or reaches at most + /// a specified timeout, returning the latest state. If the operation is + /// already done, the latest state is immediately returned. If the timeout + /// specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + /// timeout is used. If the server does not support this method, it returns + /// `google.rpc.Code.UNIMPLEMENTED`. + /// Note that this method is on a best-effort basis. It may return the latest + /// state before the specified timeout (including immediately), meaning even an + /// immediate response is no guarantee that the operation is done. + async fn wait_operation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// Manages long-running operations with an API service. + /// + /// When an API method normally takes long time to complete, it can be designed + /// to return [Operation][google.longrunning.Operation] to the client, and the client can use this + /// interface to receive the real response asynchronously by polling the + /// operation resource, or pass the operation resource to another API (such as + /// Google Cloud Pub/Sub API) to receive the response. Any API service that + /// returns long-running operations should implement the `Operations` interface + /// so developers can have a consistent client experience. + #[derive(Debug)] + pub struct OperationsServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl OperationsServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for OperationsServer + where + T: Operations, + 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() { + "/google.longrunning.Operations/ListOperations" => { + #[allow(non_camel_case_types)] + struct ListOperationsSvc(pub Arc); + impl< + T: Operations, + > tonic::server::UnaryService + for ListOperationsSvc { + type Response = super::ListOperationsResponse; + 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 { + ::list_operations(&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 inner = inner.0; + let method = ListOperationsSvc(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) + } + "/google.longrunning.Operations/GetOperation" => { + #[allow(non_camel_case_types)] + struct GetOperationSvc(pub Arc); + impl< + T: Operations, + > tonic::server::UnaryService + for GetOperationSvc { + type Response = super::Operation; + 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 { + ::get_operation(&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 inner = inner.0; + let method = GetOperationSvc(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) + } + "/google.longrunning.Operations/DeleteOperation" => { + #[allow(non_camel_case_types)] + struct DeleteOperationSvc(pub Arc); + impl< + T: Operations, + > tonic::server::UnaryService + for DeleteOperationSvc { + type Response = (); + 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 { + ::delete_operation(&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 inner = inner.0; + let method = DeleteOperationSvc(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) + } + "/google.longrunning.Operations/CancelOperation" => { + #[allow(non_camel_case_types)] + struct CancelOperationSvc(pub Arc); + impl< + T: Operations, + > tonic::server::UnaryService + for CancelOperationSvc { + type Response = (); + 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 { + ::cancel_operation(&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 inner = inner.0; + let method = CancelOperationSvc(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) + } + "/google.longrunning.Operations/WaitOperation" => { + #[allow(non_camel_case_types)] + struct WaitOperationSvc(pub Arc); + impl< + T: Operations, + > tonic::server::UnaryService + for WaitOperationSvc { + type Response = super::Operation; + 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 { + ::wait_operation(&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 inner = inner.0; + let method = WaitOperationSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for OperationsServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 OperationsServer { + const NAME: &'static str = "google.longrunning.Operations"; + } +} diff --git a/src/generated/google.pubsub.v1.rs b/src/generated/google.pubsub.v1.rs index 109e8f5..80e9838 100644 --- a/src/generated/google.pubsub.v1.rs +++ b/src/generated/google.pubsub.v1.rs @@ -716,6 +716,684 @@ pub mod schema_service_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod schema_service_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 SchemaServiceServer. + #[async_trait] + pub trait SchemaService: Send + Sync + 'static { + /// Creates a schema. + async fn create_schema( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets a schema. + async fn get_schema( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists schemas in a project. + async fn list_schemas( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists all schema revisions for the named schema. + async fn list_schema_revisions( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Commits a new schema revision to an existing schema. + async fn commit_schema( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Creates a new schema revision that is a copy of the provided revision_id. + async fn rollback_schema( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes a specific schema revision. + async fn delete_schema_revision( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes a schema. + async fn delete_schema( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Validates a schema. + async fn validate_schema( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Validates a message against a schema. + async fn validate_message( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// Service for doing schema-related operations. + #[derive(Debug)] + pub struct SchemaServiceServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl SchemaServiceServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for SchemaServiceServer + where + T: SchemaService, + 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() { + "/google.pubsub.v1.SchemaService/CreateSchema" => { + #[allow(non_camel_case_types)] + struct CreateSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for CreateSchemaSvc { + type Response = super::Schema; + 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 { + ::create_schema(&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 inner = inner.0; + let method = CreateSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/GetSchema" => { + #[allow(non_camel_case_types)] + struct GetSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for GetSchemaSvc { + type Response = super::Schema; + 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 { + ::get_schema(&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 inner = inner.0; + let method = GetSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/ListSchemas" => { + #[allow(non_camel_case_types)] + struct ListSchemasSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for ListSchemasSvc { + type Response = super::ListSchemasResponse; + 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 { + ::list_schemas(&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 inner = inner.0; + let method = ListSchemasSvc(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) + } + "/google.pubsub.v1.SchemaService/ListSchemaRevisions" => { + #[allow(non_camel_case_types)] + struct ListSchemaRevisionsSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for ListSchemaRevisionsSvc { + type Response = super::ListSchemaRevisionsResponse; + 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 { + ::list_schema_revisions(&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 inner = inner.0; + let method = ListSchemaRevisionsSvc(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) + } + "/google.pubsub.v1.SchemaService/CommitSchema" => { + #[allow(non_camel_case_types)] + struct CommitSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for CommitSchemaSvc { + type Response = super::Schema; + 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 { + ::commit_schema(&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 inner = inner.0; + let method = CommitSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/RollbackSchema" => { + #[allow(non_camel_case_types)] + struct RollbackSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for RollbackSchemaSvc { + type Response = super::Schema; + 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 { + ::rollback_schema(&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 inner = inner.0; + let method = RollbackSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/DeleteSchemaRevision" => { + #[allow(non_camel_case_types)] + struct DeleteSchemaRevisionSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for DeleteSchemaRevisionSvc { + type Response = super::Schema; + 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 { + ::delete_schema_revision( + &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 inner = inner.0; + let method = DeleteSchemaRevisionSvc(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) + } + "/google.pubsub.v1.SchemaService/DeleteSchema" => { + #[allow(non_camel_case_types)] + struct DeleteSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for DeleteSchemaSvc { + type Response = (); + 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 { + ::delete_schema(&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 inner = inner.0; + let method = DeleteSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/ValidateSchema" => { + #[allow(non_camel_case_types)] + struct ValidateSchemaSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for ValidateSchemaSvc { + type Response = super::ValidateSchemaResponse; + 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 { + ::validate_schema(&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 inner = inner.0; + let method = ValidateSchemaSvc(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) + } + "/google.pubsub.v1.SchemaService/ValidateMessage" => { + #[allow(non_camel_case_types)] + struct ValidateMessageSvc(pub Arc); + impl< + T: SchemaService, + > tonic::server::UnaryService + for ValidateMessageSvc { + type Response = super::ValidateMessageResponse; + 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 { + ::validate_message(&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 inner = inner.0; + let method = ValidateMessageSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for SchemaServiceServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 SchemaServiceServer { + const NAME: &'static str = "google.pubsub.v1.SchemaService"; + } +} /// A policy constraining the storage of messages published to the topic. #[non_exhaustive] #[allow(clippy::derive_partial_eq_without_eq)] @@ -3060,3 +3738,1705 @@ pub mod subscriber_client { } } } +/// Generated server implementations. +#[cfg(test)] +pub mod publisher_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 PublisherServer. + #[async_trait] + pub trait Publisher: Send + Sync + 'static { + /// Creates the given topic with the given name. See the [resource name rules] + /// (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). + async fn create_topic( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Updates an existing topic. Note that certain properties of a + /// topic are not modifiable. + async fn update_topic( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Adds one or more messages to the topic. Returns `NOT_FOUND` if the topic + /// does not exist. + async fn publish( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the configuration of a topic. + async fn get_topic( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists matching topics. + async fn list_topics( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists the names of the attached subscriptions on this topic. + async fn list_topic_subscriptions( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists the names of the snapshots on this topic. Snapshots are used in + /// [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + /// which allow you to manage message acknowledgments in bulk. That is, you can + /// set the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + async fn list_topic_snapshots( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes the topic with the given name. Returns `NOT_FOUND` if the topic + /// does not exist. After a topic is deleted, a new topic may be created with + /// the same name; this is an entirely new topic with none of the old + /// configuration or subscriptions. Existing subscriptions to this topic are + /// not deleted, but their `topic` field is set to `_deleted-topic_`. + async fn delete_topic( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Detaches a subscription from this topic. All messages retained in the + /// subscription are dropped. Subsequent `Pull` and `StreamingPull` requests + /// will return FAILED_PRECONDITION. If the subscription is a push + /// subscription, pushes to the endpoint will stop. + async fn detach_subscription( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// The service that an application uses to manipulate topics, and to send + /// messages to a topic. + #[derive(Debug)] + pub struct PublisherServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl PublisherServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for PublisherServer + where + T: Publisher, + 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() { + "/google.pubsub.v1.Publisher/CreateTopic" => { + #[allow(non_camel_case_types)] + struct CreateTopicSvc(pub Arc); + impl tonic::server::UnaryService + for CreateTopicSvc { + type Response = super::Topic; + 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 { + ::create_topic(&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 inner = inner.0; + let method = CreateTopicSvc(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) + } + "/google.pubsub.v1.Publisher/UpdateTopic" => { + #[allow(non_camel_case_types)] + struct UpdateTopicSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for UpdateTopicSvc { + type Response = super::Topic; + 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 { + ::update_topic(&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 inner = inner.0; + let method = UpdateTopicSvc(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) + } + "/google.pubsub.v1.Publisher/Publish" => { + #[allow(non_camel_case_types)] + struct PublishSvc(pub Arc); + impl tonic::server::UnaryService + for PublishSvc { + type Response = super::PublishResponse; + 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 { + ::publish(&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 inner = inner.0; + let method = PublishSvc(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) + } + "/google.pubsub.v1.Publisher/GetTopic" => { + #[allow(non_camel_case_types)] + struct GetTopicSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for GetTopicSvc { + type Response = super::Topic; + 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 { + ::get_topic(&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 inner = inner.0; + let method = GetTopicSvc(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) + } + "/google.pubsub.v1.Publisher/ListTopics" => { + #[allow(non_camel_case_types)] + struct ListTopicsSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for ListTopicsSvc { + type Response = super::ListTopicsResponse; + 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 { + ::list_topics(&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 inner = inner.0; + let method = ListTopicsSvc(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) + } + "/google.pubsub.v1.Publisher/ListTopicSubscriptions" => { + #[allow(non_camel_case_types)] + struct ListTopicSubscriptionsSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for ListTopicSubscriptionsSvc { + type Response = super::ListTopicSubscriptionsResponse; + 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 { + ::list_topic_subscriptions(&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 inner = inner.0; + let method = ListTopicSubscriptionsSvc(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) + } + "/google.pubsub.v1.Publisher/ListTopicSnapshots" => { + #[allow(non_camel_case_types)] + struct ListTopicSnapshotsSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for ListTopicSnapshotsSvc { + type Response = super::ListTopicSnapshotsResponse; + 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 { + ::list_topic_snapshots(&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 inner = inner.0; + let method = ListTopicSnapshotsSvc(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) + } + "/google.pubsub.v1.Publisher/DeleteTopic" => { + #[allow(non_camel_case_types)] + struct DeleteTopicSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for DeleteTopicSvc { + type Response = (); + 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 { + ::delete_topic(&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 inner = inner.0; + let method = DeleteTopicSvc(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) + } + "/google.pubsub.v1.Publisher/DetachSubscription" => { + #[allow(non_camel_case_types)] + struct DetachSubscriptionSvc(pub Arc); + impl< + T: Publisher, + > tonic::server::UnaryService + for DetachSubscriptionSvc { + type Response = super::DetachSubscriptionResponse; + 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 { + ::detach_subscription(&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 inner = inner.0; + let method = DetachSubscriptionSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for PublisherServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 PublisherServer { + const NAME: &'static str = "google.pubsub.v1.Publisher"; + } +} +/// Generated server implementations. +#[cfg(test)] +pub mod subscriber_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 SubscriberServer. + #[async_trait] + pub trait Subscriber: Send + Sync + 'static { + /// Creates a subscription to a given topic. See the [resource name rules] + /// (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). + /// If the subscription already exists, returns `ALREADY_EXISTS`. + /// If the corresponding topic doesn't exist, returns `NOT_FOUND`. + /// + /// If the name is not provided in the request, the server will assign a random + /// name for this subscription on the same project as the topic, conforming + /// to the [resource name format] + /// (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). The + /// generated name is populated in the returned Subscription object. Note that + /// for REST API requests, you must specify a name in the request. + async fn create_subscription( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the configuration details of a subscription. + async fn get_subscription( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Updates an existing subscription. Note that certain properties of a + /// subscription, such as its topic, are not modifiable. + async fn update_subscription( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists matching subscriptions. + async fn list_subscriptions( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Deletes an existing subscription. All messages retained in the subscription + /// are immediately dropped. Calls to `Pull` after deletion will return + /// `NOT_FOUND`. After a subscription is deleted, a new one may be created with + /// the same name, but the new one has no association with the old + /// subscription or its topic unless the same topic is specified. + async fn delete_subscription( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Modifies the ack deadline for a specific message. This method is useful + /// to indicate that more time is needed to process a message by the + /// subscriber, or to make the message available for redelivery if the + /// processing was interrupted. Note that this does not modify the + /// subscription-level `ackDeadlineSeconds` used for subsequent messages. + async fn modify_ack_deadline( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Acknowledges the messages associated with the `ack_ids` in the + /// `AcknowledgeRequest`. The Pub/Sub system can remove the relevant messages + /// from the subscription. + /// + /// Acknowledging a message whose ack deadline has expired may succeed, + /// but such a message may be redelivered later. Acknowledging a message more + /// than once will not result in an error. + async fn acknowledge( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Pulls messages from the server. + async fn pull( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Establishes a stream with the server, which sends messages down to the + /// client. The client streams acknowledgements and ack deadline modifications + /// back to the server. The server will close the stream and return the status + /// on any error. The server may close the stream with status `UNAVAILABLE` to + /// reassign server-side resources, in which case, the client should + /// re-establish the stream. Flow control can be achieved by configuring the + /// underlying RPC channel. + async fn streaming_pull( + &self, + request: tonic::Request>, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Modifies the `PushConfig` for a specified subscription. + /// + /// This may be used to change a push subscription to a pull one (signified by + /// an empty `PushConfig`) or vice versa, or change the endpoint URL and other + /// attributes of a push subscription. Messages will accumulate for delivery + /// continuously through the call regardless of changes to the `PushConfig`. + async fn modify_push_config( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Gets the configuration details of a snapshot. Snapshots are used in + /// [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + /// which allow you to manage message acknowledgments in bulk. That is, you can + /// set the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + async fn get_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Lists the existing snapshots. Snapshots are used in [Seek]( + /// https://cloud.google.com/pubsub/docs/replay-overview) operations, which + /// allow you to manage message acknowledgments in bulk. That is, you can set + /// the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + async fn list_snapshots( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Creates a snapshot from the requested subscription. Snapshots are used in + /// [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + /// which allow you to manage message acknowledgments in bulk. That is, you can + /// set the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + /// If the snapshot already exists, returns `ALREADY_EXISTS`. + /// If the requested subscription doesn't exist, returns `NOT_FOUND`. + /// If the backlog in the subscription is too old -- and the resulting snapshot + /// would expire in less than 1 hour -- then `FAILED_PRECONDITION` is returned. + /// See also the `Snapshot.expire_time` field. If the name is not provided in + /// the request, the server will assign a random + /// name for this snapshot on the same project as the subscription, conforming + /// to the [resource name format] + /// (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). The + /// generated name is populated in the returned Snapshot object. Note that for + /// REST API requests, you must specify a name in the request. + async fn create_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Updates an existing snapshot. Snapshots are used in + /// [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + /// which allow you to manage message acknowledgments in bulk. That is, you can + /// set the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + async fn update_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Removes an existing snapshot. Snapshots are used in [Seek] + /// (https://cloud.google.com/pubsub/docs/replay-overview) operations, which + /// allow you to manage message acknowledgments in bulk. That is, you can set + /// the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. + /// When the snapshot is deleted, all messages retained in the snapshot + /// are immediately dropped. After a snapshot is deleted, a new one may be + /// created with the same name, but the new one has no association with the old + /// snapshot or its subscription, unless the same subscription is specified. + async fn delete_snapshot( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + /// Seeks an existing subscription to a point in time or to a given snapshot, + /// whichever is provided in the request. Snapshots are used in [Seek] + /// (https://cloud.google.com/pubsub/docs/replay-overview) operations, which + /// allow you to manage message acknowledgments in bulk. That is, you can set + /// the acknowledgment state of messages in an existing subscription to the + /// state captured by a snapshot. Note that both the subscription and the + /// snapshot must be on the same topic. + async fn seek( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Err(tonic::Status::unimplemented("Not yet implemented")) + } + } + /// The service that an application uses to manipulate subscriptions and to + /// consume messages from a subscription via the `Pull` method or by + /// establishing a bi-directional stream using the `StreamingPull` method. + #[derive(Debug)] + pub struct SubscriberServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl SubscriberServer { + 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(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + 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 + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(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.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for SubscriberServer + where + T: Subscriber, + 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() { + "/google.pubsub.v1.Subscriber/CreateSubscription" => { + #[allow(non_camel_case_types)] + struct CreateSubscriptionSvc(pub Arc); + impl tonic::server::UnaryService + for CreateSubscriptionSvc { + type Response = super::Subscription; + 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 { + ::create_subscription(&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 inner = inner.0; + let method = CreateSubscriptionSvc(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) + } + "/google.pubsub.v1.Subscriber/GetSubscription" => { + #[allow(non_camel_case_types)] + struct GetSubscriptionSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for GetSubscriptionSvc { + type Response = super::Subscription; + 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 { + ::get_subscription(&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 inner = inner.0; + let method = GetSubscriptionSvc(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) + } + "/google.pubsub.v1.Subscriber/UpdateSubscription" => { + #[allow(non_camel_case_types)] + struct UpdateSubscriptionSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for UpdateSubscriptionSvc { + type Response = super::Subscription; + 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 { + ::update_subscription(&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 inner = inner.0; + let method = UpdateSubscriptionSvc(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) + } + "/google.pubsub.v1.Subscriber/ListSubscriptions" => { + #[allow(non_camel_case_types)] + struct ListSubscriptionsSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for ListSubscriptionsSvc { + type Response = super::ListSubscriptionsResponse; + 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 { + ::list_subscriptions(&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 inner = inner.0; + let method = ListSubscriptionsSvc(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) + } + "/google.pubsub.v1.Subscriber/DeleteSubscription" => { + #[allow(non_camel_case_types)] + struct DeleteSubscriptionSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for DeleteSubscriptionSvc { + type Response = (); + 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 { + ::delete_subscription(&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 inner = inner.0; + let method = DeleteSubscriptionSvc(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) + } + "/google.pubsub.v1.Subscriber/ModifyAckDeadline" => { + #[allow(non_camel_case_types)] + struct ModifyAckDeadlineSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for ModifyAckDeadlineSvc { + type Response = (); + 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 { + ::modify_ack_deadline(&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 inner = inner.0; + let method = ModifyAckDeadlineSvc(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) + } + "/google.pubsub.v1.Subscriber/Acknowledge" => { + #[allow(non_camel_case_types)] + struct AcknowledgeSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for AcknowledgeSvc { + type Response = (); + 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 { + ::acknowledge(&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 inner = inner.0; + let method = AcknowledgeSvc(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) + } + "/google.pubsub.v1.Subscriber/Pull" => { + #[allow(non_camel_case_types)] + struct PullSvc(pub Arc); + impl tonic::server::UnaryService + for PullSvc { + type Response = super::PullResponse; + 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 { + ::pull(&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 inner = inner.0; + let method = PullSvc(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) + } + "/google.pubsub.v1.Subscriber/StreamingPull" => { + #[allow(non_camel_case_types)] + struct StreamingPullSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::StreamingService + for StreamingPullSvc { + type Response = super::StreamingPullResponse; + type ResponseStream = BoxStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::streaming_pull(&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 inner = inner.0; + let method = StreamingPullSvc(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.streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/google.pubsub.v1.Subscriber/ModifyPushConfig" => { + #[allow(non_camel_case_types)] + struct ModifyPushConfigSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for ModifyPushConfigSvc { + type Response = (); + 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 { + ::modify_push_config(&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 inner = inner.0; + let method = ModifyPushConfigSvc(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) + } + "/google.pubsub.v1.Subscriber/GetSnapshot" => { + #[allow(non_camel_case_types)] + struct GetSnapshotSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for GetSnapshotSvc { + type Response = super::Snapshot; + 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 { + ::get_snapshot(&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 inner = inner.0; + let method = GetSnapshotSvc(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) + } + "/google.pubsub.v1.Subscriber/ListSnapshots" => { + #[allow(non_camel_case_types)] + struct ListSnapshotsSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for ListSnapshotsSvc { + type Response = super::ListSnapshotsResponse; + 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 { + ::list_snapshots(&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 inner = inner.0; + let method = ListSnapshotsSvc(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) + } + "/google.pubsub.v1.Subscriber/CreateSnapshot" => { + #[allow(non_camel_case_types)] + struct CreateSnapshotSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for CreateSnapshotSvc { + type Response = super::Snapshot; + 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 { + ::create_snapshot(&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 inner = inner.0; + let method = CreateSnapshotSvc(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) + } + "/google.pubsub.v1.Subscriber/UpdateSnapshot" => { + #[allow(non_camel_case_types)] + struct UpdateSnapshotSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for UpdateSnapshotSvc { + type Response = super::Snapshot; + 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 { + ::update_snapshot(&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 inner = inner.0; + let method = UpdateSnapshotSvc(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) + } + "/google.pubsub.v1.Subscriber/DeleteSnapshot" => { + #[allow(non_camel_case_types)] + struct DeleteSnapshotSvc(pub Arc); + impl< + T: Subscriber, + > tonic::server::UnaryService + for DeleteSnapshotSvc { + type Response = (); + 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 { + ::delete_snapshot(&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 inner = inner.0; + let method = DeleteSnapshotSvc(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) + } + "/google.pubsub.v1.Subscriber/Seek" => { + #[allow(non_camel_case_types)] + struct SeekSvc(pub Arc); + impl tonic::server::UnaryService + for SeekSvc { + type Response = super::SeekResponse; + 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 { + ::seek(&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 inner = inner.0; + let method = SeekSvc(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 { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for SubscriberServer { + 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 _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + 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 SubscriberServer { + const NAME: &'static str = "google.pubsub.v1.Subscriber"; + } +} diff --git a/src/pubsub/mod.rs b/src/pubsub/mod.rs index 43ece2c..ecb0bcb 100644 --- a/src/pubsub/mod.rs +++ b/src/pubsub/mod.rs @@ -27,7 +27,12 @@ mod streaming_subscription; pub mod emulator; /// Types and functions generated from PubSub's gRPC schema -#[allow(rustdoc::broken_intra_doc_links, rustdoc::bare_urls, missing_docs)] +#[allow( + rustdoc::broken_intra_doc_links, + rustdoc::bare_urls, + missing_docs, + unreachable_pub +)] pub mod api { include!("../generated/google.pubsub.v1.rs"); @@ -135,7 +140,27 @@ where let sub_name: String = subscription.clone().into(); let span = debug_span!("create_subscription", topic = sub_name); let _guard = span.enter(); - StreamSubscription::new(self.inner.clone(), subscription.into(), config) + StreamSubscription::new( + // As of the ack handler changes, the streaming implementation needs more than one + // client. The obvious approach would be to clone the client as necessary. However + // adding a Clone bound is a major semver change, and for downstream-simplification + // reasons we'd like to avoid that. + // + // Fortunately, there already *was* a clone bound on this `stream_subscription` + // function, which is the only public way to construct the stream. Also fortunately we + // only need a static number of clients and not arbitrary clones, so we can clone here + // and pass an array down there. This isn't *pretty*, but it works + // + // TODO(0.12.0) just add the clone bound + [ + self.inner.clone(), + self.inner.clone(), + self.inner.clone(), + self.inner.clone(), + ], + subscription.into(), + config, + ) } } diff --git a/src/pubsub/streaming_subscription.rs b/src/pubsub/streaming_subscription.rs index 18c4f39..b77d730 100644 --- a/src/pubsub/streaming_subscription.rs +++ b/src/pubsub/streaming_subscription.rs @@ -1,17 +1,24 @@ use std::{ convert::TryFrom, + future::Future, + mem, pin::Pin, + sync::Arc, task::{Context, Poll}, time::Duration, }; -use async_channel as mpmc; use futures::{ + future::{self, Either, FutureExt, TryFutureExt}, pin_mut, stream::{self, Stream}, StreamExt, }; use pin_project::pin_project; +use tokio::{ + sync::{mpsc, oneshot, Notify}, + time::error::Elapsed as TimeoutElapsed, +}; use tonic::metadata::MetadataValue; use tracing::{debug, trace_span, Instrument}; @@ -21,6 +28,14 @@ use crate::{ retry_policy::{exponential_backoff, ExponentialBackoff, RetryOperation, RetryPolicy}, }; +/// The maximum deadline supported by the RPC service +const MAX_DEADLINE_SEC: u32 = 600; + +/// The maximum number of acks or modacks in a single request +// 2500 as used in the go lib +// https://github.com/googleapis/google-cloud-go/blob/94d040898cc9e85fdac76560765b01cfd019d0b4/pubsub/iterator.go#L44-L52 +const MAX_ACK_BATCH_SIZE: usize = 2500; + config_default! { /// Configuration for a [streaming subscription](super::SubscriberClient::stream_subscription) /// request @@ -40,37 +55,41 @@ config_default! { pub max_outstanding_bytes: i64, /// Deprecated, subsumed by `max_outstanding_messages` + //TODO(0.12.0) remove deprecated field #[deprecated] @default(0, "StreamSubscriptionConfig::default_ack_channel_capacity") pub ack_channel_capacity: usize, } } -/// A user-initiated request to acknowledge, reject, or modify the deadline of some message -#[derive(Debug, PartialEq)] -enum UserAck { - Ack { id: String }, - Modify { id: String, seconds: i32 }, -} - /// An error encountered when issuing acks, nacks, or modifications from an /// [`AcknowledgeToken`](AcknowledgeToken) #[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)] -#[error("cannot ack/nack/modify because the stream was dropped")] -pub struct AcknowledgeError { - _private: (), +#[error("failed to ack/nack/modify")] +pub struct AcknowledgeError(#[source] AckErr); + +#[derive(Debug, Clone, thiserror::Error)] +enum AckErr { + #[error("error in background task; check primary pull stream for errors")] + BackgroundTaskPanic, + + #[error(transparent)] + Request(tonic::Status), } -impl AcknowledgeError { - // SendErrors should only happen when the receiver is disconnected, which isn't called manually - // by the stream so should only happen on drop - fn from_send_err(_err: mpmc::SendError) -> Self { - AcknowledgeError { _private: () } +// TODO(0.12.0) remove eq/partialeq, use `matches!` in tests instead +impl PartialEq for AckErr { + fn eq(&self, other: &AckErr) -> bool { + use AckErr::*; + match (self, other) { + (BackgroundTaskPanic, BackgroundTaskPanic) => true, + (Request(status_a), Request(status_b)) => status_a.code() == status_b.code(), + _ => false, + } } } -/// The maximum deadline supported by the RPC service -const MAX_DEADLINE_SEC: u32 = 600; +impl Eq for AckErr {} /// An error encountered when issuing deadline modifications with /// [`AcknowledgeToken::modify_deadline`](AcknowledgeToken::modify_deadline) @@ -88,12 +107,31 @@ pub enum ModifyAcknowledgeError { }, } +#[derive(Debug)] +struct AckRouter { + // These channels are unbounded in a technical sense; however in practice there is a bound to + // the number of outstanding messages which pubsub will issue to a streaming caller. This will + // implicitly limit the ack/nack channel sizes. + // + // However modacks are not limited, as well as acks/nacks if a user sets both + // max_outstanding_bytes and max_outstanding_messages to zero (unbounded). Then it's up to the + // user to impose backpressure by awaiting the returned futures + acks: mpsc::UnboundedSender>, + nacks: mpsc::UnboundedSender>, + modacks: mpsc::UnboundedSender>, +} + +struct ModAck { + id: String, + deadline: i32, +} + /// A token with an associated message produced by the [`StreamSubscription`](StreamSubscription) /// stream, used to control that message's re-delivery within the message queue. #[derive(Debug)] pub struct AcknowledgeToken { id: String, - channel: mpmc::Sender, + router: Arc, delivery_attempt: i32, } @@ -103,12 +141,13 @@ impl AcknowledgeToken { /// /// Note that acknowledgements may not arrive to the service within the deadline (or at all), /// so this is only a best-effort means of preventing re-delivery. - pub async fn ack(self) -> Result<(), AcknowledgeError> { - self.channel - .send(UserAck::Ack { id: self.id }) - .await - .map_err(AcknowledgeError::from_send_err)?; - Ok(()) + /// + /// The returned future will complete once the acknowledge request has been sent. It is not + /// necessary to wait for the future's completion however; calling this function will initiate + /// an acknowledgement, which will finish even without awaiting the future. This can be useful + /// for callers that don't need explicit ack settlement and prefer to save latency. + pub fn ack(self) -> impl Future> + Send { + TokenFeedback::send(&self.router.acks, self.id) } /// Negatively acknowledge the corresponding message, requesting that the message service @@ -116,18 +155,10 @@ impl AcknowledgeToken { /// /// This may be useful if the message consumer encounters an error while processing the /// message. - pub async fn nack(self) -> Result<(), AcknowledgeError> { - self.channel - .send(UserAck::Modify { - id: self.id, - // "A NACK is any call to ModifyAckDeadline with a 0 deadline" - // see ReceivedMessage or ModifyAckDeadlineRequest rpc docs - seconds: 0, - }) - .await - .map_err(AcknowledgeError::from_send_err)?; - - Ok(()) + /// + /// The returned future need not be awaited, see [`AcknowledgeToken::ack`] + pub fn nack(self) -> impl Future> + Send { + TokenFeedback::send(&self.router.nacks, self.id) } /// Modify the acknowledgement deadline of the corresponding message, so that re-delivery is @@ -138,22 +169,30 @@ impl AcknowledgeToken { /// deadline, if for example the [subscription-level /// deadline](StreamSubscriptionConfig::stream_ack_deadline) is longer. A deadline of /// 0 seconds is equivalent to a [`nack`](AcknowledgeToken::nack) and will make the message - /// immediately available for re-delivery. + /// immediately available for re-delivery. The maximum deadline accepted by the service is 600 + /// seconds. /// - /// The maximum deadline accepted by the service is 600 seconds. - pub async fn modify_deadline(&mut self, seconds: u32) -> Result<(), ModifyAcknowledgeError> { + /// The returned future need not be awaited, see [`AcknowledgeToken::ack`] + pub fn modify_deadline( + &mut self, + seconds: u32, + ) -> impl Future> + Send { if seconds > MAX_DEADLINE_SEC { - return Err(ModifyAcknowledgeError::InvalidDeadline { seconds }); + return Either::Left(future::ready(Err( + ModifyAcknowledgeError::InvalidDeadline { seconds }, + ))); } - self.channel - .send(UserAck::Modify { - id: self.id.clone(), - seconds: i32::try_from(seconds).expect("deadline must fit in i32"), - }) - .await - .map_err(|err| ModifyAcknowledgeError::Modify(AcknowledgeError::from_send_err(err)))?; - Ok(()) + Either::Right( + TokenFeedback::send( + &self.router.modacks, + ModAck { + id: self.id.clone(), + deadline: seconds as i32, + }, + ) + .map_err(ModifyAcknowledgeError::Modify), + ) } /// The approximate number of times that Cloud Pub/Sub has attempted to deliver the associated @@ -165,6 +204,209 @@ impl AcknowledgeToken { } } +// Each ack token's ack/nack/modack calls are carried by this struct to the background task that +// polls the mpsc channels. That task will then notify the token of the request's completion by sending +// a result back over the given oneshot channel +struct TokenFeedback { + payload: T, + completion: oneshot::Sender>, +} + +impl TokenFeedback { + fn send( + channel: &mpsc::UnboundedSender>, + payload: T, + ) -> impl Future> + Send { + let (completion, listener) = oneshot::channel(); + + // send the payload over the channel synchronously. After this, the caller could drop the + // returned future and the work would still happen (barring errors/panics) + let send_result = channel.send(Self { + completion, + payload, + }); + + // now create the future to actually wait on the outcome + async move { + match send_result { + Ok(()) => match listener.await { + // if the background task completed a request with our payload, then + // we're ready to return a normal case to the user. Note this might still be a + // failed response, but the request completed a trip to the pubsub service + Ok(server_response) => return server_response, + + Err(oneshot::error::RecvError { .. }) => {} + }, + Err(mpsc::error::SendError { .. }) => {} + } + // Either SendError or RecvError imply that the other end of the channel was dropped. + // This means the background handler has stopped; if there are still senders open, that + // should only happen if a panic happened in that task + Err(AcknowledgeError(AckErr::BackgroundTaskPanic)) + } + } +} + +/// Wait for acks to arrive over the given channel, and send them to the server via the acknowledge +/// grpc method. +async fn handle_acks( + mut client: api::subscriber_client::SubscriberClient, + subscription: String, + mut acks: mpsc::UnboundedReceiver>, +) where + S: GrpcService + Send + 'static, + S::Future: Send + 'static, + S::Error: Into, + S::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, +{ + let mut batch = Vec::new(); + loop { + let fetch_count = acks.recv_many(&mut batch, MAX_ACK_BATCH_SIZE).await; + if fetch_count == 0 { + // all senders dropped, pull stream must have closed + break; + } + let request = api::AcknowledgeRequest { + subscription: subscription.clone(), + ack_ids: batch + .iter_mut() + .map(|TokenFeedback { payload, .. }| mem::take(payload)) + .collect(), + }; + + let response = client + .acknowledge(request) + .await + .map(tonic::Response::into_inner) + .map_err(|err| AcknowledgeError(AckErr::Request(err))); + + let mut listeners = batch + .drain(..) + .map(|TokenFeedback { completion, .. }| completion); + + // peel off the first to avoid cloning in the common single-message case + let first = listeners.next().expect("fetched > 0"); + + // Send failures can only happen if the receiver was dropped. + // That's benign, the user isn't listening for ack responses. Ignore such failures + for listener in listeners { + let _ = listener.send(response.clone()); + } + let _ = first.send(response); + } +} + +/// much like handle_acks except includes ack_deadline_seconds and calls modify_ack_deadline. +// unfortunately hard to unify the two without proper async closures (or macros i guess) +async fn handle_nacks( + mut client: api::subscriber_client::SubscriberClient, + subscription: String, + mut nacks: mpsc::UnboundedReceiver>, +) where + S: GrpcService + Send + 'static, + S::Future: Send + 'static, + S::Error: Into, + S::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, +{ + let mut batch = Vec::new(); + loop { + let fetch_count = nacks.recv_many(&mut batch, MAX_ACK_BATCH_SIZE).await; + if fetch_count == 0 { + break; + } + let request = api::ModifyAckDeadlineRequest { + subscription: subscription.clone(), + // zero seconds implies nack + ack_deadline_seconds: 0, + ack_ids: batch + .iter_mut() + .map(|TokenFeedback { payload, .. }| mem::take(payload)) + .collect(), + }; + + let response = client + .modify_ack_deadline(request) + .await + .map(tonic::Response::into_inner) + .map_err(|err| AcknowledgeError(AckErr::Request(err))); + + let mut listeners = batch + .drain(..) + .map(|TokenFeedback { completion, .. }| completion); + + let first = listeners.next().expect("fetched > 0"); + for listener in listeners { + let _ = listener.send(response.clone()); + } + let _ = first.send(response); + } +} + +async fn handle_modacks( + mut client: api::subscriber_client::SubscriberClient, + subscription: String, + mut modacks: mpsc::UnboundedReceiver>, +) where + S: GrpcService + Send + 'static, + S::Future: Send + 'static, + S::Error: Into, + S::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, +{ + let mut batch = Vec::new(); + loop { + let fetch_count = modacks.recv_many(&mut batch, MAX_ACK_BATCH_SIZE).await; + if fetch_count == 0 { + break; + } + + // Unlike acks and nacks, each modack can have a different deadline. The request schema + // specifies a single deadline for all tokens in its batch. To resolve these two + // constraints, sort the batch into sections of identical deadlines, and send a batched + // request for each section. + // + // This is sorted in descending order because the below code pulls off the end. We want the + // shortest deadlines sent to the server first, on the theory that shorter deadlines imply + // tighter timing (though maybe it's irrelevant, deadlines are seconds while requests are + // hopefully millis) + batch.sort_by_key(|entry| std::cmp::Reverse(entry.payload.deadline)); + + // take sections off the end to avoid shifting values down as they're drained + while let Some(last_entry) = batch.last() { + let ack_deadline_seconds = last_entry.payload.deadline; + let section_start = + batch.partition_point(|entry| entry.payload.deadline > ack_deadline_seconds); + + let request = api::ModifyAckDeadlineRequest { + subscription: subscription.clone(), + ack_deadline_seconds, + ack_ids: batch[section_start..] + .iter_mut() + .map(|TokenFeedback { payload, .. }| mem::take(&mut payload.id)) + .collect(), + }; + + let response = client + .modify_ack_deadline(request) + .await + .map(tonic::Response::into_inner) + .map_err(|err| AcknowledgeError(AckErr::Request(err))); + + let mut listeners = batch + .drain(section_start..) + .map(|TokenFeedback { completion, .. }| completion); + + let first = listeners.next().expect("fetched > 0"); + for listener in listeners { + let _ = listener.send(response.clone()); + } + let _ = first.send(response); + } + } +} + /// Create the initial StreamingPullRequest which must include a Subscription string and a unique /// client_id. fn create_initial_streaming_pull_request( @@ -178,88 +420,67 @@ fn create_initial_streaming_pull_request( stream_ack_deadline_seconds: i32::try_from(config.stream_ack_deadline.as_secs()) .expect("ack deadline seconds should fit in i32"), max_outstanding_messages: config.max_outstanding_messages, - modify_deadline_seconds: Vec::default(), - modify_deadline_ack_ids: Vec::default(), max_outstanding_bytes: config.max_outstanding_bytes, - ack_ids: Vec::default(), + ..Default::default() } } /// Create the Nth StreamingPullRequest message (i.e. 2nd or later). -/// -/// Message should contain the previous message ids we want to acknowledge, and message ids for -/// messages whose deadlines should be modified. Nack'ing a message is accomplished by setting its -/// deadline to 0. fn create_subsequent_streaming_pull_request( - ack_ids: Vec, - modify_deadline_seconds: Vec, - modify_deadline_ack_ids: Vec, config: &StreamSubscriptionConfig, ) -> api::StreamingPullRequest { api::StreamingPullRequest { - ack_ids, - // subscription was set on the first request and is not set again. - subscription: String::default(), - // client_id was set on the first request and is not set again. - client_id: String::default(), // Even though this was set on the first request, it is reset on every subsequent request. // Here we "reset" it to the same value. stream_ack_deadline_seconds: i32::try_from(config.stream_ack_deadline.as_secs()) .expect("ack deadline seconds should fit in i32"), - // max_outstanding_messages was set on the first request and is not set again. - max_outstanding_messages: 0, - modify_deadline_seconds, - modify_deadline_ack_ids, - // max_outstanding_bytes was set on the first request and is not set again. - max_outstanding_bytes: 0, + ..Default::default() } } -/// Create never ending request stream of StreamingPullRequests. The first request initializes a new -/// gRPC stream and subsequent messages will acknowledge previous messages and request additional -/// ones. +/// Create an indefinite request stream of StreamingPullRequests. The first request initializes a new +/// gRPC stream and subsequent messages will keep the connection alive. +/// +/// The returned pair includes a stop indicator: after the value is dropped, the stream will stop +/// yielding elements and terminate. fn create_streaming_pull_request_stream( subscription: String, client_id: String, - user_acks: impl Stream, config: StreamSubscriptionConfig, -) -> impl Stream { - async_stream::stream! { +) -> (impl Stream, impl Drop) { + let stop_check = Arc::new(Notify::new()); + + struct StopOnDrop(Arc); + impl Drop for StopOnDrop { + fn drop(&mut self) { + self.0.notify_one(); + } + } + let stopper = StopOnDrop(Arc::clone(&stop_check)); + + let stream = async_stream::stream! { // start by issuing the first request yield create_initial_streaming_pull_request(subscription, client_id, &config); - // Subsequent requests come from user acknowledgements. - // Pull multiple acks at once in order to batch acks in the request. - // The size of batches is chosen to not exceed API restrictions - const MAX_PER_REQUEST_CHANGES: usize = 1000; // 1000 as used in the java lib - pin_mut!(user_acks); - let mut user_ack_batches = user_acks.ready_chunks(MAX_PER_REQUEST_CHANGES); - - while let Some(user_ack_batch) = user_ack_batches.next().await { - // collect the single stream of acks into individual lists depending on the ack type. - // pre-alloc only the ack list as the anticipated normal outcome - let mut acks = Vec::with_capacity(user_ack_batch.len()); - let mut deadlines = Vec::new(); - let mut deadline_acks = Vec::new(); - - for user_ack in user_ack_batch { - match user_ack { - UserAck::Ack { id } => acks.push(id), - UserAck::Modify { id, seconds } => { - deadlines.push(seconds); - deadline_acks.push(id); - } - }; - } + let should_stop = stop_check.notified(); + pin_mut!(should_stop); - yield create_subsequent_streaming_pull_request( - acks, - deadlines, - deadline_acks, - &config - ); + // Periodically send requests to keep the grpc connection active. This can help in cases + // where messages aren't being actively read (e.g. processing messages takes a long time). + // + // This does not send acks back over the stream, instead opting for explicit ack requests + // to have better feedback over ack completion/success/failure. + loop { + match tokio::time::timeout(Duration::from_secs(30), should_stop.as_mut()).await { + Ok(()) => break, + Err(TimeoutElapsed { .. }) => { + yield create_subsequent_streaming_pull_request(&config); + } + } } - } + }; + + (stream, stopper) } /// The stream returned by the @@ -283,7 +504,7 @@ pub struct StreamSubscription< /// could be called after streaming enum StreamState { Initialized { - client: api::subscriber_client::SubscriberClient, + client: [api::subscriber_client::SubscriberClient; 4], subscription: String, config: StreamSubscriptionConfig, retry_policy: R, @@ -297,7 +518,7 @@ enum StreamState { impl StreamSubscription { pub(super) fn new( - client: api::subscriber_client::SubscriberClient, + client: [api::subscriber_client::SubscriberClient; 4], subscription: String, config: StreamSubscriptionConfig, ) -> Self { @@ -421,7 +642,7 @@ where /// The stream will internally reconnect on error if the given retry policy indicates the /// error is retriable fn stream_from_client( - mut client: api::subscriber_client::SubscriberClient, + clients: [api::subscriber_client::SubscriberClient; 4], subscription: String, config: StreamSubscriptionConfig, mut retry_policy: R, @@ -442,25 +663,31 @@ where // the client id is used for stream reconnection on error let client_id = uuid::Uuid::new_v4().to_string(); - // Channel to send/receive message ids to ack. - // This needs to be a multi-producer channel as each message will get a sender handle to send - // its ack. In practice the receiver will only ever be polled as single-consumer; however there - // is a period of time during reconnection when two receivers might exist, because the - // disconnected stream is dropped in a background task at an unknown time (unknown to our - // layer anyway), and the new receiver should continue to pull from the existing senders. - let (sender, receiver) = mpmc::bounded( - usize::try_from(config.max_outstanding_messages) - .expect("outstanding messages should fit in usize"), - ); + let [mut client, ack_client, nack_client, modack_client] = clients; async_stream::stream! { let mut retry_op = None; + let (acks, acks_rx) = mpsc::unbounded_channel(); + let (nacks, nacks_rx) = mpsc::unbounded_channel(); + let (modacks, modacks_rx) = mpsc::unbounded_channel(); + let ack_router = Arc::new(AckRouter { acks, nacks, modacks }); + + // spawn the ack processing in the background. These should continue to process even + // when messages are not being pulled. + let ack_processor = tokio::spawn(future::join3( + handle_acks(ack_client, subscription.clone(), acks_rx), + handle_nacks(nack_client, subscription.clone(), nacks_rx), + handle_modacks(modack_client, subscription.clone(), modacks_rx), + )) + .unwrap_or_else(|join_err| std::panic::resume_unwind(join_err.into_panic())) + .map(|((), (), ())| ()); + pin_mut!(ack_processor); + 'reconnect: loop { - let request_stream = create_streaming_pull_request_stream( + let (request_stream, stream_drop_stopper) = create_streaming_pull_request_stream( subscription.clone(), client_id.clone(), - receiver.clone(), config, ); @@ -472,7 +699,15 @@ where { Err(err) => err, Ok(mut message_stream) => 'read: loop { - match message_stream.next().instrument(trace_span!("sub_stream_pull")).await { + // check if the background processor encountered any panics; + // if not, try to read messages from the stream. + let msg = message_stream.next().instrument(trace_span!("sub_stream_pull")); + pin_mut!(msg); + let next = future::poll_fn(|cx| match ack_processor.as_mut().poll(cx) { + Poll::Ready(()) => unreachable!("shouldn't complete while stream is active"), + Poll::Pending => msg.as_mut().poll(cx) + }); + match next.await { // If the stream is out of elements, some connection must have been closed. // However PubSub docs say StreamingPull always terminates with an error, // so this normal end-of-stream shouldn't happen, and instead should fall @@ -495,7 +730,7 @@ where for message in response.received_messages { let ack_token = AcknowledgeToken { id: message.ack_id, - channel: sender.clone(), + router: Arc::clone(&ack_router), delivery_attempt: message.delivery_attempt, }; let message = match message.message { @@ -512,7 +747,8 @@ where } } }; - debug!("Stream ended"); + std::mem::drop(stream_drop_stopper); + debug!(%client_id, "Stream ended"); // if either the streaming connection or a stream element produces an error, // the error will arrive here. @@ -544,204 +780,833 @@ where #[cfg(test)] mod test { - use rand::Rng; - use super::*; + use std::sync::Mutex; + use tonic::Code; #[test] - fn streaming_pull_request_stream() { - let subscription = "test-subscription"; - let client_id = "test-id"; - - let (mut sender, receiver) = futures::channel::mpsc::unbounded(); - - let requests = create_streaming_pull_request_stream( - subscription.into(), - client_id.into(), - receiver, - StreamSubscriptionConfig { - max_outstanding_messages: 2000, - max_outstanding_bytes: 3000, - stream_ack_deadline: Duration::from_secs(20), - ..Default::default() - }, - ); - pin_mut!(requests); + fn token_send() { + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + let (send, mut recv) = mpsc::unbounded_channel(); + let mut fut = TokenFeedback::send(&send, "hello world").boxed(); + + // without any poll, the item should already be sent over the channel + let TokenFeedback { + payload, + completion, + } = recv.try_recv().expect("send should be synchronous"); + assert_eq!(payload, "hello world"); + + // the future should now be waiting for a response on the completion channel + assert!(matches!(fut.as_mut().poll(&mut cx), Poll::Pending)); + completion.send(Ok(())).expect("oneshot is open"); + assert!(matches!(fut.as_mut().poll(&mut cx), Poll::Ready(Ok(())))); + + // setup another send to witness an error response + let mut fut = TokenFeedback::send(&send, "abc123").boxed(); + let TokenFeedback { completion, .. } = recv.try_recv().expect("send should be synchronous"); + assert!(matches!(fut.as_mut().poll(&mut cx), Poll::Pending)); + completion + .send(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + .expect("oneshot is open"); + assert!(matches!( + fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); + } + #[test] + fn token_wait() { + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + let (send, mut recv) = mpsc::unbounded_channel(); + + let mut fut = TokenFeedback::send(&send, "hello world").boxed(); + let TokenFeedback { completion, .. } = recv.try_recv().expect("send should be synchronous"); + + // if the completion gets dropped, the waiting future should resolve with an error + std::mem::drop(completion); + assert!(matches!( + fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); + + // that also applies if the future is already polling + let mut fut = TokenFeedback::send(&send, "hello world").boxed(); + let TokenFeedback { completion, .. } = recv.try_recv().expect("send should be synchronous"); + assert!(matches!(fut.as_mut().poll(&mut cx), Poll::Pending)); + std::mem::drop(completion); + assert!(matches!( + fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); + + // start a send which will encounter a receiver drop + let mut fut = TokenFeedback::send(&send, "hello world").boxed(); + assert!(matches!(fut.as_mut().poll(&mut cx), Poll::Pending)); + std::mem::drop(recv); + assert!(matches!( + fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); + + // a send started after the receiver drop should also fail + let mut fut = TokenFeedback::send(&send, "hello world").boxed(); + assert!(matches!( + fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); + } + + #[test] + fn ack_handling() { let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + #[derive(Default, Clone)] + struct MockSubscriberServer { + acks: Arc>>, + injected_errors: Arc>>, + } + + #[tonic::codegen::async_trait] + impl api::subscriber_server::Subscriber for MockSubscriberServer { + async fn acknowledge( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + self.acks.lock().unwrap().push(request.into_inner()); + + let mut errs = self.injected_errors.lock().unwrap(); + if errs.is_empty() { + Ok(tonic::Response::new(())) + } else { + Err(errs.remove(0)) + } + } + } + + let (ack_send, recv) = mpsc::unbounded_channel(); + let server = MockSubscriberServer::default(); + let take_server_acks = || server.acks.lock().unwrap().drain(..).collect::>(); + + let mut ack_handler = handle_acks( + api::subscriber_client::SubscriberClient::new( + api::subscriber_server::SubscriberServer::new(server.clone()), + ), + "test-subscription".into(), + recv, + ) + .boxed(); + + // simple single ack case + let mut ack_fut = TokenFeedback::send(&ack_send, "ack-id1".into()).boxed(); + // drive ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + + // check that the server got the request + assert_eq!( + take_server_acks(), + vec![api::AcknowledgeRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id1".into()], + }] + ); + // and that the ack token got its response + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + + // send multiple acks before the handler polls again + let mut ack_fut = future::join3( + TokenFeedback::send(&ack_send, "ack-id2".into()), + TokenFeedback::send(&ack_send, "ack-id3".into()), + TokenFeedback::send(&ack_send, "ack-id4".into()), + ) + .boxed(); + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + + // check that the server got a single buffered request + assert_eq!( + take_server_acks(), + vec![api::AcknowledgeRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id2".into(), "ack-id3".into(), "ack-id4".into()], + }] + ); - // the request stream always starts with an initialized first request + // and that all the futures got responses + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready((Ok(()), Ok(()), Ok(()))) + )); + + // send multiple acks again + let mut ack_fut = future::join3( + TokenFeedback::send(&ack_send, "ack-id5".into()), + TokenFeedback::send(&ack_send, "ack-id6".into()), + TokenFeedback::send(&ack_send, "ack-id7".into()), + ) + .boxed(); + // however this time inject an error response from the server + server + .injected_errors + .lock() + .unwrap() + .push(tonic::Status::aborted("injected-error")); + + // drive the ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); assert_eq!( - Poll::Ready(Some(api::StreamingPullRequest { - subscription: subscription.into(), - ack_ids: vec![], - modify_deadline_seconds: vec![], - modify_deadline_ack_ids: vec![], - stream_ack_deadline_seconds: 20, - client_id: client_id.into(), - max_outstanding_messages: 2000, - max_outstanding_bytes: 3000, - })), - requests.as_mut().poll_next(&mut cx) + take_server_acks(), + vec![api::AcknowledgeRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id5".into(), "ack-id6".into(), "ack-id7".into()], + }] ); - // no subsequent requests until a message is available on the channel - assert_eq!(Poll::Pending, requests.as_mut().poll_next(&mut cx)); + // the ack tokens should each get back the error + let ack_responses = ack_fut.as_mut().poll(&mut cx); + match ack_responses { + Poll::Ready(( + Err(AcknowledgeError(AckErr::Request(status1))), + Err(AcknowledgeError(AckErr::Request(status2))), + Err(AcknowledgeError(AckErr::Request(status3))), + )) if ( + (status1.code(), status2.code(), status3.code()), + (status1.message(), status2.message(), status3.message()), + ) == ( + (Code::Aborted, Code::Aborted, Code::Aborted), + ("injected-error", "injected-error", "injected-error"), + ) => {} + _ => panic!("unexpected future output {ack_responses:?}"), + }; + + // if more than the batch limit is submitted, the handler will send multiple requests + let futs = (0..(MAX_ACK_BATCH_SIZE + 2)) + .map(|i| TokenFeedback::send(&ack_send, format!("mass-ack{i}"))) + .collect::>(); - // send 1 message ack + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + let server_acks = take_server_acks(); + assert_eq!(server_acks.len(), 2); assert_eq!( - Ok(()), - sender.unbounded_send(UserAck::Ack { id: "1st".into() }) + server_acks[0].ack_ids, + (0..MAX_ACK_BATCH_SIZE) + .map(|i| format!("mass-ack{i}")) + .collect::>() ); - // the output stream should be eager, and produce a request if only 1 message is available + const _SANITY_CHECK: [(); 2500] = [(); MAX_ACK_BATCH_SIZE]; assert_eq!( - Poll::Ready(Some(api::StreamingPullRequest { - subscription: String::new(), - ack_ids: vec!["1st".into()], - modify_deadline_seconds: vec![], - modify_deadline_ack_ids: vec![], - stream_ack_deadline_seconds: 20, - client_id: String::new(), - max_outstanding_messages: 0, - max_outstanding_bytes: 0, - })), - requests.as_mut().poll_next(&mut cx) + server_acks[1].ack_ids, + vec!["mass-ack2500".to_owned(), "mass-ack2501".to_owned()] ); - assert_eq!(Poll::Pending, requests.as_mut().poll_next(&mut cx)); - // send 3 message acks/modifies + // all the futures should get their success response + for fut in futs { + assert!(matches!( + fut.boxed().as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + // the handler future can complete after the sender side is dropped. + // however it must first flush any acks still in the queue. + let mut ack_fut = TokenFeedback::send(&ack_send, "ack-id99".into()).boxed(); + std::mem::drop(ack_send); + assert!(take_server_acks().is_empty()); // sanity check + assert!(matches!( + ack_handler.as_mut().poll(&mut cx), + Poll::Ready(()) + )); assert_eq!( - Ok(()), - sender.unbounded_send(UserAck::Ack { id: "2nd".into() }) + take_server_acks(), + vec![api::AcknowledgeRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id99".into()] + }] ); + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + // copy-paste of ack handler. practically identical functionality + #[test] + fn nack_handling() { + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + #[derive(Default, Clone)] + struct MockSubscriberServer { + acks: Arc>>, + injected_errors: Arc>>, + } + + #[tonic::codegen::async_trait] + impl api::subscriber_server::Subscriber for MockSubscriberServer { + async fn modify_ack_deadline( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + self.acks.lock().unwrap().push(request.into_inner()); + + let mut errs = self.injected_errors.lock().unwrap(); + if errs.is_empty() { + Ok(tonic::Response::new(())) + } else { + Err(errs.remove(0)) + } + } + } + + let (ack_send, recv) = mpsc::unbounded_channel(); + let server = MockSubscriberServer::default(); + let take_server_acks = || server.acks.lock().unwrap().drain(..).collect::>(); + + let mut ack_handler = handle_nacks( + api::subscriber_client::SubscriberClient::new( + api::subscriber_server::SubscriberServer::new(server.clone()), + ), + "test-subscription".into(), + recv, + ) + .boxed(); + + // simple single ack case + let mut ack_fut = TokenFeedback::send(&ack_send, "ack-id1".into()).boxed(); + // drive ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + + // check that the server got the request assert_eq!( - Ok(()), - sender.unbounded_send(UserAck::Modify { - id: "3rd".into(), - seconds: 13 - }) + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id1".into()], + ack_deadline_seconds: 0, + }] ); + // and that the ack token got its response + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + + // send multiple acks before the handler polls again + let mut ack_fut = future::join3( + TokenFeedback::send(&ack_send, "ack-id2".into()), + TokenFeedback::send(&ack_send, "ack-id3".into()), + TokenFeedback::send(&ack_send, "ack-id4".into()), + ) + .boxed(); + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + + // check that the server got a single buffered request assert_eq!( - Ok(()), - sender.unbounded_send(UserAck::Ack { id: "4th".into() }) + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id2".into(), "ack-id3".into(), "ack-id4".into()], + ack_deadline_seconds: 0, + }] ); + + // and that all the futures got responses + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready((Ok(()), Ok(()), Ok(()))) + )); + + // send multiple acks again + let mut ack_fut = future::join3( + TokenFeedback::send(&ack_send, "ack-id5".into()), + TokenFeedback::send(&ack_send, "ack-id6".into()), + TokenFeedback::send(&ack_send, "ack-id7".into()), + ) + .boxed(); + // however this time inject an error response from the server + server + .injected_errors + .lock() + .unwrap() + .push(tonic::Status::aborted("injected-error")); + + // drive the ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); assert_eq!( - Ok(()), - sender.unbounded_send(UserAck::Modify { - id: "5th".into(), - seconds: 15 - }) + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id5".into(), "ack-id6".into(), "ack-id7".into()], + ack_deadline_seconds: 0, + }] ); - // the output stream should buffer when many acks/modifies are available + // the ack tokens should each get back the error + let ack_responses = ack_fut.as_mut().poll(&mut cx); + match ack_responses { + Poll::Ready(( + Err(AcknowledgeError(AckErr::Request(status1))), + Err(AcknowledgeError(AckErr::Request(status2))), + Err(AcknowledgeError(AckErr::Request(status3))), + )) if ( + (status1.code(), status2.code(), status3.code()), + (status1.message(), status2.message(), status3.message()), + ) == ( + (Code::Aborted, Code::Aborted, Code::Aborted), + ("injected-error", "injected-error", "injected-error"), + ) => {} + _ => panic!("unexpected future output {ack_responses:?}"), + }; + + // if more than the batch limit is submitted, the handler will send multiple requests + let futs = (0..(MAX_ACK_BATCH_SIZE + 2)) + .map(|i| TokenFeedback::send(&ack_send, format!("mass-ack{i}"))) + .collect::>(); + + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + let server_acks = take_server_acks(); + assert_eq!(server_acks.len(), 2); assert_eq!( - Poll::Ready(Some(api::StreamingPullRequest { - subscription: String::new(), - ack_ids: vec!["2nd".into(), "4th".into()], - modify_deadline_seconds: vec![13, 15], - modify_deadline_ack_ids: vec!["3rd".into(), "5th".into()], - stream_ack_deadline_seconds: 20, - client_id: String::new(), - max_outstanding_messages: 0, - max_outstanding_bytes: 0, - })), - requests.as_mut().poll_next(&mut cx) + server_acks[0].ack_ids, + (0..MAX_ACK_BATCH_SIZE) + .map(|i| format!("mass-ack{i}")) + .collect::>() ); - assert_eq!(Poll::Pending, requests.as_mut().poll_next(&mut cx)); - - // the output buffering has a limit of 1000. if more messages are immediately available, - // they will be sent in multiple requests. - - // generate acks/modifies with random interleaving - let inputs = std::iter::repeat_with(|| rand::thread_rng().gen::()) - .enumerate() - .skip(6) // skip 0th,1st..5th - .map(|(index, is_modify)| { - let id = index.to_string() + "th"; - if is_modify { - UserAck::Modify { - id, - seconds: index as i32, - } + + const _SANITY_CHECK: [(); 2500] = [(); MAX_ACK_BATCH_SIZE]; + assert_eq!( + server_acks[1].ack_ids, + vec!["mass-ack2500".to_owned(), "mass-ack2501".to_owned()] + ); + + // all the futures should get their success response + for fut in futs { + assert!(matches!( + fut.boxed().as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + // the handler future can complete after the sender side is dropped. + // however it must first flush any acks still in the queue. + let mut ack_fut = TokenFeedback::send(&ack_send, "ack-id99".into()).boxed(); + std::mem::drop(ack_send); + assert!(take_server_acks().is_empty()); // sanity check + assert!(matches!( + ack_handler.as_mut().poll(&mut cx), + Poll::Ready(()) + )); + assert_eq!( + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id99".into()], + ack_deadline_seconds: 0, + }] + ); + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + // *NOT* a (direct) copy-paste of ack handler, accounting for multiple deadlines. still mostly + // a copy though... + #[test] + fn modack_handling() { + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + #[derive(Default, Clone)] + struct MockSubscriberServer { + acks: Arc>>, + injected_errors: Arc>>, + } + + #[tonic::codegen::async_trait] + impl api::subscriber_server::Subscriber for MockSubscriberServer { + async fn modify_ack_deadline( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + self.acks.lock().unwrap().push(request.into_inner()); + + let mut errs = self.injected_errors.lock().unwrap(); + if errs.is_empty() { + Ok(tonic::Response::new(())) } else { - UserAck::Ack { id } + Err(errs.remove(0)) } - }) - .take(1001) - .collect::>(); + } + } - let filter_acks = |acks: &[UserAck]| { - acks.iter() - .filter_map(|ack| match ack { - UserAck::Ack { id } => Some(id.clone()), - _ => None, - }) - .collect::>() - }; + let (ack_send, recv) = mpsc::unbounded_channel(); + let server = MockSubscriberServer::default(); + let take_server_acks = || server.acks.lock().unwrap().drain(..).collect::>(); + + let mut ack_handler = handle_modacks( + api::subscriber_client::SubscriberClient::new( + api::subscriber_server::SubscriberServer::new(server.clone()), + ), + "test-subscription".into(), + recv, + ) + .boxed(); + + // simple single ack case + let mut ack_fut = TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id1".into(), + deadline: 1, + }, + ) + .boxed(); + // drive ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); - let filter_modifies = |acks: &[UserAck]| { - acks.iter() - .filter_map(|ack| match ack { - UserAck::Modify { id, seconds } => Some((id.clone(), *seconds)), - _ => None, - }) - .collect::>() - }; + // check that the server got the request + assert_eq!( + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id1".into()], + ack_deadline_seconds: 1, + }] + ); + // and that the ack token got its response + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + + // send multiple acks before the handler polls again. + // note these have varying deadlines. The handler may only batch together acks with the same + // deadline + let mut ack_fut = future::join5( + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id2".into(), + deadline: 2, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id3".into(), + deadline: 5, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id4".into(), + deadline: 2, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id5".into(), + deadline: 5, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id6".into(), + deadline: 1, + }, + ), + ) + .boxed(); + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); - let expected_first_batch = api::StreamingPullRequest { - subscription: String::new(), - ack_ids: filter_acks(&inputs[..1000]), - modify_deadline_seconds: filter_modifies(&inputs[..1000]) - .into_iter() - .map(|tup| tup.1) - .collect(), - modify_deadline_ack_ids: filter_modifies(&inputs[..1000]) - .into_iter() - .map(|tup| tup.0) - .collect(), - stream_ack_deadline_seconds: 20, - client_id: String::new(), - max_outstanding_messages: 0, - max_outstanding_bytes: 0, - }; + // the server should have gotten separate requests for each deadline, in increasing + // order by deadline. + assert_eq!( + take_server_acks(), + vec![ + api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id6".into()], + ack_deadline_seconds: 1, + }, + api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id2".into(), "ack-id4".into()], + ack_deadline_seconds: 2, + }, + api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id3".into(), "ack-id5".into()], + ack_deadline_seconds: 5, + }, + ] + ); - let expected_second_batch = api::StreamingPullRequest { - subscription: String::new(), - ack_ids: filter_acks(&inputs[1000..]), - modify_deadline_seconds: filter_modifies(&inputs[1000..]) - .into_iter() - .map(|tup| tup.1) - .collect(), - modify_deadline_ack_ids: filter_modifies(&inputs[1000..]) - .into_iter() - .map(|tup| tup.0) - .collect(), - stream_ack_deadline_seconds: 20, - client_id: String::new(), - max_outstanding_messages: 0, - max_outstanding_bytes: 0, + // check that all the futures got responses + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready((Ok(()), Ok(()), Ok(()), Ok(()), Ok(()))) + )); + + // send multiple acks again + let mut ack_fut = future::join3( + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id7".into(), + deadline: 1, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id8".into(), + deadline: 1, + }, + ), + TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id9".into(), + deadline: 1, + }, + ), + ) + .boxed(); + // however this time inject an error response from the server + server + .injected_errors + .lock() + .unwrap() + .push(tonic::Status::aborted("injected-error")); + + // drive the ack handler + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + assert_eq!( + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id7".into(), "ack-id8".into(), "ack-id9".into()], + ack_deadline_seconds: 1, + },] + ); + + // the ack tokens should each get back the error + let ack_responses = ack_fut.as_mut().poll(&mut cx); + match ack_responses { + Poll::Ready(( + Err(AcknowledgeError(AckErr::Request(status1))), + Err(AcknowledgeError(AckErr::Request(status2))), + Err(AcknowledgeError(AckErr::Request(status3))), + )) if ( + (status1.code(), status2.code(), status3.code()), + (status1.message(), status2.message(), status3.message()), + ) == ( + (Code::Aborted, Code::Aborted, Code::Aborted), + ("injected-error", "injected-error", "injected-error"), + ) => {} + _ => panic!("unexpected future output {ack_responses:?}"), }; + // if more than the batch limit is submitted, the handler will send multiple requests. + let futs = (0..(MAX_ACK_BATCH_SIZE + 2)) + .map(|i| { + TokenFeedback::send( + &ack_send, + ModAck { + id: format!("mass-ack{i}"), + deadline: 1, + }, + ) + }) + .collect::>(); + + assert!(matches!(ack_handler.as_mut().poll(&mut cx), Poll::Pending)); + let server_acks = take_server_acks(); + assert_eq!(server_acks.len(), 2); assert_eq!( - Ok(()), - inputs - .into_iter() - .try_for_each(|ack| sender.unbounded_send(ack)) + server_acks[0].ack_ids, + (0..MAX_ACK_BATCH_SIZE) + .map(|i| format!("mass-ack{i}")) + .collect::>() ); + const _SANITY_CHECK: [(); 2500] = [(); MAX_ACK_BATCH_SIZE]; assert_eq!( - Poll::Ready(Some(expected_first_batch)), - requests.as_mut().poll_next(&mut cx) + server_acks[1].ack_ids, + vec!["mass-ack2500".to_owned(), "mass-ack2501".to_owned()] ); + + // all the futures should get their success response + for fut in futs { + assert!(matches!( + fut.boxed().as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + // the handler future can complete after the sender side is dropped. + // however it must first flush any acks still in the queue. + let mut ack_fut = TokenFeedback::send( + &ack_send, + ModAck { + id: "ack-id99".into(), + deadline: 2, + }, + ) + .boxed(); + std::mem::drop(ack_send); + assert!(take_server_acks().is_empty()); // sanity check + assert!(matches!( + ack_handler.as_mut().poll(&mut cx), + Poll::Ready(()) + )); assert_eq!( - Poll::Ready(Some(expected_second_batch)), - requests.as_mut().poll_next(&mut cx) + take_server_acks(), + vec![api::ModifyAckDeadlineRequest { + subscription: "test-subscription".into(), + ack_ids: vec!["ack-id99".into()], + ack_deadline_seconds: 2, + }] ); - assert_eq!(Poll::Pending, requests.as_mut().poll_next(&mut cx)); + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Ok(())) + )); + } + + #[tokio::test] + async fn streaming_reqs_stop_drop() { + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + let (stream, stop_drop) = create_streaming_pull_request_stream( + "test-subscription".into(), + "test-client".into(), + StreamSubscriptionConfig::default(), + ); + let mut stream = stream.boxed(); + + // first call always yield the first element + assert!(matches!( + stream.as_mut().poll_next(&mut cx), + Poll::Ready(Some(api::StreamingPullRequest { .. })) + )); + + // then a periodic element waits for time + tokio::time::pause(); + assert!(matches!(stream.as_mut().poll_next(&mut cx), Poll::Pending)); + tokio::time::advance(Duration::from_secs(31)).await; + assert!(matches!( + stream.as_mut().poll_next(&mut cx), + Poll::Ready(Some(api::StreamingPullRequest { .. })) + )); + // pending on the next one + assert!(matches!(stream.as_mut().poll_next(&mut cx), Poll::Pending)); + + // however dropping the notifier should wake the stream and end it + std::mem::drop(stop_drop); + assert!(matches!( + stream.as_mut().poll_next(&mut cx), + Poll::Ready(None) + )); + } + + // panics in the background ack-handler task should be forwarded _somewhere_ + // ideally it would be to the issuing ack tokens, but it's much easier to pass to the message + // streamer + #[tokio::test] + async fn background_panic_forwarded() { + use std::panic; + let mut cx = Context::from_waker(futures::task::noop_waker_ref()); + + #[derive(Default, Clone)] + struct MockSubscriberServer {} + + #[tonic::codegen::async_trait] + impl api::subscriber_server::Subscriber for MockSubscriberServer { + async fn acknowledge( + &self, + _request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + panic!("injected test panic"); + } + + async fn streaming_pull( + &self, + _request: tonic::Request>, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + // send one message in order to provide an ack token. after that, produce no + // additional messages but don't end the stream, just hang basically + Ok(tonic::Response::new( + async_stream::stream! { + yield Ok(api::StreamingPullResponse { + received_messages: vec![api::ReceivedMessage { + ack_id: "ack1".into(), + delivery_attempt: 1, + message: Some(api::PubsubMessage { + data: vec![0u8; 16].into(), + ..Default::default() + }) + }], + ..Default::default() + }); + + future::pending::<()>().await; + } + .boxed(), + )) + } + } + + let server = MockSubscriberServer::default(); + + let mut stream = stream_from_client( + std::array::from_fn(|_| { + api::subscriber_client::SubscriberClient::new( + api::subscriber_server::SubscriberServer::new(server.clone()), + ) + }), + "test-subscription".into(), + StreamSubscriptionConfig::default(), + ExponentialBackoff::new(PubSubRetryCheck::default(), Default::default()), + ) + .boxed(); + + // pull the first message out to get an ack token + let ack_token = match stream.as_mut().poll_next(&mut cx) { + Poll::Ready(Some(Ok((ack_token, _message)))) => ack_token, + other => panic!("unexpected stream value {other:?}"), + }; + + // the stream is otherwise empty for now + assert!(matches!(stream.as_mut().poll_next(&mut cx), Poll::Pending)); + + // start an ack from the first message's token. this should trigger a panic in the + // background ack-handler task once it calls the mocked `acknowledge` function + let mut ack_fut = ack_token.ack().boxed(); + + // give the tokio test runtime an opportunity to run background tasks + tokio::task::yield_now().await; + + // the stream's poll should now forward that panic to the caller + match panic::catch_unwind(panic::AssertUnwindSafe(|| { + stream.as_mut().poll_next(&mut cx) + })) { + Ok(poll) => panic!("stream did not panic when expected, instead produced {poll:?}"), + Err(panic_cause) => match panic_cause.downcast::<&'static str>() { + Ok(text) => assert_eq!(*text, "injected test panic"), + Err(_) => panic!("unexpected panic contents"), + }, + } - // the request stream should end when the input stream ends - sender.disconnect(); - assert_eq!(Poll::Ready(None), requests.as_mut().poll_next(&mut cx)); + // and the ack future is informed that an error occurred + assert!(matches!( + ack_fut.as_mut().poll(&mut cx), + Poll::Ready(Err(AcknowledgeError(AckErr::BackgroundTaskPanic))) + )); } } diff --git a/tests/pubsub_client.rs b/tests/pubsub_client.rs index a293c54..3cd3cd8 100644 --- a/tests/pubsub_client.rs +++ b/tests/pubsub_client.rs @@ -949,78 +949,68 @@ mod pubsub_client_tests { } /// 1) Modifying a deadline with too great a deadline should be an error - /// 2) Ack'ing a message should error after the request stream is dropped - #[test] - fn ack_errors() { - let runtime = tokio::runtime::Runtime::new().unwrap(); - - // Interestingly, it appears that tonic spawns the request stream onto the runtime in some - // way, and that dropping the output stream or even the subscriber client does not drop - // the request stream. Instead, we have to drop the entire runtime in order to drop the - // background task which holds the ack request stream - - let mut ack_token = runtime.block_on(async { - let topic_name = "test-topic"; - let subscription_name = "test-subscription"; - - let emulator = Emulator::new().project("test-project").await.unwrap(); - let config = pubsub::PubSubConfig::new().endpoint(emulator.endpoint()); - - let mut publish_client = emulator - .builder() - .build_pubsub_publisher(config.clone()) - .await - .unwrap(); + /// 2) Ack'ing a message still works after the request stream is dropped + #[tokio::test] + async fn ack_errors() { + let topic_name = "test-topic"; + let subscription_name = "test-subscription"; - // Create a topic to query. - let topic = create_dummy_topic(&mut publish_client, emulator.project(), topic_name) - .await - .unwrap() - .into_inner(); + let emulator = Emulator::new().project("test-project").await.unwrap(); + let config = pubsub::PubSubConfig::new().endpoint(emulator.endpoint()); - let mut subscription_client = emulator - .builder() - .build_pubsub_subscriber(config.clone()) - .await - .unwrap(); + let mut publish_client = emulator + .builder() + .build_pubsub_publisher(config.clone()) + .await + .unwrap(); - // Create a subscription to query. Must be created before messages are published. - let _subscription = create_dummy_subscription( - &mut subscription_client, - emulator.project(), - subscription_name, - topic_name, - ) + // Create a topic to query. + let topic = create_dummy_topic(&mut publish_client, emulator.project(), topic_name) .await .unwrap() .into_inner(); - // send 1 message to the publisher to get an ack token - publish_client - .raw_api_mut() - .publish({ - let mut p = pubsub::api::PublishRequest::default(); - p.topic = topic.name; - p.messages = vec![{ - let mut m = pubsub::api::PubsubMessage::default(); - m.data = "foobar".into(); - m - }]; - p - }) - .await - .unwrap(); + let mut subscription_client = emulator + .builder() + .build_pubsub_subscriber(config.clone()) + .await + .unwrap(); - let subscription_stream = subscription_client.stream_subscription( - ProjectSubscriptionName::new(emulator.project(), subscription_name), - StreamSubscriptionConfig::default(), - ); + // Create a subscription to query. Must be created before messages are published. + let _subscription = create_dummy_subscription( + &mut subscription_client, + emulator.project(), + subscription_name, + topic_name, + ) + .await + .unwrap() + .into_inner(); + + // send 1 message to the publisher to get an ack token + publish_client + .raw_api_mut() + .publish({ + let mut p = pubsub::api::PublishRequest::default(); + p.topic = topic.name; + p.messages = vec![{ + let mut m = pubsub::api::PubsubMessage::default(); + m.data = "foobar".into(); + m + }]; + p + }) + .await + .unwrap(); - pin_mut!(subscription_stream); + let subscription_stream = subscription_client.stream_subscription( + ProjectSubscriptionName::new(emulator.project(), subscription_name), + StreamSubscriptionConfig::default(), + ); - let (ack_token, _message) = subscription_stream.next().await.unwrap().unwrap(); - ack_token - }); + pin_mut!(subscription_stream); + + let (mut ack_token, _message) = subscription_stream.next().await.unwrap().unwrap(); let mut cx = Context::from_waker(futures::task::noop_waker_ref()); @@ -1034,30 +1024,13 @@ mod pubsub_client_tests { })) ); - // invariant check that ack tokens still work while the runtime is alive - assert_eq!( - Box::pin(ack_token.modify_deadline(599)) - .as_mut() - .poll(&mut cx), - Poll::Ready(Ok(())) - ); - - std::mem::drop(runtime); + // sanity check that ack tokens work while the stream is alive + assert!(matches!(ack_token.modify_deadline(599).await, Ok(()))); - // now modifications or acks/nacks will fail + std::mem::drop(subscription_stream); - assert!(matches!( - Box::pin(ack_token.modify_deadline(599)) - .as_mut() - .poll(&mut cx), - Poll::Ready(Err(pubsub::ModifyAcknowledgeError::Modify( - pubsub::AcknowledgeError { .. } - ))) - )); - - assert!(matches!( - Box::pin(ack_token.ack()).as_mut().poll(&mut cx), - Poll::Ready(Err(pubsub::AcknowledgeError { .. })) - )); + // now modifications or acks/nacks can still proceed + assert!(matches!(ack_token.modify_deadline(599).await, Ok(()))); + assert!(matches!(ack_token.ack().await, Ok(()))); } }