rust_cast-0.17.0/.cargo_vcs_info.json0000644000000001360000000000100131300ustar { "git": { "sha1": "b831c4a42a8d88714acadb7b1e0db0fad2c30b6a" }, "path_in_vcs": "" }rust_cast-0.17.0/.gitignore000064400000000000000000000000650072674642500137410ustar 00000000000000.vscode .idea **/*.rs.bk target out *.iml Cargo.lock rust_cast-0.17.0/Cargo.lock0000644000000265460000000000100111200ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "ansi_term" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "docopt" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" dependencies = [ "lazy_static", "regex", "serde", "strsim", ] [[package]] name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", "log", "regex", "termcolor", ] [[package]] name = "fastrand" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ "instant", ] [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "itoa" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] [[package]] name = "memchr" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "once_cell" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "openssl" version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-sys", ] [[package]] name = "openssl-sys" version = "0.9.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" dependencies = [ "autocfg", "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "pkg-config" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "proc-macro2" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "protobuf" version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" [[package]] name = "protobuf-codegen" version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aec1632b7c8f2e620343439a7dfd1f3c47b18906c4be58982079911482b5d707" dependencies = [ "protobuf", ] [[package]] name = "protoc" version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2ef1dc036942fac2470fdb8a911f125404ee9129e9e807f3d12d8589001a38f" dependencies = [ "log", "which", ] [[package]] name = "protoc-rust" version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a9e315121c8e7e21396e940a3d27f92280a6d28e3931213bf6cbfea76c5cc94" dependencies = [ "protobuf", "protobuf-codegen", "protoc", "tempfile", ] [[package]] name = "quote" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "rust_cast" version = "0.17.0" dependencies = [ "ansi_term", "byteorder", "docopt", "env_logger", "log", "openssl", "protobuf", "protoc-rust", "serde", "serde_derive", "serde_json", ] [[package]] name = "ryu" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "serde" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tempfile" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", "fastrand", "libc", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "termcolor" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "which" version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" dependencies = [ "either", "lazy_static", "libc", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" rust_cast-0.17.0/Cargo.toml0000644000000031000000000000100111200ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "rust_cast" version = "0.17.0" authors = ["Aleh Zasypkin "] exclude = [".github/*", "examples/*", "protobuf/*"] description = "Library that allows you to communicate with Google Cast enabled devices (e.g. Chromecast)." homepage = "https://github.com/azasypkin/rust-cast" documentation = "https://azasypkin.github.io/rust-cast/" readme = "README.md" keywords = ["cast", "chromecast", "google"] categories = ["api-bindings", "hardware-support", "multimedia"] license = "MIT" repository = "https://github.com/azasypkin/rust-cast" resolver = "2" [dependencies.byteorder] version = "1.4.3" [dependencies.log] version = "0.4.14" [dependencies.openssl] version = "0.10.38" [dependencies.protobuf] version = "=2.27.1" [dependencies.serde] version = "1.0.136" [dependencies.serde_derive] version = "1.0.136" [dependencies.serde_json] version = "1.0.79" [dev-dependencies.ansi_term] version = "0.12.1" [dev-dependencies.docopt] version = "1.1.1" [dev-dependencies.env_logger] version = "0.9.0" [build-dependencies.protoc-rust] version = "=2.27.1" [features] thread_safe = [] rust_cast-0.17.0/Cargo.toml.orig000064400000000000000000000016170072674642500146440ustar 00000000000000[package] name = "rust_cast" description = "Library that allows you to communicate with Google Cast enabled devices (e.g. Chromecast)." documentation = "https://azasypkin.github.io/rust-cast/" homepage = "https://github.com/azasypkin/rust-cast" repository = "https://github.com/azasypkin/rust-cast" readme = "README.md" license = "MIT" keywords = ["cast", "chromecast", "google"] version = "0.17.0" authors = ["Aleh Zasypkin "] categories = ["api-bindings", "hardware-support", "multimedia"] edition = "2021" exclude = [ ".github/*", "examples/*", "protobuf/*", ] [dependencies] byteorder = "1.4.3" log = "0.4.14" openssl = "0.10.38" protobuf = "=2.27.1" serde = "1.0.136" serde_derive = "1.0.136" serde_json = "1.0.79" [dev-dependencies] ansi_term = "0.12.1" docopt = "1.1.1" env_logger = "0.9.0" [build-dependencies] protoc-rust = "=2.27.1" [features] thread_safe = []rust_cast-0.17.0/LICENSE000064400000000000000000000020550072674642500127570ustar 00000000000000MIT License Copyright (c) 2016 Aleh Zasypkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.rust_cast-0.17.0/README.md000064400000000000000000000074630072674642500132410ustar 00000000000000[![Docs](https://docs.rs/rust_cast/badge.svg)](https://docs.rs/crate/rust_cast/) ![Build Status](https://github.com/azasypkin/rust-cast/actions/workflows/ci.yml/badge.svg) # Usage * [Documentation](https://azasypkin.github.io/rust-cast/) * Try out [Rust Caster](./examples/rust_caster.rs) example to see this crate in action! # Build Proto files are taken from [Chromium Open Screen GitHub mirror](https://chromium.googlesource.com/openscreen/+/8cce349b0a595ddf7178d5730e980ace3a1d1a53/cast/common/channel/proto). By default `cargo build` won't try to generate Rust code from the files located at `protobuf/*`, if you want to do that use `GENERATE_PROTO` environment variable during build and make sure you have `protoc` binary in `$PATH`: ```bash $ GENERATE_PROTO=true cargo build ``` # Run example ## Generic features First, you need to figure out the address of the device to connect to. For example, you can use `avahi` with the following command: ```bash $ avahi-browse -a --resolve ``` ```bash // Get some info about the Google Cast enabled device (e.g. Chromecast). $ cargo run --example rust_caster -- -a 192.168.0.100 -i Number of apps run: 1 App#0: Default Media Receiver (CC1AD845) Volume level: 1 Muted: false // Run specific app on the Chromecast. $ cargo run --example rust_caster -- -a 192.168.0.100 -r youtube // Stop specific active app. $ cargo run --example rust_caster -- -a 192.168.0.100 -s youtube // Stop currently active app. $ cargo run --example rust_caster -- -a 192.168.0.100 --stop-current The following app has been stopped: Default Media Receiver (CC1AD845) ``` ## Media features ```bash // Stream a video. $ cargo run --example rust_caster -- -a 192.168.0.100 -m http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4 // Stream a video of specific format with buffering. $ cargo run --example rust_caster -- -a 192.168.0.100 -m http://xxx.webm --media-type video/webm --media-stream-type buffered // Stream video from YouTube (doesn't work with the latest YouTube app, fix is welcome). $ cargo run --example rust_caster -- -a 192.168.0.100 -m 7LcUOEP7Brc --media-app youtube // Display an image. $ cargo run --example rust_caster -- -a 192.168.0.100 -m https://azasypkin.github.io/style-my-image/images/mozilla.jpg // Change volume level. $ cargo run --example rust_caster -- -a 192.168.0.100 --media-volume 0.5 // Mute/unmute media. $ cargo run --example rust_caster -- -a 192.168.0.100 --media-mute [--media-unmute] // Pause media. $ cargo run --example rust_caster -- -a 192.168.0.100 --media-app youtube --media-pause // Resume/play media. $ cargo run --example rust_caster -- -a 192.168.0.100 --media-app youtube --media-play // Seek media. $ cargo run --example rust_caster -- -a 192.168.0.100 --media-app youtube --media-seek 100 ``` For all possible values of `--media-type` see [Supported Media for Google Cast](https://developers.google.com/cast/docs/media). # DNS TXT Record description * `md` - Model Name (e.g. "Chromecast"); * `id` - UUID without hyphens of the particular device (e.g. xx12x3x456xx789xx01xx234x56789x0); * `fn` - Friendly Name of the device (e.g. "Living Room"); * `rs` - Unknown (recent share???) (e.g. "Youtube TV"); * `bs` - Uknonwn (e.g. "XX1XXX2X3456"); * `st` - Unknown (e.g. "1"); * `ca` - Unknown (e.g. "1234"); * `ic` - Icon path (e.g. "/setup/icon.png"); * `ve` - Version (e.g. "04"). # Model names * `Chromecast` - Regular chromecast, supports video/audio; * `Chromecast Audio` - Chromecast Audio device, supports only audio. # Useful links and sources of inspiration * [DIAL Protocol](http://www.dial-multiscreen.org/); * [An implementation of the Chromecast CASTV2 protocol in JS](https://github.com/thibauts/node-castv2); * [Chromecast - steps closer to a python native api](http://www.clift.org/fred/chromecast-steps-closer-to-a-python-native-api.html); rust_cast-0.17.0/build.rs000064400000000000000000000012220072674642500134120ustar 00000000000000use std::env; extern crate protoc_rust; fn main() { let generate_proto = env::var("GENERATE_PROTO").unwrap_or_else(|_| "false".to_string()); if generate_proto == "true" { protoc_rust::Codegen::new() .out_dir("src/cast") .inputs(&[ "protobuf/authority_keys.proto", "protobuf/cast_channel.proto", ]) .includes(&["protobuf"]) .run() .expect("protoc"); } println!("rerun-if-env-changed=GENERATE_PROTO"); println!("rerun-if-changed=protobuf/authority_keys.proto"); println!("rerun-if-changed=protobuf/cast_channel.proto"); } rust_cast-0.17.0/src/cast/authority_keys.rs000064400000000000000000000254660072674642500171370ustar 00000000000000// This file is generated by rust-protobuf 2.27.1. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 #![allow(unknown_lints)] #![allow(clippy::all)] #![allow(unused_attributes)] #![cfg_attr(rustfmt, rustfmt::skip)] #![allow(box_pointers)] #![allow(dead_code)] #![allow(missing_docs)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![allow(trivial_casts)] #![allow(unused_imports)] #![allow(unused_results)] //! Generated file from `authority_keys.proto` /// Generated files are compatible only with the same version /// of protobuf runtime. // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_27_1; #[derive(PartialEq,Clone,Default,Debug)] pub struct AuthorityKeys { // message fields pub keys: ::protobuf::RepeatedField, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a AuthorityKeys { fn default() -> &'a AuthorityKeys { ::default_instance() } } impl AuthorityKeys { pub fn new() -> AuthorityKeys { ::std::default::Default::default() } // repeated .cast.channel.AuthorityKeys.Key keys = 1; pub fn get_keys(&self) -> &[AuthorityKeys_Key] { &self.keys } pub fn clear_keys(&mut self) { self.keys.clear(); } // Param is passed by value, moved pub fn set_keys(&mut self, v: ::protobuf::RepeatedField) { self.keys = v; } // Mutable pointer to the field. pub fn mut_keys(&mut self) -> &mut ::protobuf::RepeatedField { &mut self.keys } // Take field pub fn take_keys(&mut self) -> ::protobuf::RepeatedField { ::std::mem::replace(&mut self.keys, ::protobuf::RepeatedField::new()) } } impl ::protobuf::Message for AuthorityKeys { fn is_initialized(&self) -> bool { for v in &self.keys { if !v.is_initialized() { return false; } }; true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.keys)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; for value in &self.keys { let len = value.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; }; my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.keys { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; }; os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> AuthorityKeys { AuthorityKeys::new() } fn default_instance() -> &'static AuthorityKeys { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(AuthorityKeys::new) } } impl ::protobuf::Clear for AuthorityKeys { fn clear(&mut self) { self.keys.clear(); self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for AuthorityKeys { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default,Debug)] pub struct AuthorityKeys_Key { // message fields fingerprint: ::protobuf::SingularField<::std::vec::Vec>, public_key: ::protobuf::SingularField<::std::vec::Vec>, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a AuthorityKeys_Key { fn default() -> &'a AuthorityKeys_Key { ::default_instance() } } impl AuthorityKeys_Key { pub fn new() -> AuthorityKeys_Key { ::std::default::Default::default() } // required bytes fingerprint = 1; pub fn get_fingerprint(&self) -> &[u8] { match self.fingerprint.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_fingerprint(&mut self) { self.fingerprint.clear(); } pub fn has_fingerprint(&self) -> bool { self.fingerprint.is_some() } // Param is passed by value, moved pub fn set_fingerprint(&mut self, v: ::std::vec::Vec) { self.fingerprint = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_fingerprint(&mut self) -> &mut ::std::vec::Vec { if self.fingerprint.is_none() { self.fingerprint.set_default(); } self.fingerprint.as_mut().unwrap() } // Take field pub fn take_fingerprint(&mut self) -> ::std::vec::Vec { self.fingerprint.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // required bytes public_key = 2; pub fn get_public_key(&self) -> &[u8] { match self.public_key.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_public_key(&mut self) { self.public_key.clear(); } pub fn has_public_key(&self) -> bool { self.public_key.is_some() } // Param is passed by value, moved pub fn set_public_key(&mut self, v: ::std::vec::Vec) { self.public_key = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_public_key(&mut self) -> &mut ::std::vec::Vec { if self.public_key.is_none() { self.public_key.set_default(); } self.public_key.as_mut().unwrap() } // Take field pub fn take_public_key(&mut self) -> ::std::vec::Vec { self.public_key.take().unwrap_or_else(|| ::std::vec::Vec::new()) } } impl ::protobuf::Message for AuthorityKeys_Key { fn is_initialized(&self) -> bool { if self.fingerprint.is_none() { return false; } if self.public_key.is_none() { return false; } true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.fingerprint)?; }, 2 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.public_key)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(ref v) = self.fingerprint.as_ref() { my_size += ::protobuf::rt::bytes_size(1, &v); } if let Some(ref v) = self.public_key.as_ref() { my_size += ::protobuf::rt::bytes_size(2, &v); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.fingerprint.as_ref() { os.write_bytes(1, &v)?; } if let Some(ref v) = self.public_key.as_ref() { os.write_bytes(2, &v)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> AuthorityKeys_Key { AuthorityKeys_Key::new() } fn default_instance() -> &'static AuthorityKeys_Key { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(AuthorityKeys_Key::new) } } impl ::protobuf::Clear for AuthorityKeys_Key { fn clear(&mut self) { self.fingerprint.clear(); self.public_key.clear(); self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for AuthorityKeys_Key { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } rust_cast-0.17.0/src/cast/cast_channel.rs000064400000000000000000001524770072674642500165010ustar 00000000000000// This file is generated by rust-protobuf 2.27.1. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 #![allow(unknown_lints)] #![allow(clippy::all)] #![allow(unused_attributes)] #![cfg_attr(rustfmt, rustfmt::skip)] #![allow(box_pointers)] #![allow(dead_code)] #![allow(missing_docs)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![allow(trivial_casts)] #![allow(unused_imports)] #![allow(unused_results)] //! Generated file from `cast_channel.proto` /// Generated files are compatible only with the same version /// of protobuf runtime. // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_27_1; #[derive(PartialEq,Clone,Default,Debug)] pub struct CastMessage { // message fields protocol_version: ::std::option::Option, source_id: ::protobuf::SingularField<::std::string::String>, destination_id: ::protobuf::SingularField<::std::string::String>, namespace: ::protobuf::SingularField<::std::string::String>, payload_type: ::std::option::Option, payload_utf8: ::protobuf::SingularField<::std::string::String>, payload_binary: ::protobuf::SingularField<::std::vec::Vec>, continued: ::std::option::Option, remaining_length: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a CastMessage { fn default() -> &'a CastMessage { ::default_instance() } } impl CastMessage { pub fn new() -> CastMessage { ::std::default::Default::default() } // required .cast.channel.CastMessage.ProtocolVersion protocol_version = 1; pub fn get_protocol_version(&self) -> CastMessage_ProtocolVersion { self.protocol_version.unwrap_or(CastMessage_ProtocolVersion::CASTV2_1_0) } pub fn clear_protocol_version(&mut self) { self.protocol_version = ::std::option::Option::None; } pub fn has_protocol_version(&self) -> bool { self.protocol_version.is_some() } // Param is passed by value, moved pub fn set_protocol_version(&mut self, v: CastMessage_ProtocolVersion) { self.protocol_version = ::std::option::Option::Some(v); } // required string source_id = 2; pub fn get_source_id(&self) -> &str { match self.source_id.as_ref() { Some(v) => &v, None => "", } } pub fn clear_source_id(&mut self) { self.source_id.clear(); } pub fn has_source_id(&self) -> bool { self.source_id.is_some() } // Param is passed by value, moved pub fn set_source_id(&mut self, v: ::std::string::String) { self.source_id = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_source_id(&mut self) -> &mut ::std::string::String { if self.source_id.is_none() { self.source_id.set_default(); } self.source_id.as_mut().unwrap() } // Take field pub fn take_source_id(&mut self) -> ::std::string::String { self.source_id.take().unwrap_or_else(|| ::std::string::String::new()) } // required string destination_id = 3; pub fn get_destination_id(&self) -> &str { match self.destination_id.as_ref() { Some(v) => &v, None => "", } } pub fn clear_destination_id(&mut self) { self.destination_id.clear(); } pub fn has_destination_id(&self) -> bool { self.destination_id.is_some() } // Param is passed by value, moved pub fn set_destination_id(&mut self, v: ::std::string::String) { self.destination_id = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_destination_id(&mut self) -> &mut ::std::string::String { if self.destination_id.is_none() { self.destination_id.set_default(); } self.destination_id.as_mut().unwrap() } // Take field pub fn take_destination_id(&mut self) -> ::std::string::String { self.destination_id.take().unwrap_or_else(|| ::std::string::String::new()) } // required string namespace = 4; pub fn get_namespace(&self) -> &str { match self.namespace.as_ref() { Some(v) => &v, None => "", } } pub fn clear_namespace(&mut self) { self.namespace.clear(); } pub fn has_namespace(&self) -> bool { self.namespace.is_some() } // Param is passed by value, moved pub fn set_namespace(&mut self, v: ::std::string::String) { self.namespace = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_namespace(&mut self) -> &mut ::std::string::String { if self.namespace.is_none() { self.namespace.set_default(); } self.namespace.as_mut().unwrap() } // Take field pub fn take_namespace(&mut self) -> ::std::string::String { self.namespace.take().unwrap_or_else(|| ::std::string::String::new()) } // required .cast.channel.CastMessage.PayloadType payload_type = 5; pub fn get_payload_type(&self) -> CastMessage_PayloadType { self.payload_type.unwrap_or(CastMessage_PayloadType::STRING) } pub fn clear_payload_type(&mut self) { self.payload_type = ::std::option::Option::None; } pub fn has_payload_type(&self) -> bool { self.payload_type.is_some() } // Param is passed by value, moved pub fn set_payload_type(&mut self, v: CastMessage_PayloadType) { self.payload_type = ::std::option::Option::Some(v); } // optional string payload_utf8 = 6; pub fn get_payload_utf8(&self) -> &str { match self.payload_utf8.as_ref() { Some(v) => &v, None => "", } } pub fn clear_payload_utf8(&mut self) { self.payload_utf8.clear(); } pub fn has_payload_utf8(&self) -> bool { self.payload_utf8.is_some() } // Param is passed by value, moved pub fn set_payload_utf8(&mut self, v: ::std::string::String) { self.payload_utf8 = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_payload_utf8(&mut self) -> &mut ::std::string::String { if self.payload_utf8.is_none() { self.payload_utf8.set_default(); } self.payload_utf8.as_mut().unwrap() } // Take field pub fn take_payload_utf8(&mut self) -> ::std::string::String { self.payload_utf8.take().unwrap_or_else(|| ::std::string::String::new()) } // optional bytes payload_binary = 7; pub fn get_payload_binary(&self) -> &[u8] { match self.payload_binary.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_payload_binary(&mut self) { self.payload_binary.clear(); } pub fn has_payload_binary(&self) -> bool { self.payload_binary.is_some() } // Param is passed by value, moved pub fn set_payload_binary(&mut self, v: ::std::vec::Vec) { self.payload_binary = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_payload_binary(&mut self) -> &mut ::std::vec::Vec { if self.payload_binary.is_none() { self.payload_binary.set_default(); } self.payload_binary.as_mut().unwrap() } // Take field pub fn take_payload_binary(&mut self) -> ::std::vec::Vec { self.payload_binary.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // optional bool continued = 8; pub fn get_continued(&self) -> bool { self.continued.unwrap_or(false) } pub fn clear_continued(&mut self) { self.continued = ::std::option::Option::None; } pub fn has_continued(&self) -> bool { self.continued.is_some() } // Param is passed by value, moved pub fn set_continued(&mut self, v: bool) { self.continued = ::std::option::Option::Some(v); } // optional uint32 remaining_length = 9; pub fn get_remaining_length(&self) -> u32 { self.remaining_length.unwrap_or(0) } pub fn clear_remaining_length(&mut self) { self.remaining_length = ::std::option::Option::None; } pub fn has_remaining_length(&self) -> bool { self.remaining_length.is_some() } // Param is passed by value, moved pub fn set_remaining_length(&mut self, v: u32) { self.remaining_length = ::std::option::Option::Some(v); } } impl ::protobuf::Message for CastMessage { fn is_initialized(&self) -> bool { if self.protocol_version.is_none() { return false; } if self.source_id.is_none() { return false; } if self.destination_id.is_none() { return false; } if self.namespace.is_none() { return false; } if self.payload_type.is_none() { return false; } true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.protocol_version, 1, &mut self.unknown_fields)? }, 2 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.source_id)?; }, 3 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.destination_id)?; }, 4 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.namespace)?; }, 5 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.payload_type, 5, &mut self.unknown_fields)? }, 6 => { ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.payload_utf8)?; }, 7 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.payload_binary)?; }, 8 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } let tmp = is.read_bool()?; self.continued = ::std::option::Option::Some(tmp); }, 9 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } let tmp = is.read_uint32()?; self.remaining_length = ::std::option::Option::Some(tmp); }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(v) = self.protocol_version { my_size += ::protobuf::rt::enum_size(1, v); } if let Some(ref v) = self.source_id.as_ref() { my_size += ::protobuf::rt::string_size(2, &v); } if let Some(ref v) = self.destination_id.as_ref() { my_size += ::protobuf::rt::string_size(3, &v); } if let Some(ref v) = self.namespace.as_ref() { my_size += ::protobuf::rt::string_size(4, &v); } if let Some(v) = self.payload_type { my_size += ::protobuf::rt::enum_size(5, v); } if let Some(ref v) = self.payload_utf8.as_ref() { my_size += ::protobuf::rt::string_size(6, &v); } if let Some(ref v) = self.payload_binary.as_ref() { my_size += ::protobuf::rt::bytes_size(7, &v); } if let Some(v) = self.continued { my_size += 2; } if let Some(v) = self.remaining_length { my_size += ::protobuf::rt::value_size(9, v, ::protobuf::wire_format::WireTypeVarint); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.protocol_version { os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?; } if let Some(ref v) = self.source_id.as_ref() { os.write_string(2, &v)?; } if let Some(ref v) = self.destination_id.as_ref() { os.write_string(3, &v)?; } if let Some(ref v) = self.namespace.as_ref() { os.write_string(4, &v)?; } if let Some(v) = self.payload_type { os.write_enum(5, ::protobuf::ProtobufEnum::value(&v))?; } if let Some(ref v) = self.payload_utf8.as_ref() { os.write_string(6, &v)?; } if let Some(ref v) = self.payload_binary.as_ref() { os.write_bytes(7, &v)?; } if let Some(v) = self.continued { os.write_bool(8, v)?; } if let Some(v) = self.remaining_length { os.write_uint32(9, v)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> CastMessage { CastMessage::new() } fn default_instance() -> &'static CastMessage { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(CastMessage::new) } } impl ::protobuf::Clear for CastMessage { fn clear(&mut self) { self.protocol_version = ::std::option::Option::None; self.source_id.clear(); self.destination_id.clear(); self.namespace.clear(); self.payload_type = ::std::option::Option::None; self.payload_utf8.clear(); self.payload_binary.clear(); self.continued = ::std::option::Option::None; self.remaining_length = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for CastMessage { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum CastMessage_ProtocolVersion { CASTV2_1_0 = 0, CASTV2_1_1 = 1, CASTV2_1_2 = 2, CASTV2_1_3 = 3, } impl ::protobuf::ProtobufEnum for CastMessage_ProtocolVersion { fn value(&self) -> i32 { *self as i32 } fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(CastMessage_ProtocolVersion::CASTV2_1_0), 1 => ::std::option::Option::Some(CastMessage_ProtocolVersion::CASTV2_1_1), 2 => ::std::option::Option::Some(CastMessage_ProtocolVersion::CASTV2_1_2), 3 => ::std::option::Option::Some(CastMessage_ProtocolVersion::CASTV2_1_3), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [CastMessage_ProtocolVersion] = &[ CastMessage_ProtocolVersion::CASTV2_1_0, CastMessage_ProtocolVersion::CASTV2_1_1, CastMessage_ProtocolVersion::CASTV2_1_2, CastMessage_ProtocolVersion::CASTV2_1_3, ]; values } } impl ::std::marker::Copy for CastMessage_ProtocolVersion { } impl ::std::default::Default for CastMessage_ProtocolVersion { fn default() -> Self { CastMessage_ProtocolVersion::CASTV2_1_0 } } impl ::protobuf::reflect::ProtobufValue for CastMessage_ProtocolVersion { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) } } #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum CastMessage_PayloadType { STRING = 0, BINARY = 1, } impl ::protobuf::ProtobufEnum for CastMessage_PayloadType { fn value(&self) -> i32 { *self as i32 } fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(CastMessage_PayloadType::STRING), 1 => ::std::option::Option::Some(CastMessage_PayloadType::BINARY), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [CastMessage_PayloadType] = &[ CastMessage_PayloadType::STRING, CastMessage_PayloadType::BINARY, ]; values } } impl ::std::marker::Copy for CastMessage_PayloadType { } impl ::std::default::Default for CastMessage_PayloadType { fn default() -> Self { CastMessage_PayloadType::STRING } } impl ::protobuf::reflect::ProtobufValue for CastMessage_PayloadType { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) } } #[derive(PartialEq,Clone,Default,Debug)] pub struct AuthChallenge { // message fields signature_algorithm: ::std::option::Option, sender_nonce: ::protobuf::SingularField<::std::vec::Vec>, hash_algorithm: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a AuthChallenge { fn default() -> &'a AuthChallenge { ::default_instance() } } impl AuthChallenge { pub fn new() -> AuthChallenge { ::std::default::Default::default() } // optional .cast.channel.SignatureAlgorithm signature_algorithm = 1; pub fn get_signature_algorithm(&self) -> SignatureAlgorithm { self.signature_algorithm.unwrap_or(SignatureAlgorithm::RSASSA_PKCS1v15) } pub fn clear_signature_algorithm(&mut self) { self.signature_algorithm = ::std::option::Option::None; } pub fn has_signature_algorithm(&self) -> bool { self.signature_algorithm.is_some() } // Param is passed by value, moved pub fn set_signature_algorithm(&mut self, v: SignatureAlgorithm) { self.signature_algorithm = ::std::option::Option::Some(v); } // optional bytes sender_nonce = 2; pub fn get_sender_nonce(&self) -> &[u8] { match self.sender_nonce.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_sender_nonce(&mut self) { self.sender_nonce.clear(); } pub fn has_sender_nonce(&self) -> bool { self.sender_nonce.is_some() } // Param is passed by value, moved pub fn set_sender_nonce(&mut self, v: ::std::vec::Vec) { self.sender_nonce = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_sender_nonce(&mut self) -> &mut ::std::vec::Vec { if self.sender_nonce.is_none() { self.sender_nonce.set_default(); } self.sender_nonce.as_mut().unwrap() } // Take field pub fn take_sender_nonce(&mut self) -> ::std::vec::Vec { self.sender_nonce.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // optional .cast.channel.HashAlgorithm hash_algorithm = 3; pub fn get_hash_algorithm(&self) -> HashAlgorithm { self.hash_algorithm.unwrap_or(HashAlgorithm::SHA1) } pub fn clear_hash_algorithm(&mut self) { self.hash_algorithm = ::std::option::Option::None; } pub fn has_hash_algorithm(&self) -> bool { self.hash_algorithm.is_some() } // Param is passed by value, moved pub fn set_hash_algorithm(&mut self, v: HashAlgorithm) { self.hash_algorithm = ::std::option::Option::Some(v); } } impl ::protobuf::Message for AuthChallenge { fn is_initialized(&self) -> bool { true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.signature_algorithm, 1, &mut self.unknown_fields)? }, 2 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.sender_nonce)?; }, 3 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.hash_algorithm, 3, &mut self.unknown_fields)? }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(v) = self.signature_algorithm { my_size += ::protobuf::rt::enum_size(1, v); } if let Some(ref v) = self.sender_nonce.as_ref() { my_size += ::protobuf::rt::bytes_size(2, &v); } if let Some(v) = self.hash_algorithm { my_size += ::protobuf::rt::enum_size(3, v); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.signature_algorithm { os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?; } if let Some(ref v) = self.sender_nonce.as_ref() { os.write_bytes(2, &v)?; } if let Some(v) = self.hash_algorithm { os.write_enum(3, ::protobuf::ProtobufEnum::value(&v))?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> AuthChallenge { AuthChallenge::new() } fn default_instance() -> &'static AuthChallenge { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(AuthChallenge::new) } } impl ::protobuf::Clear for AuthChallenge { fn clear(&mut self) { self.signature_algorithm = ::std::option::Option::None; self.sender_nonce.clear(); self.hash_algorithm = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for AuthChallenge { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default,Debug)] pub struct AuthResponse { // message fields signature: ::protobuf::SingularField<::std::vec::Vec>, client_auth_certificate: ::protobuf::SingularField<::std::vec::Vec>, pub intermediate_certificate: ::protobuf::RepeatedField<::std::vec::Vec>, signature_algorithm: ::std::option::Option, sender_nonce: ::protobuf::SingularField<::std::vec::Vec>, hash_algorithm: ::std::option::Option, crl: ::protobuf::SingularField<::std::vec::Vec>, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a AuthResponse { fn default() -> &'a AuthResponse { ::default_instance() } } impl AuthResponse { pub fn new() -> AuthResponse { ::std::default::Default::default() } // required bytes signature = 1; pub fn get_signature(&self) -> &[u8] { match self.signature.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_signature(&mut self) { self.signature.clear(); } pub fn has_signature(&self) -> bool { self.signature.is_some() } // Param is passed by value, moved pub fn set_signature(&mut self, v: ::std::vec::Vec) { self.signature = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_signature(&mut self) -> &mut ::std::vec::Vec { if self.signature.is_none() { self.signature.set_default(); } self.signature.as_mut().unwrap() } // Take field pub fn take_signature(&mut self) -> ::std::vec::Vec { self.signature.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // required bytes client_auth_certificate = 2; pub fn get_client_auth_certificate(&self) -> &[u8] { match self.client_auth_certificate.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_client_auth_certificate(&mut self) { self.client_auth_certificate.clear(); } pub fn has_client_auth_certificate(&self) -> bool { self.client_auth_certificate.is_some() } // Param is passed by value, moved pub fn set_client_auth_certificate(&mut self, v: ::std::vec::Vec) { self.client_auth_certificate = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_client_auth_certificate(&mut self) -> &mut ::std::vec::Vec { if self.client_auth_certificate.is_none() { self.client_auth_certificate.set_default(); } self.client_auth_certificate.as_mut().unwrap() } // Take field pub fn take_client_auth_certificate(&mut self) -> ::std::vec::Vec { self.client_auth_certificate.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // repeated bytes intermediate_certificate = 3; pub fn get_intermediate_certificate(&self) -> &[::std::vec::Vec] { &self.intermediate_certificate } pub fn clear_intermediate_certificate(&mut self) { self.intermediate_certificate.clear(); } // Param is passed by value, moved pub fn set_intermediate_certificate(&mut self, v: ::protobuf::RepeatedField<::std::vec::Vec>) { self.intermediate_certificate = v; } // Mutable pointer to the field. pub fn mut_intermediate_certificate(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { &mut self.intermediate_certificate } // Take field pub fn take_intermediate_certificate(&mut self) -> ::protobuf::RepeatedField<::std::vec::Vec> { ::std::mem::replace(&mut self.intermediate_certificate, ::protobuf::RepeatedField::new()) } // optional .cast.channel.SignatureAlgorithm signature_algorithm = 4; pub fn get_signature_algorithm(&self) -> SignatureAlgorithm { self.signature_algorithm.unwrap_or(SignatureAlgorithm::RSASSA_PKCS1v15) } pub fn clear_signature_algorithm(&mut self) { self.signature_algorithm = ::std::option::Option::None; } pub fn has_signature_algorithm(&self) -> bool { self.signature_algorithm.is_some() } // Param is passed by value, moved pub fn set_signature_algorithm(&mut self, v: SignatureAlgorithm) { self.signature_algorithm = ::std::option::Option::Some(v); } // optional bytes sender_nonce = 5; pub fn get_sender_nonce(&self) -> &[u8] { match self.sender_nonce.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_sender_nonce(&mut self) { self.sender_nonce.clear(); } pub fn has_sender_nonce(&self) -> bool { self.sender_nonce.is_some() } // Param is passed by value, moved pub fn set_sender_nonce(&mut self, v: ::std::vec::Vec) { self.sender_nonce = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_sender_nonce(&mut self) -> &mut ::std::vec::Vec { if self.sender_nonce.is_none() { self.sender_nonce.set_default(); } self.sender_nonce.as_mut().unwrap() } // Take field pub fn take_sender_nonce(&mut self) -> ::std::vec::Vec { self.sender_nonce.take().unwrap_or_else(|| ::std::vec::Vec::new()) } // optional .cast.channel.HashAlgorithm hash_algorithm = 6; pub fn get_hash_algorithm(&self) -> HashAlgorithm { self.hash_algorithm.unwrap_or(HashAlgorithm::SHA1) } pub fn clear_hash_algorithm(&mut self) { self.hash_algorithm = ::std::option::Option::None; } pub fn has_hash_algorithm(&self) -> bool { self.hash_algorithm.is_some() } // Param is passed by value, moved pub fn set_hash_algorithm(&mut self, v: HashAlgorithm) { self.hash_algorithm = ::std::option::Option::Some(v); } // optional bytes crl = 7; pub fn get_crl(&self) -> &[u8] { match self.crl.as_ref() { Some(v) => &v, None => &[], } } pub fn clear_crl(&mut self) { self.crl.clear(); } pub fn has_crl(&self) -> bool { self.crl.is_some() } // Param is passed by value, moved pub fn set_crl(&mut self, v: ::std::vec::Vec) { self.crl = ::protobuf::SingularField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_crl(&mut self) -> &mut ::std::vec::Vec { if self.crl.is_none() { self.crl.set_default(); } self.crl.as_mut().unwrap() } // Take field pub fn take_crl(&mut self) -> ::std::vec::Vec { self.crl.take().unwrap_or_else(|| ::std::vec::Vec::new()) } } impl ::protobuf::Message for AuthResponse { fn is_initialized(&self) -> bool { if self.signature.is_none() { return false; } if self.client_auth_certificate.is_none() { return false; } true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.signature)?; }, 2 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.client_auth_certificate)?; }, 3 => { ::protobuf::rt::read_repeated_bytes_into(wire_type, is, &mut self.intermediate_certificate)?; }, 4 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.signature_algorithm, 4, &mut self.unknown_fields)? }, 5 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.sender_nonce)?; }, 6 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.hash_algorithm, 6, &mut self.unknown_fields)? }, 7 => { ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.crl)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(ref v) = self.signature.as_ref() { my_size += ::protobuf::rt::bytes_size(1, &v); } if let Some(ref v) = self.client_auth_certificate.as_ref() { my_size += ::protobuf::rt::bytes_size(2, &v); } for value in &self.intermediate_certificate { my_size += ::protobuf::rt::bytes_size(3, &value); }; if let Some(v) = self.signature_algorithm { my_size += ::protobuf::rt::enum_size(4, v); } if let Some(ref v) = self.sender_nonce.as_ref() { my_size += ::protobuf::rt::bytes_size(5, &v); } if let Some(v) = self.hash_algorithm { my_size += ::protobuf::rt::enum_size(6, v); } if let Some(ref v) = self.crl.as_ref() { my_size += ::protobuf::rt::bytes_size(7, &v); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.signature.as_ref() { os.write_bytes(1, &v)?; } if let Some(ref v) = self.client_auth_certificate.as_ref() { os.write_bytes(2, &v)?; } for v in &self.intermediate_certificate { os.write_bytes(3, &v)?; }; if let Some(v) = self.signature_algorithm { os.write_enum(4, ::protobuf::ProtobufEnum::value(&v))?; } if let Some(ref v) = self.sender_nonce.as_ref() { os.write_bytes(5, &v)?; } if let Some(v) = self.hash_algorithm { os.write_enum(6, ::protobuf::ProtobufEnum::value(&v))?; } if let Some(ref v) = self.crl.as_ref() { os.write_bytes(7, &v)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> AuthResponse { AuthResponse::new() } fn default_instance() -> &'static AuthResponse { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(AuthResponse::new) } } impl ::protobuf::Clear for AuthResponse { fn clear(&mut self) { self.signature.clear(); self.client_auth_certificate.clear(); self.intermediate_certificate.clear(); self.signature_algorithm = ::std::option::Option::None; self.sender_nonce.clear(); self.hash_algorithm = ::std::option::Option::None; self.crl.clear(); self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for AuthResponse { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default,Debug)] pub struct AuthError { // message fields error_type: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a AuthError { fn default() -> &'a AuthError { ::default_instance() } } impl AuthError { pub fn new() -> AuthError { ::std::default::Default::default() } // required .cast.channel.AuthError.ErrorType error_type = 1; pub fn get_error_type(&self) -> AuthError_ErrorType { self.error_type.unwrap_or(AuthError_ErrorType::INTERNAL_ERROR) } pub fn clear_error_type(&mut self) { self.error_type = ::std::option::Option::None; } pub fn has_error_type(&self) -> bool { self.error_type.is_some() } // Param is passed by value, moved pub fn set_error_type(&mut self, v: AuthError_ErrorType) { self.error_type = ::std::option::Option::Some(v); } } impl ::protobuf::Message for AuthError { fn is_initialized(&self) -> bool { if self.error_type.is_none() { return false; } true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.error_type, 1, &mut self.unknown_fields)? }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(v) = self.error_type { my_size += ::protobuf::rt::enum_size(1, v); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.error_type { os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> AuthError { AuthError::new() } fn default_instance() -> &'static AuthError { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(AuthError::new) } } impl ::protobuf::Clear for AuthError { fn clear(&mut self) { self.error_type = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for AuthError { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum AuthError_ErrorType { INTERNAL_ERROR = 0, NO_TLS = 1, SIGNATURE_ALGORITHM_UNAVAILABLE = 2, } impl ::protobuf::ProtobufEnum for AuthError_ErrorType { fn value(&self) -> i32 { *self as i32 } fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(AuthError_ErrorType::INTERNAL_ERROR), 1 => ::std::option::Option::Some(AuthError_ErrorType::NO_TLS), 2 => ::std::option::Option::Some(AuthError_ErrorType::SIGNATURE_ALGORITHM_UNAVAILABLE), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [AuthError_ErrorType] = &[ AuthError_ErrorType::INTERNAL_ERROR, AuthError_ErrorType::NO_TLS, AuthError_ErrorType::SIGNATURE_ALGORITHM_UNAVAILABLE, ]; values } } impl ::std::marker::Copy for AuthError_ErrorType { } impl ::std::default::Default for AuthError_ErrorType { fn default() -> Self { AuthError_ErrorType::INTERNAL_ERROR } } impl ::protobuf::reflect::ProtobufValue for AuthError_ErrorType { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) } } #[derive(PartialEq,Clone,Default,Debug)] pub struct DeviceAuthMessage { // message fields pub challenge: ::protobuf::SingularPtrField, pub response: ::protobuf::SingularPtrField, pub error: ::protobuf::SingularPtrField, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } impl<'a> ::std::default::Default for &'a DeviceAuthMessage { fn default() -> &'a DeviceAuthMessage { ::default_instance() } } impl DeviceAuthMessage { pub fn new() -> DeviceAuthMessage { ::std::default::Default::default() } // optional .cast.channel.AuthChallenge challenge = 1; pub fn get_challenge(&self) -> &AuthChallenge { self.challenge.as_ref().unwrap_or_else(|| ::default_instance()) } pub fn clear_challenge(&mut self) { self.challenge.clear(); } pub fn has_challenge(&self) -> bool { self.challenge.is_some() } // Param is passed by value, moved pub fn set_challenge(&mut self, v: AuthChallenge) { self.challenge = ::protobuf::SingularPtrField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_challenge(&mut self) -> &mut AuthChallenge { if self.challenge.is_none() { self.challenge.set_default(); } self.challenge.as_mut().unwrap() } // Take field pub fn take_challenge(&mut self) -> AuthChallenge { self.challenge.take().unwrap_or_else(|| AuthChallenge::new()) } // optional .cast.channel.AuthResponse response = 2; pub fn get_response(&self) -> &AuthResponse { self.response.as_ref().unwrap_or_else(|| ::default_instance()) } pub fn clear_response(&mut self) { self.response.clear(); } pub fn has_response(&self) -> bool { self.response.is_some() } // Param is passed by value, moved pub fn set_response(&mut self, v: AuthResponse) { self.response = ::protobuf::SingularPtrField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_response(&mut self) -> &mut AuthResponse { if self.response.is_none() { self.response.set_default(); } self.response.as_mut().unwrap() } // Take field pub fn take_response(&mut self) -> AuthResponse { self.response.take().unwrap_or_else(|| AuthResponse::new()) } // optional .cast.channel.AuthError error = 3; pub fn get_error(&self) -> &AuthError { self.error.as_ref().unwrap_or_else(|| ::default_instance()) } pub fn clear_error(&mut self) { self.error.clear(); } pub fn has_error(&self) -> bool { self.error.is_some() } // Param is passed by value, moved pub fn set_error(&mut self, v: AuthError) { self.error = ::protobuf::SingularPtrField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. pub fn mut_error(&mut self) -> &mut AuthError { if self.error.is_none() { self.error.set_default(); } self.error.as_mut().unwrap() } // Take field pub fn take_error(&mut self) -> AuthError { self.error.take().unwrap_or_else(|| AuthError::new()) } } impl ::protobuf::Message for DeviceAuthMessage { fn is_initialized(&self) -> bool { for v in &self.challenge { if !v.is_initialized() { return false; } }; for v in &self.response { if !v.is_initialized() { return false; } }; for v in &self.error { if !v.is_initialized() { return false; } }; true } fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.challenge)?; }, 2 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.response)?; }, 3 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.error)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, }; } ::std::result::Result::Ok(()) } // Compute sizes of nested messages #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; if let Some(ref v) = self.challenge.as_ref() { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } if let Some(ref v) = self.response.as_ref() { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } if let Some(ref v) = self.error.as_ref() { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(ref v) = self.challenge.as_ref() { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } if let Some(ref v) = self.response.as_ref() { os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } if let Some(ref v) = self.error.as_ref() { os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } fn get_cached_size(&self) -> u32 { self.cached_size.get() } fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { &self.unknown_fields } fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { &mut self.unknown_fields } fn as_any(&self) -> &dyn (::std::any::Any) { self as &dyn (::std::any::Any) } fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { self as &mut dyn (::std::any::Any) } fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { Self::descriptor_static() } fn new() -> DeviceAuthMessage { DeviceAuthMessage::new() } fn default_instance() -> &'static DeviceAuthMessage { static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; instance.get(DeviceAuthMessage::new) } } impl ::protobuf::Clear for DeviceAuthMessage { fn clear(&mut self) { self.challenge.clear(); self.response.clear(); self.error.clear(); self.unknown_fields.clear(); } } impl ::protobuf::reflect::ProtobufValue for DeviceAuthMessage { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum SignatureAlgorithm { UNSPECIFIED = 0, RSASSA_PKCS1v15 = 1, RSASSA_PSS = 2, } impl ::protobuf::ProtobufEnum for SignatureAlgorithm { fn value(&self) -> i32 { *self as i32 } fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(SignatureAlgorithm::UNSPECIFIED), 1 => ::std::option::Option::Some(SignatureAlgorithm::RSASSA_PKCS1v15), 2 => ::std::option::Option::Some(SignatureAlgorithm::RSASSA_PSS), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [SignatureAlgorithm] = &[ SignatureAlgorithm::UNSPECIFIED, SignatureAlgorithm::RSASSA_PKCS1v15, SignatureAlgorithm::RSASSA_PSS, ]; values } } impl ::std::marker::Copy for SignatureAlgorithm { } impl ::std::default::Default for SignatureAlgorithm { fn default() -> Self { SignatureAlgorithm::UNSPECIFIED } } impl ::protobuf::reflect::ProtobufValue for SignatureAlgorithm { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) } } #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum HashAlgorithm { SHA1 = 0, SHA256 = 1, } impl ::protobuf::ProtobufEnum for HashAlgorithm { fn value(&self) -> i32 { *self as i32 } fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(HashAlgorithm::SHA1), 1 => ::std::option::Option::Some(HashAlgorithm::SHA256), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [HashAlgorithm] = &[ HashAlgorithm::SHA1, HashAlgorithm::SHA256, ]; values } } impl ::std::marker::Copy for HashAlgorithm { } impl ::std::default::Default for HashAlgorithm { fn default() -> Self { HashAlgorithm::SHA1 } } impl ::protobuf::reflect::ProtobufValue for HashAlgorithm { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) } } rust_cast-0.17.0/src/cast/mod.rs000064400000000000000000000000770072674642500146220ustar 00000000000000pub mod authority_keys; pub mod cast_channel; pub mod proxies; rust_cast-0.17.0/src/cast/proxies.rs000064400000000000000000000252770072674642500155450ustar 00000000000000/// Proxy classes for the `connection` channel. pub mod connection { #[derive(Serialize, Debug)] pub struct ConnectionRequest { #[serde(rename = "type")] pub typ: String, #[serde(rename = "userAgent")] pub user_agent: String, } } /// Proxy classes for the `heartbeat` channel. pub mod heartbeat { #[derive(Serialize, Debug)] pub struct HeartBeatRequest { #[serde(rename = "type")] pub typ: String, } } /// Proxy classes for the `media` channel. pub mod media { #[derive(Serialize, Debug)] pub struct GetStatusRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, #[serde(rename = "mediaSessionId", skip_serializing_if = "Option::is_none")] pub media_session_id: Option, } #[derive(Serialize, Debug)] pub struct MediaRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "sessionId")] pub session_id: String, #[serde(rename = "type")] pub typ: String, pub media: Media, #[serde(rename = "currentTime")] pub current_time: f64, #[serde(rename = "customData")] pub custom_data: CustomData, pub autoplay: bool, } #[derive(Serialize, Debug)] pub struct PlaybackGenericRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "mediaSessionId")] pub media_session_id: i32, #[serde(rename = "type")] pub typ: String, #[serde(rename = "customData")] pub custom_data: CustomData, } #[derive(Serialize, Debug)] pub struct PlaybackSeekRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "mediaSessionId")] pub media_session_id: i32, #[serde(rename = "type")] pub typ: String, #[serde(rename = "resumeState")] pub resume_state: Option, #[serde(rename = "currentTime")] pub current_time: Option, #[serde(rename = "customData")] pub custom_data: CustomData, } #[derive(Serialize, Deserialize, Debug)] pub struct Media { #[serde(rename = "contentId")] pub content_id: String, #[serde(rename = "streamType", default)] pub stream_type: String, #[serde(rename = "contentType")] pub content_type: String, #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option, #[serde(skip_serializing_if = "Option::is_none")] pub duration: Option, } #[derive(Serialize, Deserialize, Debug)] pub struct Metadata { #[serde(rename = "metadataType")] pub metadata_type: u32, #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "seriesTitle")] pub series_title: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "albumName")] pub album_name: Option, #[serde(skip_serializing_if = "Option::is_none")] pub subtitle: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "albumArtist")] pub album_artist: Option, #[serde(skip_serializing_if = "Option::is_none")] pub artist: Option, #[serde(skip_serializing_if = "Option::is_none")] pub composer: Option, pub images: Vec, #[serde(skip_serializing_if = "Option::is_none", rename = "releaseDate")] pub release_date: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "originalAirDate")] pub original_air_date: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "creationDateTime")] pub creation_date_time: Option, #[serde(skip_serializing_if = "Option::is_none")] pub studio: Option, #[serde(skip_serializing_if = "Option::is_none")] pub location: Option, #[serde(skip_serializing_if = "Option::is_none")] pub latitude: Option, #[serde(skip_serializing_if = "Option::is_none")] pub longitude: Option, #[serde(skip_serializing_if = "Option::is_none")] pub season: Option, #[serde(skip_serializing_if = "Option::is_none")] pub episode: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "trackNumber")] pub track_number: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "discNumber")] pub disc_number: Option, #[serde(skip_serializing_if = "Option::is_none")] pub width: Option, #[serde(skip_serializing_if = "Option::is_none")] pub height: Option, } impl Metadata { pub fn new(metadata_type: u32) -> Metadata { Metadata { metadata_type, title: None, series_title: None, album_name: None, subtitle: None, album_artist: None, artist: None, composer: None, images: Vec::new(), release_date: None, original_air_date: None, creation_date_time: None, studio: None, location: None, latitude: None, longitude: None, season: None, episode: None, track_number: None, disc_number: None, width: None, height: None, } } } #[derive(Serialize, Deserialize, Debug)] pub struct Image { pub url: String, #[serde(skip_serializing_if = "Option::is_none")] pub width: Option, #[serde(skip_serializing_if = "Option::is_none")] pub height: Option, } #[derive(Serialize, Debug)] pub struct CustomData {} impl CustomData { pub fn new() -> CustomData { CustomData {} } } #[derive(Deserialize, Debug)] pub struct Status { #[serde(rename = "mediaSessionId")] pub media_session_id: i32, #[serde(default)] pub media: Option, #[serde(rename = "playbackRate")] pub playback_rate: f32, #[serde(rename = "playerState")] pub player_state: String, #[serde(rename = "idleReason")] pub idle_reason: Option, #[serde(rename = "currentTime")] pub current_time: Option, #[serde(rename = "supportedMediaCommands")] pub supported_media_commands: u32, } #[derive(Deserialize, Debug)] pub struct StatusReply { #[serde(rename = "requestId", default)] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub status: Vec, } #[derive(Deserialize, Debug)] pub struct LoadCancelledReply { #[serde(rename = "requestId")] pub request_id: i32, } #[derive(Deserialize, Debug)] pub struct LoadFailedReply { #[serde(rename = "requestId")] pub request_id: i32, } #[derive(Deserialize, Debug)] pub struct InvalidPlayerStateReply { #[serde(rename = "requestId")] pub request_id: i32, } #[derive(Deserialize, Debug)] pub struct InvalidRequestReply { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub reason: Option, } } /// Proxy classes for the `receiver` channel. pub mod receiver { use std::borrow::Cow; #[derive(Serialize, Debug)] pub struct AppLaunchRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, #[serde(rename = "appId")] pub app_id: String, } #[derive(Serialize, Debug)] pub struct AppStopRequest<'a> { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, #[serde(rename = "sessionId")] pub session_id: Cow<'a, str>, } #[derive(Serialize, Debug)] pub struct GetStatusRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, } #[derive(Serialize, Debug)] pub struct SetVolumeRequest { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub volume: Volume, } #[derive(Deserialize, Debug)] pub struct StatusReply { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub status: Status, } #[derive(Deserialize, Debug)] pub struct Status { #[serde(default)] pub applications: Vec, #[serde(rename = "isActiveInput", default)] pub is_active_input: bool, #[serde(rename = "isStandBy", default)] pub is_stand_by: bool, /// Volume parameters of the currently active cast device. pub volume: Volume, } #[derive(Deserialize, Debug)] pub struct Application { #[serde(rename = "appId")] pub app_id: String, #[serde(rename = "sessionId")] pub session_id: String, #[serde(rename = "transportId", default)] pub transport_id: String, #[serde(default)] pub namespaces: Vec, #[serde(rename = "displayName")] pub display_name: String, #[serde(rename = "statusText")] pub status_text: String, } #[derive(Deserialize, Debug)] pub struct AppNamespace { pub name: String, } /// Structure that describes possible cast device volume options. #[derive(Deserialize, Serialize, Debug)] pub struct Volume { /// Volume level. pub level: Option, /// Mute/unmute state. pub muted: Option, } #[derive(Deserialize, Debug)] pub struct LaunchErrorReply { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub reason: Option, } #[derive(Deserialize, Debug)] pub struct InvalidRequestReply { #[serde(rename = "requestId")] pub request_id: i32, #[serde(rename = "type")] pub typ: String, pub reason: Option, } } rust_cast-0.17.0/src/channels/connection.rs000064400000000000000000000063100072674642500170370ustar 00000000000000use std::{ borrow::Cow, io::{Read, Write}, }; use crate::{ cast::proxies, errors::Error, message_manager::{CastMessage, CastMessagePayload, MessageManager}, Lrc, }; const CHANNEL_NAMESPACE: &str = "urn:x-cast:com.google.cast.tp.connection"; const CHANNEL_USER_AGENT: &str = "RustCast"; const MESSAGE_TYPE_CONNECT: &str = "CONNECT"; const MESSAGE_TYPE_CLOSE: &str = "CLOSE"; #[derive(Clone, Debug)] pub enum ConnectionResponse { Connect, Close, NotImplemented(String, serde_json::Value), } pub struct ConnectionChannel<'a, W> where W: Read + Write, { sender: Cow<'a, str>, message_manager: Lrc>, } impl<'a, W> ConnectionChannel<'a, W> where W: Read + Write, { pub fn new(sender: S, message_manager: Lrc>) -> ConnectionChannel<'a, W> where S: Into>, { ConnectionChannel { sender: sender.into(), message_manager, } } pub fn connect(&self, destination: S) -> Result<(), Error> where S: Into>, { let payload = serde_json::to_string(&proxies::connection::ConnectionRequest { typ: MESSAGE_TYPE_CONNECT.to_string(), user_agent: CHANNEL_USER_AGENT.to_string(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), }) } pub fn disconnect(&self, destination: S) -> Result<(), Error> where S: Into>, { let payload = serde_json::to_string(&proxies::connection::ConnectionRequest { typ: MESSAGE_TYPE_CLOSE.to_string(), user_agent: CHANNEL_USER_AGENT.to_string(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), }) } pub fn can_handle(&self, message: &CastMessage) -> bool { message.namespace == CHANNEL_NAMESPACE } pub fn parse(&self, message: &CastMessage) -> Result { let reply = match message.payload { CastMessagePayload::String(ref payload) => { serde_json::from_str::(payload)? } _ => { return Err(Error::Internal( "Binary payload is not supported!".to_string(), )) } }; let message_type = reply .as_object() .and_then(|object| object.get("type")) .and_then(|property| property.as_str()) .unwrap_or("") .to_string(); let response = match message_type.as_ref() { MESSAGE_TYPE_CONNECT => ConnectionResponse::Connect, MESSAGE_TYPE_CLOSE => ConnectionResponse::Close, _ => ConnectionResponse::NotImplemented(message_type.to_string(), reply), }; Ok(response) } } rust_cast-0.17.0/src/channels/heartbeat.rs000064400000000000000000000057410072674642500166460ustar 00000000000000use std::{ borrow::Cow, io::{Read, Write}, }; use crate::{ cast::proxies, errors::Error, message_manager::{CastMessage, CastMessagePayload, MessageManager}, Lrc, }; const CHANNEL_NAMESPACE: &str = "urn:x-cast:com.google.cast.tp.heartbeat"; const MESSAGE_TYPE_PING: &str = "PING"; const MESSAGE_TYPE_PONG: &str = "PONG"; #[derive(Clone, Debug)] pub enum HeartbeatResponse { Ping, Pong, NotImplemented(String, serde_json::Value), } pub struct HeartbeatChannel<'a, W> where W: Read + Write, { sender: Cow<'a, str>, receiver: Cow<'a, str>, message_manager: Lrc>, } impl<'a, W> HeartbeatChannel<'a, W> where W: Read + Write, { pub fn new( sender: S, receiver: S, message_manager: Lrc>, ) -> HeartbeatChannel<'a, W> where S: Into>, { HeartbeatChannel { sender: sender.into(), receiver: receiver.into(), message_manager, } } pub fn ping(&self) -> Result<(), Error> { let payload = serde_json::to_string(&proxies::heartbeat::HeartBeatRequest { typ: MESSAGE_TYPE_PING.to_string(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), }) } pub fn pong(&self) -> Result<(), Error> { let payload = serde_json::to_string(&proxies::heartbeat::HeartBeatRequest { typ: MESSAGE_TYPE_PONG.to_string(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), }) } pub fn can_handle(&self, message: &CastMessage) -> bool { message.namespace == CHANNEL_NAMESPACE } pub fn parse(&self, message: &CastMessage) -> Result { let reply = match message.payload { CastMessagePayload::String(ref payload) => { serde_json::from_str::(payload)? } _ => { return Err(Error::Internal( "Binary payload is not supported!".to_string(), )) } }; let message_type = reply .as_object() .and_then(|object| object.get("type")) .and_then(|property| property.as_str()) .unwrap_or("") .to_string(); let response = match message_type.as_ref() { MESSAGE_TYPE_PING => HeartbeatResponse::Ping, MESSAGE_TYPE_PONG => HeartbeatResponse::Pong, _ => HeartbeatResponse::NotImplemented(message_type.to_string(), reply), }; Ok(response) } } rust_cast-0.17.0/src/channels/media.rs000064400000000000000000001047310072674642500157650ustar 00000000000000use std::{ borrow::Cow, io::{Read, Write}, str::FromStr, string::ToString, }; use crate::{ cast::proxies, errors::Error, message_manager::{CastMessage, CastMessagePayload, MessageManager}, Lrc, }; const CHANNEL_NAMESPACE: &str = "urn:x-cast:com.google.cast.media"; const MESSAGE_TYPE_GET_STATUS: &str = "GET_STATUS"; const MESSAGE_TYPE_LOAD: &str = "LOAD"; const MESSAGE_TYPE_PLAY: &str = "PLAY"; const MESSAGE_TYPE_PAUSE: &str = "PAUSE"; const MESSAGE_TYPE_STOP: &str = "STOP"; const MESSAGE_TYPE_SEEK: &str = "SEEK"; const MESSAGE_TYPE_MEDIA_STATUS: &str = "MEDIA_STATUS"; const MESSAGE_TYPE_LOAD_CANCELLED: &str = "LOAD_CANCELLED"; const MESSAGE_TYPE_LOAD_FAILED: &str = "LOAD_FAILED"; const MESSAGE_TYPE_INVALID_PLAYER_STATE: &str = "INVALID_PLAYER_STATE"; const MESSAGE_TYPE_INVALID_REQUEST: &str = "INVALID_REQUEST"; /// Describes the way cast device should stream content. #[derive(Copy, Clone, Debug)] pub enum StreamType { /// This variant allows cast device to automatically choose whatever way it's most comfortable /// with. None, /// Cast device should buffer some portion of the content and only then start streaming. Buffered, /// Cast device should display content as soon as it gets any portion of it. Live, } impl FromStr for StreamType { type Err = Error; fn from_str(s: &str) -> Result { match s { "BUFFERED" | "buffered" => Ok(StreamType::Buffered), "LIVE" | "live" => Ok(StreamType::Live), _ => Ok(StreamType::None), } } } impl ToString for StreamType { fn to_string(&self) -> String { let stream_type = match *self { StreamType::None => "NONE", StreamType::Buffered => "BUFFERED", StreamType::Live => "LIVE", }; stream_type.to_string() } } /// Generic, movie, TV show, music track, or photo metadata. #[derive(Clone, Debug)] pub enum Metadata { Generic(GenericMediaMetadata), Movie(MovieMediaMetadata), TvShow(TvShowMediaMetadata), MusicTrack(MusicTrackMediaMetadata), Photo(PhotoMediaMetadata), } /// Generic media metadata. /// /// See also the [`GenericMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#GenericMediaMetadata). #[derive(Clone, Debug)] pub struct GenericMediaMetadata { /// Descriptive title of the content. pub title: Option, /// Descriptive subtitle of the content. pub subtitle: Option, /// Zero or more URLs to an image associated with the content. pub images: Vec, /// Date and time the content was released, formatted as ISO 8601. pub release_date: Option, } /// Movie media metadata. /// /// See also the [`MovieMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#MovieMediaMetadata). #[derive(Clone, Debug)] pub struct MovieMediaMetadata { /// Title of the movie. pub title: Option, /// Subtitle of the movie. pub subtitle: Option, /// Studio which released the movie. pub studio: Option, /// Zero or more URLs to an image associated with the content. pub images: Vec, /// Date and time the movie was released, formatted as ISO 8601. pub release_date: Option, } /// TV show media metadata. /// /// See also the [`TvShowMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#TvShowMediaMetadata). #[derive(Clone, Debug)] pub struct TvShowMediaMetadata { /// Title of the TV series. pub series_title: Option, /// Title of the episode. pub episode_title: Option, /// Season number of the TV show. pub season: Option, /// Episode number (in the season) of the episode. pub episode: Option, /// Zero or more URLs to an image associated with the content. pub images: Vec, /// Date and time this episode was released, formatted as ISO 8601. pub original_air_date: Option, } /// Music track media metadata. /// /// See also the [`MusicTrackMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#MusicTrackMediaMetadata). #[derive(Clone, Debug)] pub struct MusicTrackMediaMetadata { /// Album or collection from which the track is taken. pub album_name: Option, /// Name of the track (for example, song title). pub title: Option, /// Name of the artist associated with the album featuring this track. pub album_artist: Option, /// Name of the artist associated with the track. pub artist: Option, /// Name of the composer associated with the track. pub composer: Option, /// Number of the track on the album. pub track_number: Option, /// Number of the volume (for example, a disc) of the album. pub disc_number: Option, /// Zero or more URLs to an image associated with the content. pub images: Vec, /// Date and time the content was released, formatted as ISO 8601. pub release_date: Option, } /// Photo media metadata. /// /// See also the [`PhotoMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#PhotoMediaMetadata). #[derive(Clone, Debug)] pub struct PhotoMediaMetadata { /// Title of the photograph. pub title: Option, /// Name of the photographer. pub artist: Option, /// Verbal location where the photograph was taken, for example “Madrid, Spain”. pub location: Option, /// Latitude and longitude of the location where the photograph was taken. pub latitude_longitude: Option<(f64, f64)>, /// Width and height of the photograph in pixels. pub dimensions: Option<(u32, u32)>, /// Date and time the photograph was taken, formatted as ISO 8601. pub creation_date_time: Option, } /// Image URL and optionally size metadata. /// /// This is the description of an image, including a small amount of metadata to /// allow the sender application a choice of images, depending on how it will /// render them. The height and width are optional on only one item in an array /// of images. /// /// See also the [`Image` Cast reference](https://developers.google.com/cast/docs/reference/messages#Image). #[derive(Clone, Debug)] pub struct Image { /// URL of the image. pub url: String, /// Width and height of the image. pub dimensions: Option<(u32, u32)>, } impl Image { pub fn new(url: String) -> Image { Image { url, dimensions: None, } } fn encode(&self) -> proxies::media::Image { proxies::media::Image { url: self.url.clone(), width: self.dimensions.map(|d| d.0), height: self.dimensions.map(|d| d.1), } } } /// Describes possible player states. #[derive(Copy, Clone, Debug)] pub enum PlayerState { /// Player has not been loaded yet. Idle, /// Player is actively playing content. Playing, /// Player is in PLAY mode but not actively playing content (currentTime is not changing). Buffering, /// Player is paused. Paused, } impl FromStr for PlayerState { type Err = Error; fn from_str(s: &str) -> Result { match s { "IDLE" => Ok(PlayerState::Idle), "PLAYING" => Ok(PlayerState::Playing), "BUFFERING" => Ok(PlayerState::Buffering), "PAUSED" => Ok(PlayerState::Paused), _ => Err(Error::Internal(format!("Unknown player state {}", s))), } } } impl ToString for PlayerState { fn to_string(&self) -> String { let player_state = match *self { PlayerState::Idle => "IDLE", PlayerState::Playing => "PLAYING", PlayerState::Buffering => "BUFFERING", PlayerState::Paused => "PAUSED", }; player_state.to_string() } } /// Describes possible player idle reasons. #[derive(Copy, Clone, Debug)] pub enum IdleReason { /// A sender requested to stop playback using the STOP command. Cancelled, /// A sender requested playing a different media using the LOAD command. Interrupted, /// The media playback completed. Finished, /// The media was interrupted due to an error; For example, if the player could not download the /// media due to network issues. Error, } impl FromStr for IdleReason { type Err = Error; fn from_str(s: &str) -> Result { match s { "CANCELLED" => Ok(IdleReason::Cancelled), "INTERRUPTED" => Ok(IdleReason::Interrupted), "FINISHED" => Ok(IdleReason::Finished), "ERROR" => Ok(IdleReason::Error), _ => Err(Error::Internal(format!("Unknown idle reason {}", s))), } } } /// Describes the operation to perform with playback while seeking. #[derive(Copy, Clone, Debug)] pub enum ResumeState { /// Forces media to start. PlaybackStart, /// Forces media to pause. PlaybackPause, } impl FromStr for ResumeState { type Err = Error; fn from_str(s: &str) -> Result { match s { "PLAYBACK_START" | "start" => Ok(ResumeState::PlaybackStart), "PLAYBACK_PAUSE" | "pause" => Ok(ResumeState::PlaybackPause), _ => Err(Error::Internal(format!("Unknown resume state {}", s))), } } } impl ToString for ResumeState { fn to_string(&self) -> String { let resume_state = match *self { ResumeState::PlaybackStart => "PLAYBACK_START", ResumeState::PlaybackPause => "PLAYBACK_PAUSE", }; resume_state.to_string() } } /// This data structure describes a media stream. #[derive(Clone, Debug)] pub struct Media { /// Service-specific identifier of the content currently loaded by the media player. This is a /// free form string and is specific to the application. In most cases, this will be the URL to /// the media, but the sender can choose to pass a string that the receiver can interpret /// properly. Max length: 1k. pub content_id: String, /// Describes the type of media artifact. pub stream_type: StreamType, /// MIME content type of the media being played. pub content_type: String, /// Generic, movie, TV show, music track, or photo metadata. pub metadata: Option, /// Duration of the currently playing stream in seconds. pub duration: Option, } /// Describes the current status of the media artifact with respect to the session. #[derive(Clone, Debug)] pub struct Status { /// Unique id of the request that requested the status. pub request_id: i32, /// Detailed status of every media status entry. pub entries: Vec, } /// Detailed status of the media artifact with respect to the session. #[derive(Clone, Debug)] pub struct StatusEntry { /// Unique ID for the playback of this specific session. This ID is set by the receiver at LOAD /// and can be used to identify a specific instance of a playback. For example, two playbacks of /// "Wish you were here" within the same session would each have a unique mediaSessionId. pub media_session_id: i32, /// Full description of the content that is being played back. Only be returned in a status /// messages if the Media has changed. pub media: Option, /// Indicates whether the media time is progressing, and at what rate. This is independent of /// the player state since the media time can stop in any state. 1.0 is regular time, 0.5 is /// slow motion. pub playback_rate: f32, /// Describes the state of the player. pub player_state: PlayerState, /// If the player_state is IDLE and the reason it became IDLE is known, this property is /// provided. If the player is IDLE because it just started, this property will not be provided. /// If the player is in any other state this property should not be provided. pub idle_reason: Option, /// The current position of the media player since the beginning of the content, in seconds. /// If this a live stream content, then this field represents the time in seconds from the /// beginning of the event that should be known to the player. pub current_time: Option, /// Flags describing which media commands the media player supports: /// * `1` `Pause`; /// * `2` `Seek`; /// * `4` `Stream volume`; /// * `8` `Stream mute`; /// * `16` `Skip forward`; /// * `32` `Skip backward`; /// * `1 << 12` `Unknown`; /// * `1 << 13` `Unknown`; /// * `1 << 18` `Unknown`. /// Combinations are described as summations; for example, Pause+Seek+StreamVolume+Mute == 15. pub supported_media_commands: u32, } /// Describes the load cancelled error. #[derive(Copy, Clone, Debug)] pub struct LoadCancelled { /// Unique id of the request that caused this error. pub request_id: i32, } /// Describes the load failed error. #[derive(Copy, Clone, Debug)] pub struct LoadFailed { /// Unique id of the request that caused this error. pub request_id: i32, } /// Describes the invalid player state error. #[derive(Copy, Clone, Debug)] pub struct InvalidPlayerState { /// Unique id of the request that caused this error. pub request_id: i32, } /// Describes the invalid request error. #[derive(Clone, Debug)] pub struct InvalidRequest { /// Unique id of the invalid request. pub request_id: i32, /// Description of the invalid request reason if available. pub reason: Option, } /// Represents all currently supported incoming messages that media channel can handle. #[derive(Clone, Debug)] pub enum MediaResponse { /// Statuses of the currently active media. Status(Status), /// Sent when the load request was cancelled (a second load request was received). LoadCancelled(LoadCancelled), /// Sent when the load request failed. The player state will be IDLE. LoadFailed(LoadFailed), /// Sent when the request by the sender can not be fulfilled because the player is not in a /// valid state. For example, if the application has not created a media element yet. InvalidPlayerState(InvalidPlayerState), /// Error indicating that request is not valid. InvalidRequest(InvalidRequest), /// Used every time when channel can't parse the message. Associated data contains `type` string /// field and raw JSON data returned from cast device. NotImplemented(String, serde_json::Value), } pub struct MediaChannel<'a, W> where W: Read + Write, { sender: Cow<'a, str>, message_manager: Lrc>, } impl<'a, W> MediaChannel<'a, W> where W: Read + Write, { pub fn new(sender: S, message_manager: Lrc>) -> MediaChannel<'a, W> where S: Into>, { MediaChannel { sender: sender.into(), message_manager, } } /// Retrieves status of the cast device media session. /// /// # Arguments /// /// * `destination` - `protocol` identifier of specific app media session; /// * `media_session_id` - Media session ID of the media for which the media status should be /// returned. If none is provided, then the status for all media session IDs will be provided. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn get_status( &self, destination: S, media_session_id: Option, ) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::media::GetStatusRequest { typ: MESSAGE_TYPE_GET_STATUS.to_string(), request_id, media_session_id, })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } match self.parse(message)? { MediaResponse::Status(status) => { if status.request_id == request_id { return Ok(Some(status)); } } MediaResponse::InvalidRequest(error) => { if error.request_id == request_id { return Err(Error::Internal(format!( "Invalid request ({}).", error.reason.unwrap_or_else(|| "Unknown".to_string()) ))); } } _ => {} } Ok(None) }) } /// Loads provided media to the application. /// /// # Arguments /// * `destination` - `protocol` of the application to load media with (e.g. `web-1`); /// * `session_id` - Current session identifier of the player application; /// * `media` - `Media` instance that describes the media we'd like to load. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn load(&self, destination: S, session_id: S, media: &Media) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let metadata = media.metadata.as_ref().map(|m| match *m { Metadata::Generic(ref x) => proxies::media::Metadata { title: x.title.clone(), subtitle: x.subtitle.clone(), images: x.images.iter().map(|i| i.encode()).collect(), release_date: x.release_date.clone(), ..proxies::media::Metadata::new(0) }, Metadata::Movie(ref x) => proxies::media::Metadata { title: x.title.clone(), subtitle: x.subtitle.clone(), studio: x.studio.clone(), images: x.images.iter().map(|i| i.encode()).collect(), release_date: x.release_date.clone(), ..proxies::media::Metadata::new(1) }, Metadata::TvShow(ref x) => proxies::media::Metadata { series_title: x.series_title.clone(), subtitle: x.episode_title.clone(), season: x.season, episode: x.episode, images: x.images.iter().map(|i| i.encode()).collect(), original_air_date: x.original_air_date.clone(), ..proxies::media::Metadata::new(2) }, Metadata::MusicTrack(ref x) => proxies::media::Metadata { album_name: x.album_name.clone(), title: x.title.clone(), album_artist: x.album_artist.clone(), artist: x.artist.clone(), composer: x.composer.clone(), track_number: x.track_number, disc_number: x.disc_number, images: x.images.iter().map(|i| i.encode()).collect(), release_date: x.release_date.clone(), ..proxies::media::Metadata::new(3) }, Metadata::Photo(ref x) => proxies::media::Metadata { title: x.title.clone(), artist: x.artist.clone(), location: x.location.clone(), latitude: x.latitude_longitude.map(|coord| coord.0), longitude: x.latitude_longitude.map(|coord| coord.1), width: x.dimensions.map(|dims| dims.0), height: x.dimensions.map(|dims| dims.1), creation_date_time: x.creation_date_time.clone(), ..proxies::media::Metadata::new(4) }, }); let payload = serde_json::to_string(&proxies::media::MediaRequest { request_id, session_id: session_id.into().to_string(), typ: MESSAGE_TYPE_LOAD.to_string(), media: proxies::media::Media { content_id: media.content_id.clone(), stream_type: media.stream_type.to_string(), content_type: media.content_type.clone(), metadata, duration: media.duration, }, current_time: 0_f64, autoplay: true, custom_data: proxies::media::CustomData::new(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; // Once media is loaded cast receiver device should emit status update event, or load failed // event if something went wrong. self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } match self.parse(message)? { MediaResponse::Status(status) => { if status.request_id == request_id { return Ok(Some(status)); } // [WORKAROUND] In some cases we don't receive response (e.g. from YouTube app), // so let's just wait for the response with the media we're interested in and // return it. let has_media = { status.entries.iter().any(|entry| { if let Some(ref loaded_media) = entry.media { return loaded_media.content_id == media.content_id; } false }) }; if has_media { return Ok(Some(status)); } } MediaResponse::LoadFailed(error) => { if error.request_id == request_id { return Err(Error::Internal("Failed to load media.".to_string())); } } MediaResponse::LoadCancelled(error) => { if error.request_id == request_id { return Err(Error::Internal( "Load cancelled by another request.".to_string(), )); } } MediaResponse::InvalidPlayerState(error) => { if error.request_id == request_id { return Err(Error::Internal( "Load failed because of invalid player state.".to_string(), )); } } MediaResponse::InvalidRequest(error) => { if error.request_id == request_id { return Err(Error::Internal(format!( "Load failed because of invalid media request (reason: {}).", error.reason.unwrap_or_else(|| "UNKNOWN".to_string()) ))); } } _ => {} } Ok(None) }) } /// Pauses playback of the current content. Triggers a STATUS event notification to all sender /// applications. /// /// # Arguments /// /// * `destination` - `protocol` of the media application (e.g. `web-1`); /// * `media_session_id` - ID of the media session to be paused. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn pause(&self, destination: S, media_session_id: i32) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::media::PlaybackGenericRequest { request_id, media_session_id, typ: MESSAGE_TYPE_PAUSE.to_string(), custom_data: proxies::media::CustomData::new(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; self.receive_status_entry(request_id, media_session_id) } /// Begins playback of the content that was loaded with the load call, playback is continued /// from the current time position. /// /// # Arguments /// /// * `destination` - `protocol` of the media application (e.g. `web-1`); /// * `media_session_id` - ID of the media session to be played. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn play(&self, destination: S, media_session_id: i32) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::media::PlaybackGenericRequest { request_id, media_session_id, typ: MESSAGE_TYPE_PLAY.to_string(), custom_data: proxies::media::CustomData::new(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; self.receive_status_entry(request_id, media_session_id) } /// Stops playback of the current content. Triggers a STATUS event notification to all sender /// applications. After this command the content will no longer be loaded and the /// media_session_id is invalidated. /// /// # Arguments /// /// * `destination` - `protocol` of the media application (e.g. `web-1`); /// * `media_session_id` - ID of the media session to be stopped. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn stop(&self, destination: S, media_session_id: i32) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::media::PlaybackGenericRequest { request_id, media_session_id, typ: MESSAGE_TYPE_STOP.to_string(), custom_data: proxies::media::CustomData::new(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; self.receive_status_entry(request_id, media_session_id) } /// Sets the current position in the stream. Triggers a STATUS event notification to all sender /// applications. If the position provided is outside the range of valid positions for the /// current content, then the player should pick a valid position as close to the requested /// position as possible. /// /// # Arguments /// /// * `destination` - `protocol` of the media application (e.g. `web-1`); /// * `media_session_id` - ID of the media session to seek in; /// * `current_time` - Time in seconds to seek to. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn seek( &self, destination: S, media_session_id: i32, current_time: Option, resume_state: Option, ) -> Result where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::media::PlaybackSeekRequest { request_id, media_session_id, typ: MESSAGE_TYPE_SEEK.to_string(), current_time, resume_state: resume_state.map(|s| s.to_string()), custom_data: proxies::media::CustomData::new(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: destination.into().to_string(), payload: CastMessagePayload::String(payload), })?; self.receive_status_entry(request_id, media_session_id) } pub fn can_handle(&self, message: &CastMessage) -> bool { message.namespace == CHANNEL_NAMESPACE } pub fn parse(&self, message: &CastMessage) -> Result { let reply = match message.payload { CastMessagePayload::String(ref payload) => { serde_json::from_str::(payload)? } _ => { return Err(Error::Internal( "Binary payload is not supported!".to_string(), )) } }; let message_type = reply .as_object() .and_then(|object| object.get("type")) .and_then(|property| property.as_str()) .unwrap_or("") .to_string(); let response = match message_type.as_ref() { MESSAGE_TYPE_MEDIA_STATUS => { let reply: proxies::media::StatusReply = serde_json::value::from_value(reply)?; let statuses_entries = reply.status.iter().map(|x| { StatusEntry { media_session_id: x.media_session_id, media: x.media.as_ref().map(|m| { Media { content_id: m.content_id.to_string(), stream_type: StreamType::from_str(m.stream_type.as_ref()).unwrap(), content_type: m.content_type.to_string(), metadata: None, // TODO duration: m.duration, } }), playback_rate: x.playback_rate, player_state: PlayerState::from_str(x.player_state.as_ref()).unwrap(), idle_reason: x .idle_reason .as_ref() .map(|reason| IdleReason::from_str(reason).unwrap()), current_time: x.current_time, supported_media_commands: x.supported_media_commands, } }); MediaResponse::Status(Status { request_id: reply.request_id, entries: statuses_entries.collect::>(), }) } MESSAGE_TYPE_LOAD_CANCELLED => { let reply: proxies::media::LoadCancelledReply = serde_json::value::from_value(reply)?; MediaResponse::LoadCancelled(LoadCancelled { request_id: reply.request_id, }) } MESSAGE_TYPE_LOAD_FAILED => { let reply: proxies::media::LoadFailedReply = serde_json::value::from_value(reply)?; MediaResponse::LoadFailed(LoadFailed { request_id: reply.request_id, }) } MESSAGE_TYPE_INVALID_PLAYER_STATE => { let reply: proxies::media::InvalidPlayerStateReply = serde_json::value::from_value(reply)?; MediaResponse::InvalidPlayerState(InvalidPlayerState { request_id: reply.request_id, }) } MESSAGE_TYPE_INVALID_REQUEST => { let reply: proxies::media::InvalidRequestReply = serde_json::value::from_value(reply)?; MediaResponse::InvalidRequest(InvalidRequest { request_id: reply.request_id, reason: reply.reason, }) } _ => MediaResponse::NotImplemented(message_type.to_string(), reply), }; Ok(response) } /// Waits for the status entry with specified `request_id` and `media_session_id`. This method /// is very handy for the media playback methods where particular `StatusEntry` is required. /// /// # Arguments /// /// * `request_id` - ID of the request that caused status entry to be broadcasted. /// * `media_session_id` - ID of the media session to receive. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. fn receive_status_entry( &self, request_id: i32, media_session_id: i32, ) -> Result { self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } match self.parse(message)? { MediaResponse::Status(mut status) => { if status.request_id == request_id { let position = status .entries .iter() .position(|e| e.media_session_id == media_session_id); return Ok(position.map(|position| status.entries.remove(position))); } } MediaResponse::InvalidPlayerState(error) => { if error.request_id == request_id { return Err(Error::Internal( "Request failed because of invalid player state.".to_string(), )); } } MediaResponse::InvalidRequest(error) => { if error.request_id == request_id { return Err(Error::Internal(format!( "Invalid request ({}).", error.reason.unwrap_or_else(|| "Unknown".to_string()) ))); } } _ => {} } Ok(None) }) } } rust_cast-0.17.0/src/channels/mod.rs000064400000000000000000000001100072674642500154470ustar 00000000000000pub mod connection; pub mod heartbeat; pub mod media; pub mod receiver; rust_cast-0.17.0/src/channels/receiver.rs000064400000000000000000000372010072674642500165070ustar 00000000000000use std::{ borrow::Cow, convert::Into, io::{Read, Write}, str::FromStr, string::ToString, }; use crate::{ cast::proxies, errors::Error, message_manager::{CastMessage, CastMessagePayload, MessageManager}, Lrc, }; const CHANNEL_NAMESPACE: &str = "urn:x-cast:com.google.cast.receiver"; const MESSAGE_TYPE_LAUNCH: &str = "LAUNCH"; const MESSAGE_TYPE_STOP: &str = "STOP"; const MESSAGE_TYPE_GET_STATUS: &str = "GET_STATUS"; const MESSAGE_TYPE_SET_VOLUME: &str = "SET_VOLUME"; const MESSAGE_TYPE_RECEIVER_STATUS: &str = "RECEIVER_STATUS"; const MESSAGE_TYPE_LAUNCH_ERROR: &str = "LAUNCH_ERROR"; const MESSAGE_TYPE_INVALID_REQUEST: &str = "INVALID_REQUEST"; const APP_DEFAULT_MEDIA_RECEIVER_ID: &str = "CC1AD845"; const APP_BACKDROP_ID: &str = "E8C28D3C"; const APP_YOUTUBE_ID: &str = "233637DE"; /// Structure that describes possible cast device volume options. #[derive(Copy, Clone, Debug)] pub struct Volume { /// Volume level. pub level: Option, /// Mute/unmute state. pub muted: Option, } /// This `From` implementation is useful when only volume level is needed. impl From for Volume { fn from(level: f32) -> Self { Self { level: Some(level), muted: None, } } } /// This `From` implementation is useful when only mute/unmute state is needed. impl From for Volume { fn from(muted: bool) -> Self { Self { level: None, muted: Some(muted), } } } /// This `From<(f32, bool)>` implementation is useful when both volume level and mute/unmute state are /// needed. impl From<(f32, bool)> for Volume { fn from((level, muted): (f32, bool)) -> Self { Self { level: Some(level), muted: Some(muted), } } } /// Structure that describes currently run Cast Device application. #[derive(Clone, Debug)] pub struct Application { /// The identifier of the Cast application. Not for display. pub app_id: String, /// Session id of the currently active application. pub session_id: String, /// Name of the `pipe` to talk to the application. pub transport_id: String, /// A list of the namespaces supported by the receiver application. pub namespaces: Vec, /// The human-readable name of the Cast application, for example, "YouTube". pub display_name: String, /// Descriptive text for the current application content, for example “My vacations”. pub status_text: String, } /// Describes the current status of the receiver cast device. #[derive(Clone, Debug)] pub struct Status { /// Unique id of the request that requested the status. pub request_id: i32, /// Contains the list of applications that are currently run. pub applications: Vec, /// Determines whether the Cast device is the active input or not. pub is_active_input: bool, /// Determines whether the Cast device is in stand by mode. pub is_stand_by: bool, /// Volume parameters of the currently active cast device. pub volume: Volume, } /// Describes the application launch error. #[derive(Clone, Debug)] pub struct LaunchError { /// Unique id of the request that tried to launch application. pub request_id: i32, /// Description of the launch error reason if available. pub reason: Option, } /// Describes the invalid request error. #[derive(Clone, Debug)] pub struct InvalidRequest { /// Unique id of the invalid request. pub request_id: i32, /// Description of the invalid request reason if available. pub reason: Option, } /// Represents all currently supported incoming messages that receiver channel can handle. #[derive(Clone, Debug)] pub enum ReceiverResponse { /// Status of the currently active receiver. Status(Status), /// Error indicating that receiver failed to launch application. LaunchError(LaunchError), /// Error indicating that request is not valid. InvalidRequest(InvalidRequest), /// Used every time when channel can't parse the message. Associated data contains `type` string /// field and raw JSON data returned from cast device. NotImplemented(String, serde_json::Value), } #[derive(Clone, Debug, PartialEq)] pub enum CastDeviceApp { DefaultMediaReceiver, Backdrop, YouTube, Custom(String), } impl FromStr for CastDeviceApp { type Err = (); fn from_str(s: &str) -> Result { let app = match s { APP_DEFAULT_MEDIA_RECEIVER_ID | "default" => CastDeviceApp::DefaultMediaReceiver, APP_BACKDROP_ID | "backdrop" => CastDeviceApp::Backdrop, APP_YOUTUBE_ID | "youtube" => CastDeviceApp::YouTube, custom => CastDeviceApp::Custom(custom.to_string()), }; Ok(app) } } impl ToString for CastDeviceApp { fn to_string(&self) -> String { match *self { CastDeviceApp::DefaultMediaReceiver => APP_DEFAULT_MEDIA_RECEIVER_ID.to_string(), CastDeviceApp::Backdrop => APP_BACKDROP_ID.to_string(), CastDeviceApp::YouTube => APP_YOUTUBE_ID.to_string(), CastDeviceApp::Custom(ref app_id) => app_id.to_string(), } } } pub struct ReceiverChannel<'a, W> where W: Write + Read, { sender: Cow<'a, str>, receiver: Cow<'a, str>, message_manager: Lrc>, } impl<'a, W> ReceiverChannel<'a, W> where W: Write + Read, { pub fn new( sender: S, receiver: S, message_manager: Lrc>, ) -> ReceiverChannel<'a, W> where S: Into>, { ReceiverChannel { sender: sender.into(), receiver: receiver.into(), message_manager, } } /// Launches the specified receiver's application. /// /// # Examples /// /// ```no_run /// use std::str::FromStr; /// use rust_cast::{CastDevice, channels::receiver::CastDeviceApp}; /// /// # let cast_device = CastDevice::connect_without_host_verification("host", 1234).unwrap(); /// cast_device.receiver.launch_app(&CastDeviceApp::from_str("youtube").unwrap()); /// ``` /// /// # Arguments /// /// * `app` - `CastDeviceApp` instance reference to run. pub fn launch_app(&self, app: &CastDeviceApp) -> Result { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::receiver::AppLaunchRequest { typ: MESSAGE_TYPE_LAUNCH.to_string(), request_id, app_id: app.to_string(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), })?; // Once application is run cast receiver device should emit status update event, or launch // error event if something went wrong. self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } match self.parse(message)? { ReceiverResponse::Status(mut status) => { if status.request_id == request_id { return Ok(Some(status.applications.remove(0))); } } ReceiverResponse::LaunchError(error) => { if error.request_id == request_id { return Err(Error::Internal(format!( "Could not run application ({}).", error.reason.unwrap_or_else(|| "Unknown".to_string()) ))); } } _ => {} } Ok(None) }) } /// Stops currently active app using corresponding `session_id`. /// /// # Arguments /// * `session_id` - identifier of the active application session from `Application` instance. pub fn stop_app(&self, session_id: S) -> Result<(), Error> where S: Into>, { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::receiver::AppStopRequest { typ: MESSAGE_TYPE_STOP.to_string(), request_id, session_id: session_id.into(), })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), })?; // Once application is stopped cast receiver device should emit status update event, or // invalid request event if provided session id is not valid. self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } match self.parse(message)? { ReceiverResponse::Status(status) => { if status.request_id == request_id { return Ok(Some(())); } } ReceiverResponse::InvalidRequest(error) => { if error.request_id == request_id { return Err(Error::Internal(format!( "Invalid request ({}).", error.reason.unwrap_or_else(|| "Unknown".to_string()) ))); } } _ => {} } Ok(None) }) } /// Retrieves status of the cast device receiver. /// /// # Return value /// /// Returned `Result` should consist of either `Status` instance or an `Error`. pub fn get_status(&self) -> Result { let request_id = self.message_manager.generate_request_id(); let payload = serde_json::to_string(&proxies::receiver::GetStatusRequest { typ: MESSAGE_TYPE_GET_STATUS.to_string(), request_id, })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), })?; self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } let message = self.parse(message)?; if let ReceiverResponse::Status(status) = message { if status.request_id == request_id { return Ok(Some(status)); } } Ok(None) }) } /// Sets volume for the active cast device. /// /// # Arguments /// /// * `volume` - anything that can be converted to a valid `Volume` structure. It's possible to /// set volume level, mute/unmute state or both altogether. /// /// # Return value /// /// Actual `Volume` instance returned by receiver. /// /// # Errors /// /// Usually method can fail only if network connection with cast device is lost for some reason. pub fn set_volume(&self, volume: T) -> Result where T: Into, { let request_id = self.message_manager.generate_request_id(); let volume = volume.into(); let payload = serde_json::to_string(&proxies::receiver::SetVolumeRequest { typ: MESSAGE_TYPE_SET_VOLUME.to_string(), request_id, volume: proxies::receiver::Volume { level: volume.level, muted: volume.muted, }, })?; self.message_manager.send(CastMessage { namespace: CHANNEL_NAMESPACE.to_string(), source: self.sender.to_string(), destination: self.receiver.to_string(), payload: CastMessagePayload::String(payload), })?; self.message_manager.receive_find_map(|message| { if !self.can_handle(message) { return Ok(None); } let message = self.parse(message)?; if let ReceiverResponse::Status(status) = message { if status.request_id == request_id { return Ok(Some(status.volume)); } } Ok(None) }) } pub fn can_handle(&self, message: &CastMessage) -> bool { message.namespace == CHANNEL_NAMESPACE } pub fn parse(&self, message: &CastMessage) -> Result { let reply = match message.payload { CastMessagePayload::String(ref payload) => { serde_json::from_str::(payload)? } _ => { return Err(Error::Internal( "Binary payload is not supported!".to_string(), )) } }; let message_type = reply .as_object() .and_then(|object| object.get("type")) .and_then(|property| property.as_str()) .unwrap_or("") .to_string(); let response = match message_type.as_ref() { MESSAGE_TYPE_RECEIVER_STATUS => { let status_reply: proxies::receiver::StatusReply = serde_json::value::from_value(reply)?; let status = Status { request_id: status_reply.request_id, applications: status_reply .status .applications .iter() .map(|app| Application { app_id: app.app_id.clone(), session_id: app.session_id.clone(), transport_id: app.transport_id.clone(), namespaces: app .namespaces .iter() .map(|ns| ns.name.clone()) .collect::>(), display_name: app.display_name.clone(), status_text: app.status_text.clone(), }) .collect::>(), is_active_input: status_reply.status.is_active_input, is_stand_by: status_reply.status.is_stand_by, volume: Volume { level: status_reply.status.volume.level, muted: status_reply.status.volume.muted, }, }; ReceiverResponse::Status(status) } MESSAGE_TYPE_LAUNCH_ERROR => { let reply: proxies::receiver::LaunchErrorReply = serde_json::value::from_value(reply)?; ReceiverResponse::LaunchError(LaunchError { request_id: reply.request_id, reason: reply.reason, }) } MESSAGE_TYPE_INVALID_REQUEST => { let reply: proxies::receiver::InvalidRequestReply = serde_json::value::from_value(reply)?; ReceiverResponse::InvalidRequest(InvalidRequest { request_id: reply.request_id, reason: reply.reason, }) } _ => ReceiverResponse::NotImplemented(message_type.to_string(), reply), }; Ok(response) } } rust_cast-0.17.0/src/errors.rs000064400000000000000000000061510072674642500144240ustar 00000000000000use openssl::error::ErrorStack; use openssl::ssl::HandshakeError; use protobuf::ProtobufError; use serde_json::error::Error as SerializationError; use std::error::Error as StdError; use std::fmt::{Display, Formatter, Result}; use std::io::Error as IoError; use std::net::TcpStream; /// Consolidates possible error types that can occur in the OpenSSL lib. #[derive(Debug)] pub enum SslError { /// This variant includes everything related to the existing SSL connection. Generic(ErrorStack), /// This variant describes an error or intermediate state after a TLS handshake attempt. Handshake(HandshakeError), } impl Display for SslError { fn fmt(&self, f: &mut Formatter) -> Result { match *self { SslError::Generic(ref err) => Display::fmt(&err, f), SslError::Handshake(ref err) => Display::fmt(&err, f), } } } impl StdError for SslError { fn source(&self) -> Option<&(dyn StdError + 'static)> { match *self { SslError::Generic(ref e) => e.source(), SslError::Handshake(ref e) => e.source(), } } } /// Consolidates possible error types that can occur in the lib. #[derive(Debug)] pub enum Error { /// This variant is used when error occurs in the lib logic. Internal(String), /// This variant includes everything related to the network connection. Io(IoError), /// This variant includes all possible errors that come from Protobuf layer. Protobuf(ProtobufError), /// This variant includes everything related to (de)serialization of incoming and outgoing /// messages. Serialization(SerializationError), /// This variant includes any error that comes from OpenSSL. Ssl(SslError), } impl Display for Error { fn fmt(&self, f: &mut Formatter) -> Result { match *self { Error::Internal(ref message) => f.write_str(message), Error::Io(ref err) => Display::fmt(&err, f), Error::Protobuf(ref err) => Display::fmt(&err, f), Error::Serialization(ref err) => Display::fmt(&err, f), Error::Ssl(ref err) => Display::fmt(&err, f), } } } impl StdError for Error { fn source(&self) -> Option<&(dyn StdError + 'static)> { match *self { Error::Io(ref err) => Some(err), Error::Protobuf(ref err) => Some(err), Error::Ssl(ref err) => Some(err), Error::Serialization(ref err) => Some(err), Error::Internal(_) => None, } } } impl From for Error { fn from(err: IoError) -> Error { Error::Io(err) } } impl From for Error { fn from(err: ProtobufError) -> Error { Error::Protobuf(err) } } impl From for Error { fn from(err: SerializationError) -> Error { Error::Serialization(err) } } impl From for Error { fn from(err: ErrorStack) -> Error { Error::Ssl(SslError::Generic(err)) } } impl From> for Error { fn from(err: HandshakeError) -> Error { Error::Ssl(SslError::Handshake(err)) } } rust_cast-0.17.0/src/lib.rs000064400000000000000000000200410072674642500136500ustar 00000000000000#![doc(html_root_url = "https://azasypkin.github.io/rust-cast/")] extern crate byteorder; #[macro_use] extern crate log; extern crate openssl; extern crate protobuf; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; mod cast; pub mod channels; pub mod errors; pub mod message_manager; mod utils; use std::borrow::Cow; use std::net::TcpStream; use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode}; use channels::connection::{ConnectionChannel, ConnectionResponse}; use channels::heartbeat::{HeartbeatChannel, HeartbeatResponse}; use channels::media::{MediaChannel, MediaResponse}; use channels::receiver::{ReceiverChannel, ReceiverResponse}; use errors::Error; use message_manager::{CastMessage, MessageManager}; const DEFAULT_SENDER_ID: &str = "sender-0"; const DEFAULT_RECEIVER_ID: &str = "receiver-0"; #[cfg(feature = "thread_safe")] type Lrc = std::sync::Arc; #[cfg(not(feature = "thread_safe"))] type Lrc = std::rc::Rc; /// Supported channel message types. #[derive(Clone, Debug)] pub enum ChannelMessage { /// Message to be processed by `ConnectionChannel`. Connection(ConnectionResponse), /// Message to be processed by `HeartbeatChannel`. Heartbeat(HeartbeatResponse), /// Message to be processed by `MediaChannel`. Media(MediaResponse), /// Message to be processed by `ReceiverChannel`. Receiver(ReceiverResponse), /// Raw message is returned when built-in channels can't process it (e.g. because of unknown /// `namespace`). Raw(CastMessage), } /// Structure that manages connection to a cast device. pub struct CastDevice<'a> { message_manager: Lrc>>, /// Channel that manages connection responses/requests. pub connection: ConnectionChannel<'a, SslStream>, /// Channel that allows connection to stay alive (via ping-pong requests/responses). pub heartbeat: HeartbeatChannel<'a, SslStream>, /// Channel that manages various media stuff. pub media: MediaChannel<'a, SslStream>, /// Channel that manages receiving platform (e.g. Chromecast). pub receiver: ReceiverChannel<'a, SslStream>, } impl<'a> CastDevice<'a> { /// Connects to the cast device using host name and port. /// /// # Examples /// /// ```no_run /// use rust_cast::CastDevice; /// /// let device = CastDevice::connect("192.168.1.2", 8009)?; /// # Ok::<(), rust_cast::errors::Error>(()) /// ``` /// /// # Arguments /// /// * `host` - Cast device host name. /// * `port` - Cast device port number. /// /// # Errors /// /// This method may fail if connection to Cast device can't be established for some reason /// (e.g. wrong host name or port). /// /// # Return value /// /// Instance of `CastDevice` that allows you to manage connection. pub fn connect(host: S, port: u16) -> Result, Error> where S: Into>, { let host = host.into(); debug!( "Establishing connection with cast device at {}:{}...", host, port ); let connector = SslConnector::builder(SslMethod::tls())?.build(); let tcp_stream = TcpStream::connect((host.as_ref(), port))?; CastDevice::connect_to_device(connector.connect(host.as_ref(), tcp_stream)?) } /// Connects to the cast device using host name and port _without_ host verification. Use on /// your own risk! /// /// # Examples /// /// ```no_run /// use rust_cast::CastDevice; /// /// let device = CastDevice::connect_without_host_verification("192.168.1.2", 8009)?; /// # Ok::<(), rust_cast::errors::Error>(()) /// ``` /// /// # Arguments /// /// * `host` - Cast device host name. /// * `port` - Cast device port number. /// /// # Errors /// /// This method may fail if connection to Cast device can't be established for some reason /// (e.g. wrong host name or port). /// /// # Return value /// /// Instance of `CastDevice` that allows you to manage connection. pub fn connect_without_host_verification(host: S, port: u16) -> Result, Error> where S: Into>, { let host = host.into(); debug!( "Establishing non-verified connection with cast device at {}:{}...", host, port ); let mut builder = SslConnector::builder(SslMethod::tls())?; builder.set_verify(SslVerifyMode::NONE); let connector = builder.build(); let tcp_stream = TcpStream::connect((host.as_ref(), port))?; debug!( "Connection with {}:{} successfully established.", host, port ); CastDevice::connect_to_device(connector.connect(host.as_ref(), tcp_stream)?) } /// Waits for any message returned by cast device (e.g. Chromecast) and returns its parsed /// version. /// /// # Examples /// /// ```no_run /// use rust_cast::ChannelMessage; /// /// # use rust_cast::CastDevice; /// # let cast_device = CastDevice::connect_without_host_verification("192.168.1.2", 8009)?; /// /// match cast_device.receive() { /// Ok(ChannelMessage::Connection(res)) => log::debug!("Connection message: {:?}", res), /// Ok(ChannelMessage::Heartbeat(_)) => cast_device.heartbeat.pong()?, /// Ok(_) => {}, /// Err(err) => log::error!("Error occurred while receiving message {}", err) /// } /// # Ok::<(), rust_cast::errors::Error>(()) /// ``` /// /// # Errors /// /// Usually fails if message returned by device can't be parsed. /// /// # Returned values /// /// Parsed channel message. pub fn receive(&self) -> Result { let cast_message = self.message_manager.receive()?; if self.connection.can_handle(&cast_message) { return Ok(ChannelMessage::Connection( self.connection.parse(&cast_message)?, )); } if self.heartbeat.can_handle(&cast_message) { return Ok(ChannelMessage::Heartbeat( self.heartbeat.parse(&cast_message)?, )); } if self.media.can_handle(&cast_message) { return Ok(ChannelMessage::Media(self.media.parse(&cast_message)?)); } if self.receiver.can_handle(&cast_message) { return Ok(ChannelMessage::Receiver( self.receiver.parse(&cast_message)?, )); } Ok(ChannelMessage::Raw(cast_message)) } /// Connects to the cast device using provided ssl stream. /// /// # Arguments /// /// * `ssl_stream` - SSL Stream for the TCP connection established with the device. /// /// # Return value /// /// Instance of `CastDevice` that allows you to manage connection. fn connect_to_device(ssl_stream: SslStream) -> Result, Error> { let message_manager_rc = Lrc::new(MessageManager::new(ssl_stream)); let heartbeat = HeartbeatChannel::new( DEFAULT_SENDER_ID, DEFAULT_RECEIVER_ID, Lrc::clone(&message_manager_rc), ); let connection = ConnectionChannel::new(DEFAULT_SENDER_ID, Lrc::clone(&message_manager_rc)); let receiver = ReceiverChannel::new( DEFAULT_SENDER_ID, DEFAULT_RECEIVER_ID, Lrc::clone(&message_manager_rc), ); let media = MediaChannel::new(DEFAULT_SENDER_ID, Lrc::clone(&message_manager_rc)); Ok(CastDevice { message_manager: message_manager_rc, heartbeat, connection, receiver, media, }) } } #[cfg(test)] pub(crate) mod tests { #[test] #[cfg(feature = "thread_safe")] fn test_thread_safe() { use crate::CastDevice; fn is_sync() {} fn is_send() {} is_sync::(); is_send::(); } } rust_cast-0.17.0/src/message_manager.rs000064400000000000000000000223510072674642500162260ustar 00000000000000use std::{ io::{Read, Write}, ops::{Deref, DerefMut}, }; use crate::{cast::cast_channel, errors::Error, utils}; struct Lock( #[cfg(feature = "thread_safe")] std::sync::Mutex, #[cfg(not(feature = "thread_safe"))] std::cell::RefCell, ); struct LockGuard<'a, T>( #[cfg(feature = "thread_safe")] std::sync::MutexGuard<'a, T>, #[cfg(not(feature = "thread_safe"))] std::cell::Ref<'a, T>, ); impl<'a, T> Deref for LockGuard<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { self.0.deref() } } struct LockGuardMut<'a, T>( #[cfg(feature = "thread_safe")] std::sync::MutexGuard<'a, T>, #[cfg(not(feature = "thread_safe"))] std::cell::RefMut<'a, T>, ); impl<'a, T> Deref for LockGuardMut<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { self.0.deref() } } impl<'a, T> DerefMut for LockGuardMut<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.0.deref_mut() } } impl Lock { fn new(data: T) -> Self { Lock({ #[cfg(feature = "thread_safe")] let lock = std::sync::Mutex::new(data); #[cfg(not(feature = "thread_safe"))] let lock = std::cell::RefCell::new(data); lock }) } fn borrow(&self) -> LockGuard<'_, T> { LockGuard({ #[cfg(feature = "thread_safe")] let guard = self.0.lock().unwrap(); #[cfg(not(feature = "thread_safe"))] let guard = self.0.borrow(); guard }) } fn borrow_mut(&self) -> LockGuardMut<'_, T> { LockGuardMut({ #[cfg(feature = "thread_safe")] let guard = self.0.lock().unwrap(); #[cfg(not(feature = "thread_safe"))] let guard = self.0.borrow_mut(); guard }) } } /// Type of the payload that `CastMessage` can have. #[derive(Debug, Clone)] pub enum CastMessagePayload { /// Payload represented by UTF-8 string (usually it's just a JSON string). String(String), /// Payload represented by binary data. Binary(Vec), } /// Base structure that represents messages that are exchanged between Receiver and Sender. #[derive(Debug, Clone)] pub struct CastMessage { /// A namespace is a labeled protocol. That is, messages that are exchanged throughout the /// Cast ecosystem utilize namespaces to identify the protocol of the message being sent. pub namespace: String, /// Unique identifier of the `sender` application. pub source: String, /// Unique identifier of the `receiver` application. pub destination: String, /// Payload data attached to the message (either string or binary). pub payload: CastMessagePayload, } /// Static structure that is responsible for (de)serializing and sending/receiving Cast protocol /// messages. pub struct MessageManager where S: Write + Read, { message_buffer: Lock>, stream: Lock, request_counter: Lock, } impl MessageManager where S: Write + Read, { pub fn new(stream: S) -> Self { MessageManager { stream: Lock::new(stream), message_buffer: Lock::new(vec![]), request_counter: Lock::new(1), } } /// Sends `message` to the Cast Device. /// /// # Arguments /// /// * `message` - `CastMessage` instance to be sent to the Cast Device. pub fn send(&self, message: CastMessage) -> Result<(), Error> { let mut raw_message = cast_channel::CastMessage::new(); raw_message.set_protocol_version(cast_channel::CastMessage_ProtocolVersion::CASTV2_1_0); raw_message.set_namespace(message.namespace); raw_message.set_source_id(message.source); raw_message.set_destination_id(message.destination); match message.payload { CastMessagePayload::String(payload) => { raw_message.set_payload_type(cast_channel::CastMessage_PayloadType::STRING); raw_message.set_payload_utf8(payload); } CastMessagePayload::Binary(payload) => { raw_message.set_payload_type(cast_channel::CastMessage_PayloadType::BINARY); raw_message.set_payload_binary(payload); } }; let message_content_buffer = utils::to_vec(&raw_message)?; let message_length_buffer = utils::write_u32_to_buffer(message_content_buffer.len() as u32)?; let writer = &mut *self.stream.borrow_mut(); writer.write_all(&message_length_buffer)?; writer.write_all(&message_content_buffer)?; debug!("Message sent: {:?}", raw_message); Ok(()) } /// Waits for the next `CastMessage` available. Can also return existing message from the /// internal message buffer containing messages that have been received previously, but haven't /// been consumed for some reason (e.g. during `receive_find_map` call). /// /// # Return value /// /// `Result` containing parsed `CastMessage` or `Error`. pub fn receive(&self) -> Result { let mut message_buffer = self.message_buffer.borrow_mut(); // If we have messages in the buffer, let's return them from it. if message_buffer.is_empty() { self.read() } else { Ok(message_buffer.remove(0)) } } /// Waits for the next `CastMessage` for which `f` returns valid mapped value. Messages in which /// `f` is not interested are placed into internal message buffer and can be later retrieved /// with `receive`. This method always reads from the stream. /// /// # Example /// /// ```no_run /// # use std::net::TcpStream; /// # use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode}; /// # use rust_cast::message_manager::{CastMessage, MessageManager}; /// # let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); /// # let tcp_stream = TcpStream::connect(("0", 8009)).unwrap(); /// # let ssl_stream = connector.connect("0", tcp_stream).unwrap(); /// # let message_manager = MessageManager::new(ssl_stream); /// # fn can_handle(message: &CastMessage) -> bool { unimplemented!() } /// # fn parse(message: &CastMessage) { unimplemented!() } /// message_manager.receive_find_map(|message| { /// if !can_handle(message) { /// return Ok(None); /// } /// /// parse(message); /// /// Ok(Some(())) /// })?; /// # Ok::<(), rust_cast::errors::Error>(()) /// ``` /// /// # Arguments /// /// * `f` - Function that analyzes and maps `CastMessage` to any other type. If message doesn't /// look like something `f` is looking for, then `Ok(None)` should be returned so that message /// is not lost and placed into internal message buffer for later retrieval. /// /// # Return value /// /// `Result` containing parsed `CastMessage` or `Error`. pub fn receive_find_map(&self, f: F) -> Result where F: Fn(&CastMessage) -> Result, Error>, { loop { let message = self.read()?; // If message is found, just return mapped result, otherwise keep unprocessed message // in the buffer, it can be later retrieved with `receive`. match f(&message)? { Some(r) => return Ok(r), None => self.message_buffer.borrow_mut().push(message), } } } /// Generates unique integer number that is used in some requests to map them with the response. /// /// # Return value /// /// Unique (in the scope of this particular `MessageManager` instance) integer number. pub fn generate_request_id(&self) -> i32 { let request_id = *self.request_counter.borrow() + 1; *self.request_counter.borrow_mut() = request_id; request_id } /// Reads next `CastMessage` from the stream. /// /// # Return value /// /// `Result` containing parsed `CastMessage` or `Error`. fn read(&self) -> Result { let mut buffer: [u8; 4] = [0; 4]; let reader = &mut *self.stream.borrow_mut(); reader.read_exact(&mut buffer)?; let length = utils::read_u32_from_buffer(&buffer)?; let mut buffer: Vec = Vec::with_capacity(length as usize); let mut limited_reader = reader.take(u64::from(length)); limited_reader.read_to_end(&mut buffer)?; let raw_message = utils::from_vec::(buffer.to_vec())?; debug!("Message received: {:?}", raw_message); Ok(CastMessage { namespace: raw_message.get_namespace().to_string(), source: raw_message.get_source_id().to_string(), destination: raw_message.get_destination_id().to_string(), payload: match raw_message.get_payload_type() { cast_channel::CastMessage_PayloadType::STRING => { CastMessagePayload::String(raw_message.get_payload_utf8().to_string()) } cast_channel::CastMessage_PayloadType::BINARY => { CastMessagePayload::Binary(raw_message.get_payload_binary().to_owned()) } }, }) } } rust_cast-0.17.0/src/utils.rs000064400000000000000000000013350072674642500142470ustar 00000000000000use crate::errors::Error; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::Cursor; pub fn read_u32_from_buffer(buffer: &[u8]) -> Result { Ok(Cursor::new(buffer).read_u32::()?) } pub fn write_u32_to_buffer(number: u32) -> Result, Error> { let mut buffer = vec![]; buffer.write_u32::(number)?; Ok(buffer) } pub fn to_vec(message: &M) -> Result, Error> { let mut buffer = vec![]; message.write_to_writer(&mut buffer)?; Ok(buffer) } pub fn from_vec(buffer: Vec) -> Result { let mut read_buffer = Cursor::new(buffer); Ok(M::parse_from_reader(&mut read_buffer)?) }