diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c93319d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "musicfs"] + path = musicfs + url = /home/fujin/Code/agregators/musicfs +[submodule "tora"] + path = tora + url = /home/fujin/Code/agregators/tora diff --git a/Cargo.lock b/Cargo.lock index fa5925f..85eb6e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,9 @@ dependencies = [ "prost", "serde", "tokio", + "toml", "tonic", + "tonic-health", "tonic-prost", "tonic-reflection", ] @@ -715,6 +717,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "simd-adler32" version = "0.3.9" @@ -807,6 +818,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -822,6 +834,45 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + [[package]] name = "tonic" version = "0.14.6" @@ -852,6 +903,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-health" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcfab99db777fba2802f0dfa861d1628d1ae916fb199d29819941f139ae85082" +dependencies = [ + "prost", + "tokio", + "tokio-stream", + "tonic", + "tonic-prost", +] + [[package]] name = "tonic-prost" version = "0.14.6" @@ -980,3 +1044,9 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" diff --git a/Cargo.toml b/Cargo.toml index 88d9e91..fd88d4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,8 @@ serde = ["dep:serde"] # @@protoc_deletion_point(features) # This section is automatically generated by protoc-gen-prost-crate. # Changes in this area may be lost on regeneration. -proto_full = ["musicfs"] -"musicfs" = [] +proto_full = ["torrent"] +"torrent" = [] # @@protoc_insertion_point(features) [dependencies] @@ -23,5 +23,7 @@ tonic = { version = "0.14.2", features = ["gzip"] } tonic-prost = "0.14.2" tokio = { version = "1.52.3", features = [ "macros", "rt-multi-thread" ] } tonic-reflection = "0.14.6" +tonic-health = "0.14.6" +toml = "1.1.2" -[workspace] +[workspace] \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml index a4745d0..7f9139a 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -3,6 +3,7 @@ inputs: - directory: proto - directory: ../metadata-agregator/proto - directory: ../musicfs/proto + - directory: ../tora/proto plugins: - local: protoc-gen-prost #path: ../../target/debug/protoc-gen-prost diff --git a/devenv.lock b/devenv.lock index 9531f4e..5cefb5b 100644 --- a/devenv.lock +++ b/devenv.lock @@ -1,5 +1,85 @@ { "nodes": { + "bun2nix": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": [ + "pinix", + "nixpkgs" + ], + "systems": [ + "pinix", + "systems" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1778446047, + "narHash": "sha256-oQvcadh2BCkrog+SGrG6YffKJrveYpjj3TdQJWaKhaM=", + "owner": "nix-community", + "repo": "bun2nix", + "rev": "f2bc12af1a6369648aac41041ceeaa0b866599c6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "2.1.0", + "repo": "bun2nix", + "type": "github" + } + }, + "cachix": { + "inputs": { + "devenv": [ + "crate2nix" + ], + "flake-compat": [ + "crate2nix" + ], + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1767714506, + "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=", + "owner": "cachix", + "repo": "cachix", + "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "latest", + "repo": "cachix", + "type": "github" + } + }, + "crate2nix": { + "inputs": { + "cachix": "cachix", + "devshell": "devshell", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "nix-test-runner": "nix-test-runner", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1782759041, + "narHash": "sha256-2577vxyoBa8+ZRiXr3CuPtOuEtPRYsFPSZuEc/KI/80=", + "owner": "nix-community", + "repo": "crate2nix", + "rev": "5e1ecfd2d15b34ec90c2e51fdffbe8116595a767", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "crate2nix", + "type": "github" + } + }, "devenv": { "locked": { "dir": "src/modules", @@ -17,7 +97,42 @@ "type": "github" } }, + "devshell": { + "inputs": { + "nixpkgs": [ + "crate2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768818222, + "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=", + "owner": "numtide", + "repo": "devshell", + "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "flake-compat": { + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "revCount": 69, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" + } + }, + "flake-compat_2": { "flake": false, "locked": { "lastModified": 1767039857, @@ -33,9 +148,80 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "crate2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768135262, + "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "pinix", + "bun2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1777988971, + "narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "git-hooks": { "inputs": { - "flake-compat": "flake-compat", + "flake-compat": [ + "crate2nix", + "cachix", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "crate2nix", + "cachix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765404074, + "narHash": "sha256-+ZDU2d+vzWkEJiqprvV5PR26DVFN2vgddwG5SnPZcUM=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "2d6f58930fbcd82f6f9fd59fb6d13e37684ca529", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "git-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_2", "nixpkgs": [ "nixpkgs" ] @@ -54,22 +240,80 @@ "type": "github" } }, - "nixpkgs": { + "gitignore": { "inputs": { - "nixpkgs-src": "nixpkgs-src" + "nixpkgs": [ + "crate2nix", + "cachix", + "git-hooks", + "nixpkgs" + ] }, "locked": { - "lastModified": 1782924808, - "narHash": "sha256-tn2ahNv3ZNXyVHdPx/uw+N0xa7YSMtXUr6OEvu+s8ng=", - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "e2c881cb8d5f1cac6cef9d71f0d450a55691b999", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "crate2nix", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nix-test-runner": { + "flake": false, + "locked": { + "lastModified": 1588761593, + "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=", + "owner": "stoeffel", + "repo": "nix-test-runner", + "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2", + "type": "github" + }, + "original": { + "owner": "stoeffel", + "repo": "nix-test-runner", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1765186076, + "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", "type": "github" } }, @@ -90,15 +334,135 @@ "type": "github" } }, + "nixpkgs_2": { + "inputs": { + "nixpkgs-src": "nixpkgs-src" + }, + "locked": { + "lastModified": 1782924808, + "narHash": "sha256-tn2ahNv3ZNXyVHdPx/uw+N0xa7YSMtXUr6OEvu+s8ng=", + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "e2c881cb8d5f1cac6cef9d71f0d450a55691b999", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1773646010, + "narHash": "sha256-iYrs97hS7p5u4lQzuNWzuALGIOdkPXvjz7bviiBjUu8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "5b2c2d84341b2afb5647081c1386a80d7a8d8605", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pinix": { + "inputs": { + "bun2nix": "bun2nix", + "nixpkgs": "nixpkgs_3", + "systems": "systems" + }, + "locked": { + "lastModified": 1783064273, + "narHash": "sha256-8u4o7iP+GlgA/nxZtFy08SXaHehD0f6SZHi2cVV2ZfI=", + "owner": "lukasl-dev", + "repo": "pi.nix", + "rev": "9538c024e2fc57b764fdd0dd1db8d79b635a1f7e", + "type": "github" + }, + "original": { + "owner": "lukasl-dev", + "repo": "pi.nix", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "crate2nix", + "flake-compat" + ], + "gitignore": "gitignore_2", + "nixpkgs": [ + "crate2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769069492, + "narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { + "crate2nix": "crate2nix", "devenv": "devenv", - "git-hooks": "git-hooks", - "nixpkgs": "nixpkgs", - "treefmt-nix": "treefmt-nix" + "git-hooks": "git-hooks_2", + "nixpkgs": "nixpkgs_2", + "pinix": "pinix", + "treefmt-nix": "treefmt-nix_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" } }, "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "pinix", + "bun2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775636079, + "narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_2": { "inputs": { "nixpkgs": [ "nixpkgs" diff --git a/devenv.nix b/devenv.nix index 8b672f4..9ad70d2 100644 --- a/devenv.nix +++ b/devenv.nix @@ -40,4 +40,14 @@ opencode ]; + + services.postgres = { + enable = true; + # initialDatabases = [ + # { + # name = "toradb"; + # schema = ./db/schema.sql; + # } + # ]; + }; } diff --git a/devenv.yaml b/devenv.yaml index ee5a179..f982501 100644 --- a/devenv.yaml +++ b/devenv.yaml @@ -11,3 +11,7 @@ inputs: inputs: nixpkgs: follows: nixpkgs + +imports: +- ./musicfs +- ./tora diff --git a/musicfs b/musicfs new file mode 160000 index 0000000..5f79b3c --- /dev/null +++ b/musicfs @@ -0,0 +1 @@ +Subproject commit 5f79b3c2b09f64e922ce4451c2a7497a81a17857 diff --git a/proto/health.proto b/proto/health.proto new file mode 100644 index 0000000..aa65be2 --- /dev/null +++ b/proto/health.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package health; + +// Custom detailed health check, distinct from grpc.health.v1.Health: a single +// call returns our own status plus the status of every subservice we depend +// on (e.g. torad), instead of requiring one Check call per service name. +service Health { + rpc Check(CheckRequest) returns (CheckResponse); +} + +message CheckRequest {} + +enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; +} + +message SubserviceStatus { + string name = 1; + ServingStatus status = 2; + // Populated when status is NOT_SERVING, e.g. a connection or timeout error. + string message = 3; +} + +message CheckResponse { + ServingStatus status = 1; + repeated SubserviceStatus subservices = 2; +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..efc67e1 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,17 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Config { + pub service: ServiceConfig, + pub torrent: TorrentConfig, +} + +#[derive(Debug, Deserialize)] +pub struct ServiceConfig { + pub address: String, +} + +#[derive(Debug, Deserialize)] +pub struct TorrentConfig { + pub address: String, +} diff --git a/src/generated/health/health.rs b/src/generated/health/health.rs new file mode 100644 index 0000000..7e76293 --- /dev/null +++ b/src/generated/health/health.rs @@ -0,0 +1,170 @@ +// @generated +// This file is @generated by prost-build. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct CheckRequest {} +impl ::prost::Name for CheckRequest { + const NAME: &'static str = "CheckRequest"; + const PACKAGE: &'static str = "health"; + fn full_name() -> ::prost::alloc::string::String { + "health.CheckRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/health.CheckRequest".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct SubserviceStatus { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(enumeration = "ServingStatus", tag = "2")] + pub status: i32, + /// Populated when status is NOT_SERVING, e.g. a connection or timeout error. + #[prost(string, tag = "3")] + pub message: ::prost::alloc::string::String, +} +impl ::prost::Name for SubserviceStatus { + const NAME: &'static str = "SubserviceStatus"; + const PACKAGE: &'static str = "health"; + fn full_name() -> ::prost::alloc::string::String { + "health.SubserviceStatus".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/health.SubserviceStatus".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CheckResponse { + #[prost(enumeration = "ServingStatus", tag = "1")] + pub status: i32, + #[prost(message, repeated, tag = "2")] + pub subservices: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for CheckResponse { + const NAME: &'static str = "CheckResponse"; + const PACKAGE: &'static str = "health"; + fn full_name() -> ::prost::alloc::string::String { + "health.CheckResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/health.CheckResponse".into() + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ServingStatus { + Unknown = 0, + Serving = 1, + NotServing = 2, +} +impl ServingStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unknown => "UNKNOWN", + Self::Serving => "SERVING", + Self::NotServing => "NOT_SERVING", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "SERVING" => Some(Self::Serving), + "NOT_SERVING" => Some(Self::NotServing), + _ => None, + } + } +} +/// Encoded file descriptor set for the `health` package +pub const FILE_DESCRIPTOR_SET: &[u8] = &[ + 0x0a, 0xb1, 0x0a, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x22, 0x0e, 0x0a, 0x0c, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6f, 0x0a, 0x10, 0x53, 0x75, 0x62, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x15, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7a, 0x0a, 0x0d, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x73, 0x75, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2a, 0x3a, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, + 0x10, 0x02, 0x32, 0x3e, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x34, 0x0a, 0x05, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x14, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4a, 0x97, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x1d, 0x01, 0x0a, 0x08, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x00, + 0x0f, 0x0a, 0xed, 0x01, 0x0a, 0x02, 0x06, 0x00, 0x12, 0x04, 0x07, 0x00, 0x09, 0x01, 0x1a, 0xe0, + 0x01, 0x20, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x20, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2c, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x63, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x3a, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x0a, 0x20, 0x63, + 0x61, 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x6f, 0x75, 0x72, 0x20, + 0x6f, 0x77, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x70, 0x6c, 0x75, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x73, 0x75, 0x62, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x77, + 0x65, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x6f, 0x6e, 0x20, 0x28, 0x65, 0x2e, + 0x67, 0x2e, 0x20, 0x74, 0x6f, 0x72, 0x61, 0x64, 0x29, 0x2c, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x20, + 0x6f, 0x6e, 0x65, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x20, 0x70, + 0x65, 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2e, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x03, 0x07, 0x08, 0x0e, 0x0a, 0x0b, 0x0a, + 0x04, 0x06, 0x00, 0x02, 0x00, 0x12, 0x03, 0x08, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x08, 0x06, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, + 0x02, 0x12, 0x03, 0x08, 0x0c, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x08, 0x23, 0x30, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x03, 0x0b, 0x00, 0x17, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x08, 0x14, 0x0a, 0x0a, 0x0a, 0x02, 0x05, + 0x00, 0x12, 0x04, 0x0d, 0x00, 0x11, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, + 0x0d, 0x05, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0e, 0x02, + 0x09, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0e, 0x02, 0x0e, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x0e, 0x0c, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0f, 0x02, 0x09, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, + 0x02, 0x01, 0x12, 0x03, 0x0f, 0x02, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, + 0x12, 0x03, 0x0f, 0x0c, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x10, 0x02, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x10, 0x02, 0x12, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x10, 0x10, 0x11, 0x0a, 0x0a, + 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, + 0x01, 0x12, 0x03, 0x13, 0x08, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, + 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, + 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x09, 0x0d, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x10, 0x11, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x15, 0x02, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, + 0x01, 0x12, 0x03, 0x15, 0x10, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, + 0x03, 0x15, 0x19, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x17, + 0x02, 0x08, 0x0a, 0x58, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x17, 0x02, 0x15, 0x1a, + 0x4b, 0x20, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6e, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x69, 0x73, 0x20, 0x4e, 0x4f, 0x54, 0x5f, 0x53, + 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x2c, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x20, 0x61, 0x20, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x17, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, + 0x02, 0x02, 0x03, 0x12, 0x03, 0x17, 0x13, 0x14, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, + 0x1a, 0x00, 0x1d, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x1a, 0x08, 0x15, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1b, 0x02, 0x0f, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x10, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x1b, 0x19, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, + 0x12, 0x03, 0x1c, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1c, + 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x1c, 0x0b, 0x1b, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x1c, 0x27, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1c, 0x2a, 0x2b, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +]; +include!("health.serde.rs"); +include!("health.tonic.rs"); +// @@protoc_insertion_point(module) diff --git a/src/generated/health/health.serde.rs b/src/generated/health/health.serde.rs new file mode 100644 index 0000000..6439a95 --- /dev/null +++ b/src/generated/health/health.serde.rs @@ -0,0 +1,380 @@ +// @generated +impl serde::Serialize for CheckRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("health.CheckRequest", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for CheckRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField {} + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = CheckRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct health.CheckRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(CheckRequest {}) + } + } + deserializer.deserialize_struct("health.CheckRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for CheckResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.status != 0 { + len += 1; + } + if !self.subservices.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("health.CheckResponse", len)?; + if self.status != 0 { + let v = ServingStatus::try_from(self.status).map_err(|_| { + serde::ser::Error::custom(format!("Invalid variant {}", self.status)) + })?; + struct_ser.serialize_field("status", &v)?; + } + if !self.subservices.is_empty() { + struct_ser.serialize_field("subservices", &self.subservices)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for CheckResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["status", "subservices"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Status, + Subservices, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "status" => Ok(GeneratedField::Status), + "subservices" => Ok(GeneratedField::Subservices), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = CheckResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct health.CheckResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut status__ = None; + let mut subservices__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Status => { + if status__.is_some() { + return Err(serde::de::Error::duplicate_field("status")); + } + status__ = Some(map_.next_value::()? as i32); + } + GeneratedField::Subservices => { + if subservices__.is_some() { + return Err(serde::de::Error::duplicate_field("subservices")); + } + subservices__ = Some(map_.next_value()?); + } + } + } + Ok(CheckResponse { + status: status__.unwrap_or_default(), + subservices: subservices__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("health.CheckResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ServingStatus { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Unknown => "UNKNOWN", + Self::Serving => "SERVING", + Self::NotServing => "NOT_SERVING", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for ServingStatus { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["UNKNOWN", "SERVING", "NOT_SERVING"]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ServingStatus; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + fn visit_i64(self, v: i64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self) + }) + } + + fn visit_u64(self, v: u64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self) + }) + } + + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "UNKNOWN" => Ok(ServingStatus::Unknown), + "SERVING" => Ok(ServingStatus::Serving), + "NOT_SERVING" => Ok(ServingStatus::NotServing), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for SubserviceStatus { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.name.is_empty() { + len += 1; + } + if self.status != 0 { + len += 1; + } + if !self.message.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("health.SubserviceStatus", len)?; + if !self.name.is_empty() { + struct_ser.serialize_field("name", &self.name)?; + } + if self.status != 0 { + let v = ServingStatus::try_from(self.status).map_err(|_| { + serde::ser::Error::custom(format!("Invalid variant {}", self.status)) + })?; + struct_ser.serialize_field("status", &v)?; + } + if !self.message.is_empty() { + struct_ser.serialize_field("message", &self.message)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for SubserviceStatus { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["name", "status", "message"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Name, + Status, + Message, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "name" => Ok(GeneratedField::Name), + "status" => Ok(GeneratedField::Status), + "message" => Ok(GeneratedField::Message), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = SubserviceStatus; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct health.SubserviceStatus") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut name__ = None; + let mut status__ = None; + let mut message__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Name => { + if name__.is_some() { + return Err(serde::de::Error::duplicate_field("name")); + } + name__ = Some(map_.next_value()?); + } + GeneratedField::Status => { + if status__.is_some() { + return Err(serde::de::Error::duplicate_field("status")); + } + status__ = Some(map_.next_value::()? as i32); + } + GeneratedField::Message => { + if message__.is_some() { + return Err(serde::de::Error::duplicate_field("message")); + } + message__ = Some(map_.next_value()?); + } + } + } + Ok(SubserviceStatus { + name: name__.unwrap_or_default(), + status: status__.unwrap_or_default(), + message: message__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("health.SubserviceStatus", FIELDS, GeneratedVisitor) + } +} diff --git a/src/generated/health/health.tonic.rs b/src/generated/health/health.tonic.rs new file mode 100644 index 0000000..baee54c --- /dev/null +++ b/src/generated/health/health.tonic.rs @@ -0,0 +1,269 @@ +// @generated +/// Generated client implementations. +pub mod health_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::http::Uri; + use tonic::codegen::*; + #[derive(Debug, Clone)] + pub struct HealthClient { + inner: tonic::client::Grpc, + } + impl HealthClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl HealthClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> HealthClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + >>::Error: + Into + std::marker::Send + std::marker::Sync, + { + HealthClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn check( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/health.Health/Check"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("health.Health", "Check")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod health_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with HealthServer. + #[async_trait] + pub trait Health: std::marker::Send + std::marker::Sync + 'static { + async fn check( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct HealthServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl HealthServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor(inner: T, interceptor: F) -> 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 HealthServer + where + T: Health, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/health.Health/Check" => { + #[allow(non_camel_case_types)] + struct CheckSvc(pub Arc); + impl tonic::server::UnaryService for CheckSvc { + type Response = super::CheckResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::check(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = CheckSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => Box::pin(async move { + let mut response = http::Response::new(tonic::body::Body::default()); + let headers = response.headers_mut(); + headers.insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers.insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }), + } + } + } + impl Clone for HealthServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "health.Health"; + impl tonic::server::NamedService for HealthServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/src/generated/mod.rs b/src/generated/mod.rs index 84af9ce..d9fb2ef 100644 --- a/src/generated/mod.rs +++ b/src/generated/mod.rs @@ -1,7 +1,7 @@ // @generated -#[cfg(feature = "musicfs")] -// @@protoc_insertion_point(attribute:musicfs) -pub mod musicfs { - include!("musicfs/musicfs.rs"); - // @@protoc_insertion_point(musicfs) +#[cfg(feature = "torrent")] +// @@protoc_insertion_point(attribute:torrent) +pub mod torrent { + include!("torrent/torrent.rs"); + // @@protoc_insertion_point(torrent) } diff --git a/src/generated/torrent/torrent.rs b/src/generated/torrent/torrent.rs new file mode 100644 index 0000000..a8dbfb9 --- /dev/null +++ b/src/generated/torrent/torrent.rs @@ -0,0 +1,497 @@ +// @generated +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct AddRequest { + #[prost(string, tag = "1")] + pub magnet: ::prost::alloc::string::String, + /// Optional output directory override. Empty means use torad's default. + #[prost(string, tag = "2")] + pub output_dir: ::prost::alloc::string::String, +} +impl ::prost::Name for AddRequest { + const NAME: &'static str = "AddRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.AddRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.AddRequest".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct AddResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +impl ::prost::Name for AddResponse { + const NAME: &'static str = "AddResponse"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.AddResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.AddResponse".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct StatusRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +impl ::prost::Name for StatusRequest { + const NAME: &'static str = "StatusRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.StatusRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.StatusRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ListRequest {} +impl ::prost::Name for ListRequest { + const NAME: &'static str = "ListRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.ListRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.ListRequest".into() + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListResponse { + #[prost(message, repeated, tag = "1")] + pub torrents: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for ListResponse { + const NAME: &'static str = "ListResponse"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.ListResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.ListResponse".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct RemoveRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(bool, tag = "2")] + pub delete_files: bool, +} +impl ::prost::Name for RemoveRequest { + const NAME: &'static str = "RemoveRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.RemoveRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.RemoveRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct RemoveResponse {} +impl ::prost::Name for RemoveResponse { + const NAME: &'static str = "RemoveResponse"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.RemoveResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.RemoveResponse".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PauseRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +impl ::prost::Name for PauseRequest { + const NAME: &'static str = "PauseRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.PauseRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.PauseRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PauseResponse {} +impl ::prost::Name for PauseResponse { + const NAME: &'static str = "PauseResponse"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.PauseResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.PauseResponse".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ResumeRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +impl ::prost::Name for ResumeRequest { + const NAME: &'static str = "ResumeRequest"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.ResumeRequest".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.ResumeRequest".into() + } +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ResumeResponse {} +impl ::prost::Name for ResumeResponse { + const NAME: &'static str = "ResumeResponse"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.ResumeResponse".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.ResumeResponse".into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct TorrentStatus { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub info_hash: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub source: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub output_path: ::prost::alloc::string::String, + #[prost(uint64, tag = "6")] + pub total_bytes: u64, + #[prost(uint64, tag = "7")] + pub downloaded_bytes: u64, + #[prost(enumeration = "State", tag = "8")] + pub state: i32, + #[prost(string, tag = "9")] + pub error_message: ::prost::alloc::string::String, + #[prost(uint64, tag = "10")] + pub download_speed_bps: u64, + #[prost(uint64, tag = "11")] + pub eta_seconds: u64, + #[prost(uint64, tag = "12")] + pub uploaded_bytes: u64, + #[prost(uint64, tag = "13")] + pub upload_speed_bps: u64, + #[prost(uint32, tag = "14")] + pub peers: u32, + #[prost(uint32, tag = "15")] + pub seeds: u32, +} +impl ::prost::Name for TorrentStatus { + const NAME: &'static str = "TorrentStatus"; + const PACKAGE: &'static str = "torrent"; + fn full_name() -> ::prost::alloc::string::String { + "torrent.TorrentStatus".into() + } + fn type_url() -> ::prost::alloc::string::String { + "/torrent.TorrentStatus".into() + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum State { + Unspecified = 0, + Pending = 1, + Downloading = 2, + Paused = 3, + Finished = 4, + Error = 5, +} +impl State { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "STATE_UNSPECIFIED", + Self::Pending => "PENDING", + Self::Downloading => "DOWNLOADING", + Self::Paused => "PAUSED", + Self::Finished => "FINISHED", + Self::Error => "ERROR", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "STATE_UNSPECIFIED" => Some(Self::Unspecified), + "PENDING" => Some(Self::Pending), + "DOWNLOADING" => Some(Self::Downloading), + "PAUSED" => Some(Self::Paused), + "FINISHED" => Some(Self::Finished), + "ERROR" => Some(Self::Error), + _ => None, + } + } +} +/// Encoded file descriptor set for the `torrent` package +pub const FILE_DESCRIPTOR_SET: &[u8] = &[ + 0x0a, 0x90, 0x1f, 0x0a, 0x0d, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x07, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x22, 0x43, 0x0a, 0x0a, 0x41, + 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x67, + 0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x67, 0x6e, 0x65, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x44, 0x69, 0x72, + 0x22, 0x1d, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x0d, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x42, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x32, 0x0a, 0x08, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x6f, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x74, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x0a, 0x0c, 0x50, 0x61, 0x75, + 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0f, 0x0a, 0x0d, 0x50, 0x61, 0x75, + 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65, + 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x52, + 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xec, 0x03, + 0x0a, 0x0d, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x66, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65, + 0x65, 0x64, 0x5f, 0x62, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73, 0x12, 0x1f, + 0x0a, 0x0b, 0x65, 0x74, 0x61, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x74, 0x61, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, + 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, 0x62, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x42, 0x70, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x65, 0x65, 0x64, 0x73, 0x2a, 0x61, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, + 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x4f, 0x57, + 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x41, + 0x55, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, + 0x45, 0x44, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x32, + 0xd9, 0x02, 0x0a, 0x08, 0x54, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x03, + 0x41, 0x64, 0x64, 0x12, 0x13, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x64, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, + 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x14, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, + 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x50, 0x61, 0x75, 0x73, + 0x65, 0x12, 0x15, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x75, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x74, 0x6f, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, + 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4a, 0xad, 0x14, 0x0a, 0x06, + 0x12, 0x04, 0x00, 0x00, 0x53, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12, + 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x00, 0x10, 0x0a, 0x0a, 0x0a, 0x02, 0x06, 0x00, + 0x12, 0x04, 0x04, 0x00, 0x11, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x03, 0x04, + 0x08, 0x10, 0x0a, 0x5a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x00, 0x12, 0x03, 0x06, 0x02, 0x2c, 0x1a, + 0x4d, 0x20, 0x41, 0x64, 0x64, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x20, 0x6c, 0x69, + 0x6e, 0x6b, 0x20, 0x6f, 0x72, 0x20, 0x2e, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x06, 0x06, 0x09, 0x0a, 0x0c, 0x0a, 0x05, + 0x06, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x06, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x06, 0x1f, 0x2a, 0x0a, 0x3a, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x01, + 0x12, 0x03, 0x08, 0x02, 0x34, 0x1a, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6f, + 0x66, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08, + 0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x0d, 0x1a, + 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x25, 0x32, 0x0a, 0x35, + 0x0a, 0x04, 0x06, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x02, 0x2f, 0x1a, 0x28, 0x20, 0x4c, 0x69, + 0x73, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x20, + 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x65, + 0x6d, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x0a, 0x06, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x0a, 0x0b, + 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0a, 0x21, 0x2d, 0x0a, + 0x2e, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x02, 0x35, 0x1a, 0x21, 0x20, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x61, 0x20, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0c, 0x06, 0x0c, 0x0a, 0x0c, 0x0a, + 0x05, 0x06, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x0c, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, + 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0c, 0x25, 0x33, 0x0a, 0x2b, 0x0a, 0x04, 0x06, 0x00, 0x02, + 0x04, 0x12, 0x03, 0x0e, 0x02, 0x32, 0x1a, 0x1e, 0x20, 0x50, 0x61, 0x75, 0x73, 0x65, 0x20, 0x61, + 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x01, 0x12, + 0x03, 0x0e, 0x06, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x0e, + 0x0c, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x04, 0x03, 0x12, 0x03, 0x0e, 0x23, 0x30, + 0x0a, 0x27, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x05, 0x12, 0x03, 0x10, 0x02, 0x35, 0x1a, 0x1a, 0x20, + 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x61, 0x20, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x20, + 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, + 0x05, 0x01, 0x12, 0x03, 0x10, 0x06, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x02, + 0x12, 0x03, 0x10, 0x0d, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x05, 0x03, 0x12, 0x03, + 0x10, 0x25, 0x33, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x13, 0x00, 0x17, 0x01, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x13, 0x08, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, + 0x00, 0x12, 0x03, 0x14, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x14, 0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, + 0x12, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x16, 0x02, 0x08, + 0x0a, 0x53, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x18, 0x1a, 0x46, 0x20, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, + 0x64, 0x65, 0x2e, 0x20, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x74, 0x6f, 0x72, 0x61, 0x64, 0x27, 0x73, 0x20, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x16, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x16, 0x16, + 0x17, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x19, 0x00, 0x1b, 0x01, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x19, 0x08, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x1a, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, + 0x03, 0x1a, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1a, + 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1a, 0x0e, 0x0f, + 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x1d, 0x00, 0x1f, 0x01, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, + 0x05, 0x12, 0x03, 0x1e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, + 0x1e, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x09, + 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x0e, 0x0f, 0x0a, + 0x09, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x03, 0x21, 0x00, 0x16, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, + 0x01, 0x12, 0x03, 0x21, 0x08, 0x13, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x23, 0x00, + 0x25, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x23, 0x08, 0x14, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x24, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x00, 0x06, 0x12, 0x03, 0x24, 0x0b, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x24, 0x19, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x24, 0x24, 0x25, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x27, 0x00, 0x2a, 0x01, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x27, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x28, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, + 0x00, 0x12, 0x03, 0x28, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x28, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x28, + 0x0e, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, 0x29, 0x02, 0x06, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, 0x12, 0x03, 0x29, 0x02, 0x18, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x29, 0x07, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x29, 0x16, 0x17, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x06, 0x12, + 0x03, 0x2c, 0x00, 0x19, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x16, + 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x07, 0x12, 0x04, 0x2e, 0x00, 0x30, 0x01, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x07, 0x01, 0x12, 0x03, 0x2e, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, + 0x05, 0x12, 0x03, 0x2f, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, 0x00, 0x12, 0x03, + 0x2f, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2f, 0x09, + 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2f, 0x0e, 0x0f, 0x0a, + 0x09, 0x0a, 0x02, 0x04, 0x08, 0x12, 0x03, 0x32, 0x00, 0x18, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x08, + 0x01, 0x12, 0x03, 0x32, 0x08, 0x15, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x09, 0x12, 0x04, 0x34, 0x00, + 0x36, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x09, 0x01, 0x12, 0x03, 0x34, 0x08, 0x15, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x05, 0x12, 0x03, 0x35, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x09, 0x02, 0x00, 0x12, 0x03, 0x35, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x35, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x35, 0x0e, 0x0f, 0x0a, 0x09, 0x0a, 0x02, 0x04, 0x0a, 0x12, 0x03, 0x38, 0x00, 0x19, + 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0a, 0x01, 0x12, 0x03, 0x38, 0x08, 0x16, 0x0a, 0x0a, 0x0a, 0x02, + 0x05, 0x00, 0x12, 0x04, 0x3a, 0x00, 0x41, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, + 0x03, 0x3a, 0x05, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3b, + 0x02, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x3b, 0x02, 0x18, 0x0a, + 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x3b, 0x16, 0x17, 0x0a, 0x0c, 0x0a, + 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3c, 0x02, 0x09, 0x0a, 0x0b, 0x0a, 0x04, 0x05, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x3c, 0x02, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, + 0x02, 0x12, 0x03, 0x3c, 0x0c, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, 0x12, + 0x03, 0x3d, 0x02, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x3d, 0x02, + 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x3d, 0x10, 0x11, 0x0a, + 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, + 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3e, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, + 0x02, 0x03, 0x02, 0x12, 0x03, 0x3e, 0x0b, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, + 0x01, 0x12, 0x03, 0x3f, 0x02, 0x0a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x04, 0x12, 0x03, + 0x3f, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3f, 0x0d, + 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x05, 0x01, 0x12, 0x03, 0x40, 0x02, 0x07, 0x0a, + 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x05, 0x12, 0x03, 0x40, 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x00, 0x02, 0x05, 0x02, 0x12, 0x03, 0x40, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0b, + 0x12, 0x04, 0x43, 0x00, 0x53, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0b, 0x01, 0x12, 0x03, 0x43, + 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x05, 0x12, 0x03, 0x44, 0x02, 0x08, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x00, 0x12, 0x03, 0x44, 0x02, 0x10, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x12, 0x03, 0x44, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x0b, 0x02, 0x00, 0x03, 0x12, 0x03, 0x44, 0x0e, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, + 0x01, 0x05, 0x12, 0x03, 0x45, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x01, 0x12, + 0x03, 0x45, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x03, 0x45, + 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x12, 0x03, 0x45, 0x15, 0x16, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x02, 0x05, 0x12, 0x03, 0x46, 0x02, 0x08, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x02, 0x12, 0x03, 0x46, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x0b, 0x02, 0x02, 0x01, 0x12, 0x03, 0x46, 0x09, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, + 0x02, 0x03, 0x12, 0x03, 0x46, 0x10, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x05, + 0x12, 0x03, 0x47, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x03, 0x12, 0x03, 0x47, + 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x01, 0x12, 0x03, 0x47, 0x09, 0x0f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x03, 0x03, 0x12, 0x03, 0x47, 0x12, 0x13, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x04, 0x05, 0x12, 0x03, 0x48, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x0b, 0x02, 0x04, 0x12, 0x03, 0x48, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, + 0x04, 0x01, 0x12, 0x03, 0x48, 0x09, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x04, 0x03, + 0x12, 0x03, 0x48, 0x17, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x05, 0x12, 0x03, + 0x49, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x05, 0x12, 0x03, 0x49, 0x02, 0x19, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x01, 0x12, 0x03, 0x49, 0x09, 0x14, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x05, 0x03, 0x12, 0x03, 0x49, 0x17, 0x18, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0b, 0x02, 0x06, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, + 0x02, 0x06, 0x12, 0x03, 0x4a, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x06, 0x01, + 0x12, 0x03, 0x4a, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x06, 0x03, 0x12, 0x03, + 0x4a, 0x1c, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x07, 0x06, 0x12, 0x03, 0x4b, 0x02, + 0x07, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x07, 0x12, 0x03, 0x4b, 0x02, 0x12, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x07, 0x01, 0x12, 0x03, 0x4b, 0x08, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0b, 0x02, 0x07, 0x03, 0x12, 0x03, 0x4b, 0x10, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, + 0x02, 0x08, 0x05, 0x12, 0x03, 0x4c, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x08, + 0x12, 0x03, 0x4c, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x08, 0x01, 0x12, 0x03, + 0x4c, 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x08, 0x03, 0x12, 0x03, 0x4c, 0x19, + 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x09, 0x05, 0x12, 0x03, 0x4d, 0x02, 0x08, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x09, 0x12, 0x03, 0x4d, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0b, 0x02, 0x09, 0x01, 0x12, 0x03, 0x4d, 0x09, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, + 0x02, 0x09, 0x03, 0x12, 0x03, 0x4d, 0x1e, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a, + 0x05, 0x12, 0x03, 0x4e, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0a, 0x12, 0x03, + 0x4e, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a, 0x01, 0x12, 0x03, 0x4e, 0x09, + 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0a, 0x03, 0x12, 0x03, 0x4e, 0x17, 0x19, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0b, 0x05, 0x12, 0x03, 0x4f, 0x02, 0x08, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x0b, 0x02, 0x0b, 0x12, 0x03, 0x4f, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, + 0x02, 0x0b, 0x01, 0x12, 0x03, 0x4f, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0b, + 0x03, 0x12, 0x03, 0x4f, 0x1a, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x05, 0x12, + 0x03, 0x50, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0c, 0x12, 0x03, 0x50, 0x02, + 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x01, 0x12, 0x03, 0x50, 0x09, 0x19, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0c, 0x03, 0x12, 0x03, 0x50, 0x1c, 0x1e, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x0b, 0x02, 0x0d, 0x05, 0x12, 0x03, 0x51, 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x0b, 0x02, 0x0d, 0x12, 0x03, 0x51, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0d, + 0x01, 0x12, 0x03, 0x51, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0d, 0x03, 0x12, + 0x03, 0x51, 0x11, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0e, 0x05, 0x12, 0x03, 0x52, + 0x02, 0x08, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x0e, 0x12, 0x03, 0x52, 0x02, 0x14, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x0e, 0x01, 0x12, 0x03, 0x52, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x0b, 0x02, 0x0e, 0x03, 0x12, 0x03, 0x52, 0x11, 0x13, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +]; +include!("torrent.serde.rs"); +include!("torrent.tonic.rs"); +// @@protoc_insertion_point(module) diff --git a/src/generated/torrent/torrent.serde.rs b/src/generated/torrent/torrent.serde.rs new file mode 100644 index 0000000..c626f55 --- /dev/null +++ b/src/generated/torrent/torrent.serde.rs @@ -0,0 +1,1448 @@ +// @generated +impl serde::Serialize for AddRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.magnet.is_empty() { + len += 1; + } + if !self.output_dir.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.AddRequest", len)?; + if !self.magnet.is_empty() { + struct_ser.serialize_field("magnet", &self.magnet)?; + } + if !self.output_dir.is_empty() { + struct_ser.serialize_field("outputDir", &self.output_dir)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AddRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["magnet", "output_dir", "outputDir"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Magnet, + OutputDir, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "magnet" => Ok(GeneratedField::Magnet), + "outputDir" | "output_dir" => Ok(GeneratedField::OutputDir), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AddRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.AddRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut magnet__ = None; + let mut output_dir__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Magnet => { + if magnet__.is_some() { + return Err(serde::de::Error::duplicate_field("magnet")); + } + magnet__ = Some(map_.next_value()?); + } + GeneratedField::OutputDir => { + if output_dir__.is_some() { + return Err(serde::de::Error::duplicate_field("outputDir")); + } + output_dir__ = Some(map_.next_value()?); + } + } + } + Ok(AddRequest { + magnet: magnet__.unwrap_or_default(), + output_dir: output_dir__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.AddRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for AddResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.AddResponse", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AddResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["id"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AddResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.AddResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + } + } + Ok(AddResponse { + id: id__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.AddResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ListRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("torrent.ListRequest", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ListRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField {} + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ListRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.ListRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(ListRequest {}) + } + } + deserializer.deserialize_struct("torrent.ListRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ListResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.torrents.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.ListResponse", len)?; + if !self.torrents.is_empty() { + struct_ser.serialize_field("torrents", &self.torrents)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ListResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["torrents"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Torrents, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "torrents" => Ok(GeneratedField::Torrents), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ListResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.ListResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut torrents__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Torrents => { + if torrents__.is_some() { + return Err(serde::de::Error::duplicate_field("torrents")); + } + torrents__ = Some(map_.next_value()?); + } + } + } + Ok(ListResponse { + torrents: torrents__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.ListResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for PauseRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.PauseRequest", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for PauseRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["id"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = PauseRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.PauseRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + } + } + Ok(PauseRequest { + id: id__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.PauseRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for PauseResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("torrent.PauseResponse", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for PauseResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField {} + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = PauseResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.PauseResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(PauseResponse {}) + } + } + deserializer.deserialize_struct("torrent.PauseResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for RemoveRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + if self.delete_files { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.RemoveRequest", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + if self.delete_files { + struct_ser.serialize_field("deleteFiles", &self.delete_files)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for RemoveRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["id", "delete_files", "deleteFiles"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + DeleteFiles, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + "deleteFiles" | "delete_files" => Ok(GeneratedField::DeleteFiles), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = RemoveRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.RemoveRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + let mut delete_files__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + GeneratedField::DeleteFiles => { + if delete_files__.is_some() { + return Err(serde::de::Error::duplicate_field("deleteFiles")); + } + delete_files__ = Some(map_.next_value()?); + } + } + } + Ok(RemoveRequest { + id: id__.unwrap_or_default(), + delete_files: delete_files__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.RemoveRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for RemoveResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("torrent.RemoveResponse", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for RemoveResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField {} + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = RemoveResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.RemoveResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(RemoveResponse {}) + } + } + deserializer.deserialize_struct("torrent.RemoveResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ResumeRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.ResumeRequest", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ResumeRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["id"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ResumeRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.ResumeRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + } + } + Ok(ResumeRequest { + id: id__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.ResumeRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ResumeResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("torrent.ResumeResponse", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ResumeResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField {} + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ResumeResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.ResumeResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(ResumeResponse {}) + } + } + deserializer.deserialize_struct("torrent.ResumeResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for State { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Unspecified => "STATE_UNSPECIFIED", + Self::Pending => "PENDING", + Self::Downloading => "DOWNLOADING", + Self::Paused => "PAUSED", + Self::Finished => "FINISHED", + Self::Error => "ERROR", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for State { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "STATE_UNSPECIFIED", + "PENDING", + "DOWNLOADING", + "PAUSED", + "FINISHED", + "ERROR", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = State; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + fn visit_i64(self, v: i64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self) + }) + } + + fn visit_u64(self, v: u64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self) + }) + } + + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "STATE_UNSPECIFIED" => Ok(State::Unspecified), + "PENDING" => Ok(State::Pending), + "DOWNLOADING" => Ok(State::Downloading), + "PAUSED" => Ok(State::Paused), + "FINISHED" => Ok(State::Finished), + "ERROR" => Ok(State::Error), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for StatusRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.StatusRequest", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for StatusRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &["id"]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = StatusRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.StatusRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + } + } + Ok(StatusRequest { + id: id__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.StatusRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for TorrentStatus { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + if !self.info_hash.is_empty() { + len += 1; + } + if !self.name.is_empty() { + len += 1; + } + if !self.source.is_empty() { + len += 1; + } + if !self.output_path.is_empty() { + len += 1; + } + if self.total_bytes != 0 { + len += 1; + } + if self.downloaded_bytes != 0 { + len += 1; + } + if self.state != 0 { + len += 1; + } + if !self.error_message.is_empty() { + len += 1; + } + if self.download_speed_bps != 0 { + len += 1; + } + if self.eta_seconds != 0 { + len += 1; + } + if self.uploaded_bytes != 0 { + len += 1; + } + if self.upload_speed_bps != 0 { + len += 1; + } + if self.peers != 0 { + len += 1; + } + if self.seeds != 0 { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("torrent.TorrentStatus", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + if !self.info_hash.is_empty() { + struct_ser.serialize_field("infoHash", &self.info_hash)?; + } + if !self.name.is_empty() { + struct_ser.serialize_field("name", &self.name)?; + } + if !self.source.is_empty() { + struct_ser.serialize_field("source", &self.source)?; + } + if !self.output_path.is_empty() { + struct_ser.serialize_field("outputPath", &self.output_path)?; + } + if self.total_bytes != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "totalBytes", + ToString::to_string(&self.total_bytes).as_str(), + )?; + } + if self.downloaded_bytes != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "downloadedBytes", + ToString::to_string(&self.downloaded_bytes).as_str(), + )?; + } + if self.state != 0 { + let v = State::try_from(self.state).map_err(|_| { + serde::ser::Error::custom(format!("Invalid variant {}", self.state)) + })?; + struct_ser.serialize_field("state", &v)?; + } + if !self.error_message.is_empty() { + struct_ser.serialize_field("errorMessage", &self.error_message)?; + } + if self.download_speed_bps != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "downloadSpeedBps", + ToString::to_string(&self.download_speed_bps).as_str(), + )?; + } + if self.eta_seconds != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "etaSeconds", + ToString::to_string(&self.eta_seconds).as_str(), + )?; + } + if self.uploaded_bytes != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "uploadedBytes", + ToString::to_string(&self.uploaded_bytes).as_str(), + )?; + } + if self.upload_speed_bps != 0 { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field( + "uploadSpeedBps", + ToString::to_string(&self.upload_speed_bps).as_str(), + )?; + } + if self.peers != 0 { + struct_ser.serialize_field("peers", &self.peers)?; + } + if self.seeds != 0 { + struct_ser.serialize_field("seeds", &self.seeds)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for TorrentStatus { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "id", + "info_hash", + "infoHash", + "name", + "source", + "output_path", + "outputPath", + "total_bytes", + "totalBytes", + "downloaded_bytes", + "downloadedBytes", + "state", + "error_message", + "errorMessage", + "download_speed_bps", + "downloadSpeedBps", + "eta_seconds", + "etaSeconds", + "uploaded_bytes", + "uploadedBytes", + "upload_speed_bps", + "uploadSpeedBps", + "peers", + "seeds", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + InfoHash, + Name, + Source, + OutputPath, + TotalBytes, + DownloadedBytes, + State, + ErrorMessage, + DownloadSpeedBps, + EtaSeconds, + UploadedBytes, + UploadSpeedBps, + Peers, + Seeds, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "id" => Ok(GeneratedField::Id), + "infoHash" | "info_hash" => Ok(GeneratedField::InfoHash), + "name" => Ok(GeneratedField::Name), + "source" => Ok(GeneratedField::Source), + "outputPath" | "output_path" => Ok(GeneratedField::OutputPath), + "totalBytes" | "total_bytes" => Ok(GeneratedField::TotalBytes), + "downloadedBytes" | "downloaded_bytes" => { + Ok(GeneratedField::DownloadedBytes) + } + "state" => Ok(GeneratedField::State), + "errorMessage" | "error_message" => Ok(GeneratedField::ErrorMessage), + "downloadSpeedBps" | "download_speed_bps" => { + Ok(GeneratedField::DownloadSpeedBps) + } + "etaSeconds" | "eta_seconds" => Ok(GeneratedField::EtaSeconds), + "uploadedBytes" | "uploaded_bytes" => Ok(GeneratedField::UploadedBytes), + "uploadSpeedBps" | "upload_speed_bps" => { + Ok(GeneratedField::UploadSpeedBps) + } + "peers" => Ok(GeneratedField::Peers), + "seeds" => Ok(GeneratedField::Seeds), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = TorrentStatus; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct torrent.TorrentStatus") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + let mut info_hash__ = None; + let mut name__ = None; + let mut source__ = None; + let mut output_path__ = None; + let mut total_bytes__ = None; + let mut downloaded_bytes__ = None; + let mut state__ = None; + let mut error_message__ = None; + let mut download_speed_bps__ = None; + let mut eta_seconds__ = None; + let mut uploaded_bytes__ = None; + let mut upload_speed_bps__ = None; + let mut peers__ = None; + let mut seeds__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + GeneratedField::InfoHash => { + if info_hash__.is_some() { + return Err(serde::de::Error::duplicate_field("infoHash")); + } + info_hash__ = Some(map_.next_value()?); + } + GeneratedField::Name => { + if name__.is_some() { + return Err(serde::de::Error::duplicate_field("name")); + } + name__ = Some(map_.next_value()?); + } + GeneratedField::Source => { + if source__.is_some() { + return Err(serde::de::Error::duplicate_field("source")); + } + source__ = Some(map_.next_value()?); + } + GeneratedField::OutputPath => { + if output_path__.is_some() { + return Err(serde::de::Error::duplicate_field("outputPath")); + } + output_path__ = Some(map_.next_value()?); + } + GeneratedField::TotalBytes => { + if total_bytes__.is_some() { + return Err(serde::de::Error::duplicate_field("totalBytes")); + } + total_bytes__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::DownloadedBytes => { + if downloaded_bytes__.is_some() { + return Err(serde::de::Error::duplicate_field("downloadedBytes")); + } + downloaded_bytes__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::State => { + if state__.is_some() { + return Err(serde::de::Error::duplicate_field("state")); + } + state__ = Some(map_.next_value::()? as i32); + } + GeneratedField::ErrorMessage => { + if error_message__.is_some() { + return Err(serde::de::Error::duplicate_field("errorMessage")); + } + error_message__ = Some(map_.next_value()?); + } + GeneratedField::DownloadSpeedBps => { + if download_speed_bps__.is_some() { + return Err(serde::de::Error::duplicate_field("downloadSpeedBps")); + } + download_speed_bps__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::EtaSeconds => { + if eta_seconds__.is_some() { + return Err(serde::de::Error::duplicate_field("etaSeconds")); + } + eta_seconds__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::UploadedBytes => { + if uploaded_bytes__.is_some() { + return Err(serde::de::Error::duplicate_field("uploadedBytes")); + } + uploaded_bytes__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::UploadSpeedBps => { + if upload_speed_bps__.is_some() { + return Err(serde::de::Error::duplicate_field("uploadSpeedBps")); + } + upload_speed_bps__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::Peers => { + if peers__.is_some() { + return Err(serde::de::Error::duplicate_field("peers")); + } + peers__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + GeneratedField::Seeds => { + if seeds__.is_some() { + return Err(serde::de::Error::duplicate_field("seeds")); + } + seeds__ = Some( + map_.next_value::<::pbjson::private::NumberDeserialize<_>>()? + .0, + ); + } + } + } + Ok(TorrentStatus { + id: id__.unwrap_or_default(), + info_hash: info_hash__.unwrap_or_default(), + name: name__.unwrap_or_default(), + source: source__.unwrap_or_default(), + output_path: output_path__.unwrap_or_default(), + total_bytes: total_bytes__.unwrap_or_default(), + downloaded_bytes: downloaded_bytes__.unwrap_or_default(), + state: state__.unwrap_or_default(), + error_message: error_message__.unwrap_or_default(), + download_speed_bps: download_speed_bps__.unwrap_or_default(), + eta_seconds: eta_seconds__.unwrap_or_default(), + uploaded_bytes: uploaded_bytes__.unwrap_or_default(), + upload_speed_bps: upload_speed_bps__.unwrap_or_default(), + peers: peers__.unwrap_or_default(), + seeds: seeds__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("torrent.TorrentStatus", FIELDS, GeneratedVisitor) + } +} diff --git a/src/generated/torrent/torrent.tonic.rs b/src/generated/torrent/torrent.tonic.rs new file mode 100644 index 0000000..2f75817 --- /dev/null +++ b/src/generated/torrent/torrent.tonic.rs @@ -0,0 +1,544 @@ +// @generated +/// Generated client implementations. +pub mod torrents_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::http::Uri; + use tonic::codegen::*; + #[derive(Debug, Clone)] + pub struct TorrentsClient { + inner: tonic::client::Grpc, + } + impl TorrentsClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl TorrentsClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> TorrentsClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + >>::Error: + Into + std::marker::Send + std::marker::Sync, + { + TorrentsClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn add( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Add"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "Add")); + self.inner.unary(req, path, codec).await + } + pub async fn status( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Status"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "Status")); + self.inner.unary(req, path, codec).await + } + pub async fn list( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/List"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "List")); + self.inner.unary(req, path, codec).await + } + pub async fn remove( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Remove"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "Remove")); + self.inner.unary(req, path, codec).await + } + pub async fn pause( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Pause"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "Pause")); + self.inner.unary(req, path, codec).await + } + pub async fn resume( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/torrent.Torrents/Resume"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("torrent.Torrents", "Resume")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod torrents_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with TorrentsServer. + #[async_trait] + pub trait Torrents: std::marker::Send + std::marker::Sync + 'static { + async fn add( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn status( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn list( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn remove( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn pause( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn resume( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct TorrentsServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl TorrentsServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor(inner: T, interceptor: F) -> 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 TorrentsServer + where + T: Torrents, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/torrent.Torrents/Add" => { + #[allow(non_camel_case_types)] + struct AddSvc(pub Arc); + impl tonic::server::UnaryService for AddSvc { + type Response = super::AddResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::add(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AddSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/torrent.Torrents/Status" => { + #[allow(non_camel_case_types)] + struct StatusSvc(pub Arc); + impl tonic::server::UnaryService for StatusSvc { + type Response = super::TorrentStatus; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::status(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = StatusSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/torrent.Torrents/List" => { + #[allow(non_camel_case_types)] + struct ListSvc(pub Arc); + impl tonic::server::UnaryService for ListSvc { + type Response = super::ListResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::list(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/torrent.Torrents/Remove" => { + #[allow(non_camel_case_types)] + struct RemoveSvc(pub Arc); + impl tonic::server::UnaryService for RemoveSvc { + type Response = super::RemoveResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::remove(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RemoveSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/torrent.Torrents/Pause" => { + #[allow(non_camel_case_types)] + struct PauseSvc(pub Arc); + impl tonic::server::UnaryService for PauseSvc { + type Response = super::PauseResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::pause(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = PauseSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/torrent.Torrents/Resume" => { + #[allow(non_camel_case_types)] + struct ResumeSvc(pub Arc); + impl tonic::server::UnaryService for ResumeSvc { + type Response = super::ResumeResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::resume(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ResumeSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => Box::pin(async move { + let mut response = http::Response::new(tonic::body::Body::default()); + let headers = response.headers_mut(); + headers.insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers.insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }), + } + } + } + impl Clone for TorrentsServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "torrent.Torrents"; + impl tonic::server::NamedService for TorrentsServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/src/greeter.rs b/src/greeter.rs new file mode 100644 index 0000000..3432a09 --- /dev/null +++ b/src/greeter.rs @@ -0,0 +1,18 @@ +use crate::generated::hello::{HelloReply, HelloRequest, greeter_server::Greeter}; + +#[derive(Debug, Default)] +pub struct GreeterService; + +#[tonic::async_trait] +impl Greeter for GreeterService { + async fn say_hello( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let name = request.into_inner().name; + let reply = HelloReply { + message: format!("Hello, {}!", name), + }; + Ok(tonic::Response::new(reply)) + } +} diff --git a/src/health.rs b/src/health.rs new file mode 100644 index 0000000..87f2407 --- /dev/null +++ b/src/health.rs @@ -0,0 +1,114 @@ +use std::time::Duration; + +use tonic::transport::Channel; +use tonic_health::pb::{ + HealthCheckRequest as GrpcHealthCheckRequest, HealthCheckResponse as GrpcHealthCheckResponse, + health_check_response::ServingStatus as GrpcServingStatus, health_client::HealthClient, + health_server::Health as GrpcHealth, +}; + +use crate::generated::health::{ + CheckRequest, CheckResponse, ServingStatus, SubserviceStatus, health_server::Health, +}; +use crate::generated::torrent::torrents_server; + +const QUERY_TIMEOUT: Duration = Duration::from_secs(2); +const TORA_SUBSERVICE_NAME: &str = "tora"; + +#[derive(Debug, Clone)] +pub struct HealthService { + tora_channel: Channel, +} + +impl HealthService { + pub fn new(tora_channel: Channel) -> Self { + Self { tora_channel } + } + + async fn probe_tora(&self) -> Result<(), String> { + let mut client = HealthClient::new(self.tora_channel.clone()); + let request = GrpcHealthCheckRequest { + service: String::new(), + }; + + match tokio::time::timeout(QUERY_TIMEOUT, client.check(request)).await { + Ok(Ok(response)) => match GrpcServingStatus::try_from(response.into_inner().status) { + Ok(GrpcServingStatus::Serving) => Ok(()), + Ok(status) => Err(format!("torad reported {}", status.as_str_name())), + Err(_) => Err("torad reported an unknown status".to_string()), + }, + Ok(Err(status)) => Err(format!("torad health check failed: {status}")), + Err(_) => Err("torad health check timed out".to_string()), + } + } +} + +#[tonic::async_trait] +impl GrpcHealth for HealthService { + async fn check( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let status = match request.into_inner().service.as_str() { + "" | torrents_server::SERVICE_NAME => match self.probe_tora().await { + Ok(()) => GrpcServingStatus::Serving, + Err(_) => GrpcServingStatus::NotServing, + }, + _ => return Err(tonic::Status::not_found("unknown service")), + }; + + Ok(tonic::Response::new(GrpcHealthCheckResponse { + status: status as i32, + })) + } + + type WatchStream = std::pin::Pin< + Box< + dyn tonic::codegen::tokio_stream::Stream< + Item = Result, + > + Send, + >, + >; + + async fn watch( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + Err(tonic::Status::unimplemented( + "watch is not supported, use check", + )) + } +} + +#[tonic::async_trait] +impl Health for HealthService { + async fn check( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + let (status, message) = match self.probe_tora().await { + Ok(()) => (ServingStatus::Serving, String::new()), + Err(message) => (ServingStatus::NotServing, message), + }; + + let subservices = vec![SubserviceStatus { + name: TORA_SUBSERVICE_NAME.to_string(), + status: status as i32, + message, + }]; + + let overall = if subservices + .iter() + .all(|s| s.status == ServingStatus::Serving as i32) + { + ServingStatus::Serving + } else { + ServingStatus::NotServing + }; + + Ok(tonic::Response::new(CheckResponse { + status: overall as i32, + subservices, + })) + } +} diff --git a/src/main.rs b/src/main.rs index dc800d7..054664e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,54 @@ -use generated::hello::{ - FILE_DESCRIPTOR_SET, HelloReply, HelloRequest, - greeter_server::{Greeter, GreeterServer}, -}; - +mod config; +mod greeter; +mod health; +mod torrent; mod generated { pub mod hello { include!("generated/hello/hello.rs"); } -} -#[derive(Debug, Default)] -struct GreeterService; + pub mod torrent { + include!("generated/torrent/torrent.rs"); + } -#[tonic::async_trait] -impl Greeter for GreeterService { - async fn say_hello( - &self, - request: tonic::Request, - ) -> Result, tonic::Status> { - let name = request.into_inner().name; - let reply = HelloReply { - message: format!("Hello, {}!", name), - }; - Ok(tonic::Response::new(reply)) + pub mod health { + include!("generated/health/health.rs"); } } +use std::fs; + +use generated::{ + health::health_server::HealthServer as AggregatorHealthServer, + hello::greeter_server::GreeterServer, torrent::torrents_server::TorrentsServer, +}; +use greeter::GreeterService; +use health::HealthService; +use tonic_health::pb::health_server::HealthServer; +use torrent::TorrentsService; + #[tokio::main] async fn main() -> Result<(), Box> { - let addr = "[::1]:50051".parse()?; + let config_str = fs::read_to_string("config.toml").expect("Failed to read file"); + let config: config::Config = toml::from_str(&config_str).expect("Failed to parse TOML"); + let addr = config.service.address.parse()?; let reflection = tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET) + .register_encoded_file_descriptor_set(generated::hello::FILE_DESCRIPTOR_SET) + .register_encoded_file_descriptor_set(generated::torrent::FILE_DESCRIPTOR_SET) + .register_encoded_file_descriptor_set(generated::health::FILE_DESCRIPTOR_SET) + .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) .build_v1()?; + let torrents = TorrentsService::new(&config.torrent.address); + let health = HealthService::new(torrents.channel()); + tonic::transport::Server::builder() .add_service(reflection) + .add_service(HealthServer::new(health.clone())) + .add_service(AggregatorHealthServer::new(health)) .add_service(GreeterServer::new(GreeterService::default())) + .add_service(TorrentsServer::new(torrents)) .serve(addr) .await?; diff --git a/src/torrent.rs b/src/torrent.rs new file mode 100644 index 0000000..fb8396d --- /dev/null +++ b/src/torrent.rs @@ -0,0 +1,77 @@ +use crate::generated::torrent::{torrents_client::TorrentsClient, torrents_server::Torrents, *}; +use tonic::transport::{Channel, Endpoint}; + +#[derive(Debug)] +pub struct TorrentsService { + channel: Channel, +} + +impl TorrentsService { + pub fn new(address: &str) -> Self { + let channel = Endpoint::from_shared(address.to_string()) + .expect("torrent.address should be a valid endpoint") + .connect_lazy(); + Self { channel } + } + + pub fn channel(&self) -> Channel { + self.channel.clone() + } +} + +#[tonic::async_trait] +impl Torrents for TorrentsService { + async fn add( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .add(request.into_inner()) + .await; + } + + async fn status( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .status(request.into_inner()) + .await; + } + + async fn list( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .list(request.into_inner()) + .await; + } + + async fn remove( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .remove(request.into_inner()) + .await; + } + + async fn pause( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .pause(request.into_inner()) + .await; + } + + async fn resume( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + return TorrentsClient::new(self.channel.clone()) + .resume(request.into_inner()) + .await; + } +} diff --git a/tora b/tora new file mode 160000 index 0000000..6ef2b76 --- /dev/null +++ b/tora @@ -0,0 +1 @@ +Subproject commit 6ef2b76977a69b75a31532f2c1e99da4679c3836