fundamentum_portforwarding_proto_rust/
lib.rs1pub mod errors;
9pub mod com {
13 pub mod fundamentum {
17 pub mod portforwarding {
21 pub use v1 as latest;
22 pub mod v1 {
27 use crate::Version;
28
29 include!(concat!(
30 env!("OUT_DIR"),
31 "/com.fundamentum.portforwarding.v1.rs"
32 ));
33
34 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#[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#[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: ErrorCode,
130 pub message: String,
131}
132
133#[derive(Clone, Debug, PartialEq, Eq)]
134pub struct Tty {
135 pub cmd: String,
136 pub rows: u32,
137 pub cols: u32,
138}
139
140#[derive(Clone, Debug, PartialEq, Eq)]
141pub enum OpenConnection {
142 Tty(Tty),
143 Port(TargetPort),
144}
145
146#[derive(PartialEq, Eq, Clone, Debug)]
148pub enum Status {
149 ConnectionEstablished,
150}
151
152impl PortforwardingOperation {
153 #[must_use]
155 pub const fn new_error(code: ErrorCode, message: String) -> Self {
156 Self::Error(ErrorOperation { code, message })
157 }
158
159 #[must_use]
161 pub const fn new_close_connection() -> Self {
162 Self::CloseConnection
163 }
164
165 #[must_use]
167 pub const fn new_open_port_connection(port: TargetPort) -> Self {
168 Self::OpenConnection(OpenConnection::Port(port))
169 }
170
171 #[must_use]
173 pub const fn new_open_tty_connection(cmd: String, row: u32, cols: u32) -> Self {
174 Self::OpenConnection(OpenConnection::Tty(Tty {
175 cmd,
176 rows: row,
177 cols,
178 }))
179 }
180
181 #[must_use]
183 pub const fn new_transfer_data(payload: Vec<u8>) -> Self {
184 Self::TransferData(TransferData { payload })
185 }
186
187 #[must_use]
189 pub const fn new_connection_established() -> Self {
190 Self::Status(Status::ConnectionEstablished)
191 }
192
193 pub fn encode(self, version: &Version) -> Vec<u8> {
194 match version {
195 Version::V1 => match self {
196 Self::TransferData(transfer_data_msg) => v1::TransferData {
197 payload: transfer_data_msg.payload,
198 }
199 .encode_to_vec(),
200 Self::Error(error_msg) => v1::Error {
201 code: error_msg.code as i32,
202 message: error_msg.message,
203 }
204 .encode_to_vec(),
205 Self::Status(status) => match status {
206 Status::ConnectionEstablished => v1::Status {
207 value: v1::StatusValue::StatusConnectionEstablished.into(),
208 }
209 .encode_to_vec(),
210 },
211 Self::OpenConnection(open_connection_msg) => v1::OpenConnection {
212 r#type: match open_connection_msg {
213 OpenConnection::Tty(tty) => {
214 Some(v1::open_connection::Type::Tty(v1::open_connection::Tty {
215 cmd: tty.cmd,
216 rows: tty.rows,
217 cols: tty.cols,
218 }))
219 }
220 OpenConnection::Port(port) => {
221 Some(v1::open_connection::Type::TargetPort(port.0))
222 }
223 },
224 }
225 .encode_to_vec(),
226 Self::CloseConnection => v1::CloseConnection {}.encode_to_vec(),
227 Self::Handshake => Vec::new(),
228 },
229 }
230 }
231
232 pub fn decode(
233 version: Version,
234 payload: &[u8],
235 operation: PortforwardingOperationTag,
236 ) -> Result<Self, errors::Error> {
237 use PortforwardingOperationTag as Tag;
238
239 if operation == Tag::Handshake {
240 return Ok(Self::Handshake);
241 }
242 match version {
243 Version::V1 => match operation {
244 Tag::OpenConnection => {
245 let decoded = v1::OpenConnection::decode(payload)?;
246 match decoded.r#type {
247 Some(v1::open_connection::Type::Tty(tty)) => {
248 Ok(Self::OpenConnection(OpenConnection::Tty(Tty {
249 cmd: tty.cmd,
250 rows: tty.rows,
251 cols: tty.cols,
252 })))
253 }
254 Some(v1::open_connection::Type::TargetPort(port)) => {
255 Ok(Self::OpenConnection(OpenConnection::Port(TargetPort(port))))
256 }
257 None => Err(errors::Error::InvalidOperation),
258 }
259 }
260 Tag::CloseConnection => Ok(Self::CloseConnection),
261 Tag::TransferData => Ok(Self::TransferData(TransferData {
262 payload: v1::TransferData::decode(payload)?.payload,
263 })),
264 Tag::Error => {
265 let v1_error = v1::Error::decode(payload)?;
266 Ok(Self::Error(ErrorOperation {
267 code: ErrorCode::from(v1_error.code),
268 message: v1_error.message,
269 }))
270 }
271 Tag::Status => {
272 let v1_status = v1::Status::decode(payload)?;
273 Ok(Self::Status(match v1_status.value() {
274 v1::StatusValue::StatusConnectionEstablished => {
275 Status::ConnectionEstablished
276 }
277 _ => return Err(errors::Error::InvalidStatus),
278 }))
279 }
280 _ => Err(errors::Error::InvalidOperation),
281 },
282 }
283 }
284}
285
286impl fmt::Display for PortforwardingOperationTag {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 match self {
289 Self::CloseConnection => write!(f, "close"),
290 Self::OpenConnection => write!(f, "open"),
291 Self::TransferData => write!(f, "tx"),
292 Self::Handshake => write!(f, "hsk"),
293 Self::Error => write!(f, "error"),
294 Self::Status => write!(f, "status"),
295 }
296 }
297}
298
299impl FromStr for PortforwardingOperationTag {
300 type Err = errors::Error;
301
302 fn from_str(s: &str) -> Result<Self, Self::Err> {
303 match s {
304 "error" => Ok(Self::Error),
305 "status" => Ok(Self::Status),
306 "close" => Ok(Self::CloseConnection),
307 "open" => Ok(Self::OpenConnection),
308 "hsk" => Ok(Self::Handshake),
309 "tx" => Ok(Self::TransferData),
310 _ => Err(errors::Error::InvalidOperation),
311 }
312 }
313}
314
315#[derive(Clone, Debug, PartialEq, Eq)]
316pub enum ErrorCode {
317 Unknown = 0,
319 InstanceNotFound = 1,
321 InstanceCorrupted = 2,
324 SpawnTty = 3,
326 SpawnTcp = 4,
328 HeaderParsing = 5,
330 InvalidRowsColsValueForTty = 6,
332 InvalidPort = 7,
334 WriteDataToServer = 8,
336 UnsupportedPlatform = 9,
338 UnexpectedOperation = 10,
340 ResizeTty = 11,
342 SpawnTtyCommand = 12,
344}
345
346impl std::convert::From<i32> for ErrorCode {
347 fn from(value: i32) -> Self {
348 match value {
349 0 => ErrorCode::Unknown,
350 1 => ErrorCode::InstanceNotFound,
351 2 => ErrorCode::InstanceCorrupted,
352 3 => ErrorCode::SpawnTty,
353 4 => ErrorCode::SpawnTcp,
354 5 => ErrorCode::HeaderParsing,
355 6 => ErrorCode::InvalidRowsColsValueForTty,
356 7 => ErrorCode::InvalidPort,
357 8 => ErrorCode::WriteDataToServer,
358 9 => ErrorCode::UnsupportedPlatform,
359 10 => ErrorCode::UnexpectedOperation,
360 11 => ErrorCode::ResizeTty,
361 12 => ErrorCode::SpawnTtyCommand,
362 _ => ErrorCode::Unknown,
363 }
364 }
365}