medea_control_api_proto/grpc/
mod.rs

1//! [gRPC]-based [Control API] implementation.
2//!
3//! [gRPC]: https://grpc.io
4//! [Control API]: https://tinyurl.com/yxsqplq7
5
6#[cfg(feature = "client")]
7mod client;
8mod convert;
9#[cfg(feature = "server")]
10mod server;
11
12#[allow(
13    clippy::nursery,
14    clippy::pedantic,
15    clippy::restriction,
16    clippy::style,
17    let_underscore_drop,
18    meta_variable_misuse,
19    missing_copy_implementations,
20    missing_debug_implementations,
21    missing_docs,
22    noop_method_call,
23    semicolon_in_expressions_from_macros,
24    unreachable_pub,
25    unused_extern_crates,
26    unused_import_braces,
27    unused_labels,
28    unused_lifetimes,
29    unused_qualifications,
30    unused_results,
31    variant_size_differences
32)]
33#[rustfmt::skip]
34pub mod api;
35#[allow(
36    clippy::nursery,
37    clippy::pedantic,
38    clippy::restriction,
39    clippy::style,
40    let_underscore_drop,
41    meta_variable_misuse,
42    missing_copy_implementations,
43    missing_debug_implementations,
44    missing_docs,
45    noop_method_call,
46    semicolon_in_expressions_from_macros,
47    unreachable_pub,
48    unused_extern_crates,
49    unused_import_braces,
50    unused_labels,
51    unused_lifetimes,
52    unused_qualifications,
53    unused_results,
54    variant_size_differences
55)]
56#[rustfmt::skip]
57pub mod callback;
58
59use std::str::FromStr;
60
61use derive_more::with_trait::{Display, Error, From, Into};
62use url::Url;
63
64#[doc(inline)]
65pub use self::convert::ProtobufError;
66#[cfg(feature = "client")]
67#[doc(inline)]
68pub use self::{
69    api::control_api_client::ControlApiClient,
70    callback::callback_server::CallbackServer as CallbackApiServer,
71    client::ControlApiClientError,
72};
73#[cfg(feature = "server")]
74#[doc(inline)]
75pub use self::{
76    api::control_api_server::ControlApiServer,
77    callback::callback_client::CallbackClient as CallbackApiClient,
78    server::CallbackApiClientError,
79};
80
81/// URL representing a [gRPC] callback implementing [`CallbackApi`].
82///
83/// [`CallbackApi`]: crate::CallbackApi
84/// [gRPC]: https://grpc.io
85#[derive(Clone, Debug, Display, Eq, Hash, Into, PartialEq)]
86#[display("grpc://{_0}")]
87#[into(String)]
88pub struct CallbackUrl(Url);
89
90impl CallbackUrl {
91    /// Converts this [`CallbackUrl`] into the one with `http://` scheme.
92    #[must_use]
93    pub fn to_http(&self) -> Url {
94        let mut url = self.0.clone();
95        url.set_scheme("http").unwrap_or_else(|()| unreachable!());
96        url
97    }
98}
99
100impl FromStr for CallbackUrl {
101    type Err = CallbackUrlParseError;
102
103    fn from_str(value: &str) -> Result<Self, Self::Err> {
104        let url = Url::parse(value)?;
105        if url.scheme() != "grpc" {
106            return Err(CallbackUrlParseError::WrongScheme);
107        }
108        if url.host().is_none() {
109            return Err(CallbackUrlParseError::MissingHost);
110        }
111        Ok(Self(url))
112    }
113}
114
115/// Error of parsing a [`CallbackUrl`].
116#[derive(Clone, Copy, Debug, Display, Error, From)]
117pub enum CallbackUrlParseError {
118    /// Error of parsing the provided [`Url`].
119    #[display("Invalid URL: {_0}")]
120    UrlParseErr(url::ParseError),
121
122    /// [`Url`] is missing host.
123    #[display("Missing host")]
124    MissingHost,
125
126    /// [`Url`] contains unsupported scheme.
127    #[display("Only `grpc://` scheme is allowed")]
128    WrongScheme,
129}