fundamentum_portforwarding_proto_rust/
lib.rs

1//! Rust bindings to Fundamentum portforwarding protocol.
2//! A library that provides a Rust representation of the basic types, interfaces and
3//! other components required to define and interact with portforwarding
4//! defined by [`fundamentum-portforwarding-proto`][repo-proto].
5//!
6//! [repo-proto]: https://bitbucket.org/amotus/fundamentum-portforwarding-proto
7
8pub mod errors;
9/// The rust bindings generated from the protobuf files under `./proto/`.
10///
11/// Mirrors original protobuf top level 'com' namespace.
12pub mod com {
13    /// Mirrors original protobuf namespace at 'com.fundamentum'.
14    ///
15    /// Exposes Fundamentum related protobuf symbols.
16    pub mod fundamentum {
17        /// Mirrors original protobuf namespace at 'com.fundamentum.portforwarding'.
18        ///
19        /// Exposes Fundamentum Portforwarding related protobuf symbols.
20        pub mod portforwarding {
21            pub use v1 as latest;
22            /// Mirrors original protobuf namespace at 'com.fundamentum.portforwarding.v1'.
23            ///
24            /// Exposes Fundamentum Portforwarding related protobuf symbols as of version 1
25            /// or the services.
26            pub mod v1 {
27                use crate::Version;
28
29                include!(concat!(
30                    env!("OUT_DIR"),
31                    "/com.fundamentum.portforwarding.v1.rs"
32                ));
33
34                /// Get current version
35                pub fn get_version() -> Version {
36                    Version::V1
37                }
38            }
39        }
40    }
41}
42use com::fundamentum::portforwarding::v1;
43use derive_new::new;
44use enum_tags::Tag;
45pub use enum_tags_traits::TaggedEnum;
46pub use errors::Error;
47use prost::Message;
48use serde::{Deserialize, Serialize};
49use std::{
50    fmt::{self, Display},
51    str::FromStr,
52};
53use uuid::Uuid;
54
55#[derive(PartialEq, Eq, Debug, new, Clone, Copy)]
56pub struct TargetPort(pub u32);
57
58impl Display for TargetPort {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        write!(f, "{}", self.0)
61    }
62}
63
64#[derive(PartialEq, Eq, Debug, new, Serialize, Deserialize, Clone, Copy)]
65pub struct ProxyPort(pub u32);
66
67impl Display for ProxyPort {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(f, "{}", self.0)
70    }
71}
72
73/// Protocol version
74#[derive(Debug, Clone)]
75pub enum Version {
76    V1,
77}
78
79impl Version {
80    pub fn get_latest() -> Self {
81        com::fundamentum::portforwarding::latest::get_version()
82    }
83}
84
85impl FromStr for Version {
86    type Err = errors::Error;
87
88    fn from_str(input: &str) -> Result<Version, Self::Err> {
89        match input {
90            "1" => Ok(Version::V1),
91            _ => Err(errors::Error::InvalidVersion),
92        }
93    }
94}
95
96impl Display for Version {
97    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98        match self {
99            Version::V1 => write!(f, "1"),
100        }
101    }
102}
103
104#[derive(Clone, new)]
105pub struct PortForwardingMsg {
106    pub instance_id: Uuid,
107    pub operation: PortforwardingOperation,
108    pub version: Version,
109}
110
111/// Layer that represent portforwarding device message with good typing
112#[derive(Clone, Debug, PartialEq, Eq, Tag)]
113pub enum PortforwardingOperation {
114    Handshake,
115    TransferData(TransferData),
116    Error(ErrorOperation),
117    Status(Status),
118    OpenConnection(OpenConnection),
119    CloseConnection,
120}
121
122#[derive(Clone, Debug, PartialEq, Eq)]
123pub struct TransferData {
124    pub payload: Vec<u8>,
125}
126
127#[derive(Clone, Debug, PartialEq, Eq)]
128pub struct ErrorOperation {
129    pub code: i32,
130    pub message: String,
131}
132
133#[derive(Clone, Debug, PartialEq, Eq)]
134pub struct OpenConnection {
135    pub target_port: TargetPort,
136}
137
138/// Represent each possible status
139#[derive(PartialEq, Eq, Clone, Debug)]
140pub enum Status {
141    ConnectionEstablished,
142}
143
144impl PortforwardingOperation {
145    /// Close a connection payload
146    #[must_use]
147    pub const fn new_close_connection() -> Self {
148        Self::CloseConnection
149    }
150
151    /// generate open connection message
152    #[must_use]
153    pub const fn new_open_connection(port: TargetPort) -> Self {
154        Self::OpenConnection(OpenConnection { target_port: port })
155    }
156
157    /// generate transfer data message
158    #[must_use]
159    pub const fn new_transfer_data(payload: Vec<u8>) -> Self {
160        Self::TransferData(TransferData { payload })
161    }
162
163    /// generate transfer data message
164    #[must_use]
165    pub const fn new_connection_established() -> Self {
166        Self::Status(Status::ConnectionEstablished)
167    }
168
169    pub fn encode(self, version: &Version) -> Vec<u8> {
170        match version {
171            Version::V1 => match self {
172                Self::TransferData(transfer_data_msg) => v1::TransferData {
173                    payload: transfer_data_msg.payload,
174                }
175                .encode_to_vec(),
176                Self::Error(error_msg) => v1::Error {
177                    code: error_msg.code,
178                    message: error_msg.message,
179                }
180                .encode_to_vec(),
181                Self::Status(status) => match status {
182                    Status::ConnectionEstablished => v1::Status {
183                        value: v1::StatusValue::StatusConnectionEstablished.into(),
184                    }
185                    .encode_to_vec(),
186                },
187                Self::OpenConnection(open_connection_msg) => v1::OpenConnection {
188                    target_port: open_connection_msg.target_port.0,
189                }
190                .encode_to_vec(),
191                Self::CloseConnection => v1::CloseConnection {}.encode_to_vec(),
192                Self::Handshake => Vec::new(),
193            },
194        }
195    }
196
197    pub fn decode(
198        version: Version,
199        payload: &[u8],
200        operation: PortforwardingOperationTag,
201    ) -> Result<Self, errors::Error> {
202        use PortforwardingOperationTag as Tag;
203
204        if operation == Tag::Handshake {
205            return Ok(Self::Handshake);
206        }
207        match version {
208            Version::V1 => match operation {
209                Tag::OpenConnection => Ok(Self::OpenConnection(OpenConnection {
210                    target_port: TargetPort(v1::OpenConnection::decode(payload)?.target_port),
211                })),
212                Tag::CloseConnection => Ok(Self::CloseConnection),
213                Tag::TransferData => Ok(Self::TransferData(TransferData {
214                    payload: v1::TransferData::decode(payload)?.payload,
215                })),
216                Tag::Error => {
217                    let v1_error = v1::Error::decode(payload)?;
218                    Ok(Self::Error(ErrorOperation {
219                        code: v1_error.code,
220                        message: v1_error.message,
221                    }))
222                }
223                Tag::Status => {
224                    let v1_status = v1::Status::decode(payload)?;
225                    Ok(Self::Status(match v1_status.value() {
226                        v1::StatusValue::StatusConnectionEstablished => {
227                            Status::ConnectionEstablished
228                        }
229                        _ => return Err(errors::Error::InvalidStatus),
230                    }))
231                }
232                _ => Err(errors::Error::InvalidOperation),
233            },
234        }
235    }
236}
237
238impl fmt::Display for PortforwardingOperationTag {
239    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240        match self {
241            Self::CloseConnection => write!(f, "close"),
242            Self::OpenConnection => write!(f, "open"),
243            Self::TransferData => write!(f, "tx"),
244            Self::Handshake => write!(f, "hsk"),
245            Self::Error => write!(f, "error"),
246            Self::Status => write!(f, "status"),
247        }
248    }
249}
250
251impl FromStr for PortforwardingOperationTag {
252    type Err = errors::Error;
253
254    fn from_str(s: &str) -> Result<Self, Self::Err> {
255        match s {
256            "error" => Ok(Self::Error),
257            "status" => Ok(Self::Status),
258            "close" => Ok(Self::CloseConnection),
259            "open" => Ok(Self::OpenConnection),
260            "hsk" => Ok(Self::Handshake),
261            "tx" => Ok(Self::TransferData),
262            _ => Err(errors::Error::InvalidOperation),
263        }
264    }
265}