Skip to main content

inet2_addr/
server.rs

1// Internet2 addresses with support for Tor v3
2//
3// Written in 2019-2022 by
4//     Dr. Maxim Orlovsky <orlovsky@lnp-bp.org>
5//     Martin Habovstiak <martin.habovstiak@gmail.com>
6//
7// To the extent possible under law, the author(s) have dedicated all copyright
8// and related and neighboring rights to this software to the public domain
9// worldwide. This software is distributed without any warranty.
10//
11// You should have received a copy of the MIT License along with this software.
12// If not, see <https://opensource.org/licenses/MIT>.
13
14#![allow(clippy::init_numbered_fields)]
15
16use std::net::{self, SocketAddr};
17use std::str::FromStr;
18
19use crate::node::NodeAddrParseError;
20use crate::{AddrParseError, InetSocketAddr, NodeAddr};
21
22/// Errors parsing [`ServerAddr`] string representation
23#[derive(Debug, Display, Error, From)]
24#[display(doc_comments)]
25pub enum ServerAddrParseError {
26    /// Invalid node address
27    #[from]
28    #[display(inner)]
29    InvalidNode(NodeAddrParseError),
30
31    /// Invalid internet socket address
32    #[from]
33    #[display(inner)]
34    InvalidAddr(AddrParseError),
35
36    /// invalid server address string '{0}'
37    Unrecognized(String),
38}
39
40/// Server address representing connection to a remote or a local server over
41/// ZMQ protocol.
42#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)]
43#[cfg_attr(feature = "strict_encoding", derive(StrictEncode, StrictDecode))]
44#[cfg_attr(
45    feature = "serde",
46    derive(Serialize, Deserialize),
47    serde(crate = "serde_crate")
48)]
49pub enum ServerAddr {
50    /// Encrypted connection over TCP
51    #[display("{0}", alt = "bronze://{0}")]
52    #[from]
53    Bronze(NodeAddr),
54
55    /// Unencrypted connection over TCP
56    #[display("{0}", alt = "tcp://{0}")]
57    #[from]
58    Tcp(InetSocketAddr),
59
60    /// Local IPC connection
61    #[display("{0}", alt = "ipc://{0}")]
62    #[from]
63    Ipc(String),
64}
65
66impl FromStr for ServerAddr {
67    type Err = ServerAddrParseError;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        let mut split = s.split("://");
71        Ok(match (split.next(), split.next(), split.next()) {
72            (Some("bronze"), Some(s), None) => NodeAddr::from_str(s)?.into(),
73            (Some("tcp"), Some(s), None) => InetSocketAddr::from_str(s)?.into(),
74            (Some("ipc"), Some(s), None) => ServerAddr::Ipc(s.to_owned()),
75            (Some(s), None, _) => NodeAddr::from_str(s)
76                .map(ServerAddr::from)
77                .map_err(ServerAddrParseError::from)
78                .or_else(|_| {
79                    InetSocketAddr::from_str(s)
80                        .map(ServerAddr::from)
81                        .map_err(ServerAddrParseError::from)
82                })
83                .unwrap_or_else(|_| ServerAddr::Ipc(s.to_owned())),
84            _ => return Err(ServerAddrParseError::Unrecognized(s.to_owned())),
85        })
86    }
87}
88
89/// Errors parsing [`ServiceAddr`] string representation
90#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
91#[display(doc_comments)]
92pub enum ServiceAddrParseError {
93    /// Invalid internet socket address
94    #[from]
95    #[display(inner)]
96    InvalidAddr(net::AddrParseError),
97
98    /// invalid server address string '{0}'
99    Unrecognized(String),
100}
101
102/// Address of microservice which may be local or remote; standalone process or
103/// a thread, connectable via ZMQ.
104#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)]
105#[cfg_attr(feature = "strict_encoding", derive(StrictEncode, StrictDecode))]
106#[cfg_attr(
107    feature = "serde",
108    derive(Serialize, Deserialize),
109    serde(crate = "serde_crate")
110)]
111pub enum ServiceAddr {
112    /// Connection via TCP
113    #[display("{0}", alt = "tcp://{0}")]
114    #[from]
115    Tcp(SocketAddr),
116
117    /// Connection via IPC
118    #[display("{0}", alt = "ipc://{0}")]
119    Ipc(String),
120
121    /// In-memory connection
122    #[display("{0}", alt = "inproc://{0}")]
123    Inproc(String),
124}
125
126impl FromStr for ServiceAddr {
127    type Err = ServiceAddrParseError;
128
129    fn from_str(s: &str) -> Result<Self, Self::Err> {
130        let mut split = s.split("://");
131        Ok(match (split.next(), split.next(), split.next()) {
132            (Some("tcp"), Some(s), None) => SocketAddr::from_str(s)?.into(),
133            (Some("ipc"), Some(s), None) => ServiceAddr::Ipc(s.to_owned()),
134            (Some("inproc"), Some(s), None) => {
135                ServiceAddr::Inproc(s.to_owned())
136            }
137            (Some(s), None, _) if s.contains('/') => {
138                ServiceAddr::Ipc(s.to_owned())
139            }
140            (Some(s), None, _) => SocketAddr::from_str(s)
141                .map(ServiceAddr::from)
142                .unwrap_or_else(|_| ServiceAddr::Inproc(s.to_owned())),
143            _ => return Err(ServiceAddrParseError::Unrecognized(s.to_owned())),
144        })
145    }
146}
147
148impl ServiceAddr {
149    /// Returns ZeroMQ connection string
150    pub fn zmq_connect_string(&self) -> String { format!("{self:#}") }
151}