reach_core/communication/
mod.rs

1// SPDX-FileCopyrightText: 2024-2025 eaon <eaon@posteo.net>
2// SPDX-FileCopyrightText: 2025 Michael Goldenberg <m@mgoldenberg.net>
3// SPDX-License-Identifier: EUPL-1.2
4
5#[cfg(feature = "websocket")]
6use rand_core::CryptoRngCore;
7
8use reach_aliases::*;
9
10#[cfg(feature = "websocket")]
11use crate::RandomFromRng;
12use crate::error;
13
14mod proto {
15    include!(concat!(env!("OUT_DIR"), "/reach.communication.rs"));
16}
17
18#[cfg(all(feature = "reachable", feature = "websocket"))]
19pub mod secrets;
20
21mod traits;
22pub use traits::*;
23
24#[derive(Debug, Clone, Eq, PartialEq)]
25pub struct Communication<T> {
26    pub r#type: T,
27    pub inner: Vec<u8>,
28    pub augmentation: Option<Vec<u8>>,
29}
30
31impl<T> Communication<T>
32where
33    T: CommunicableType,
34{
35    pub fn new(r#type: T) -> Self {
36        Self::from(r#type, vec![], None)
37    }
38
39    #[cfg(feature = "websocket")]
40    pub fn tag(self, csprng: &mut impl CryptoRngCore) -> (Self, Vec<u8>) {
41        let tag = OneSix::random_from_rng(csprng).to_vec();
42        (
43            Self {
44                r#type: self.r#type,
45                inner: self.inner,
46                augmentation: Some(tag.clone()),
47            },
48            tag,
49        )
50    }
51
52    #[cfg(feature = "reachable")]
53    pub fn with_tag(mut self, tag: Vec<u8>) -> Self {
54        self.augmentation.replace(tag);
55        self
56    }
57
58    pub fn with_augmentation(mut self, augmentation: Option<Vec<u8>>) -> Self {
59        self.augmentation = augmentation;
60        self
61    }
62
63    pub fn pad_to(self, length: usize) -> Self {
64        let padding = length.saturating_sub(self.inner.len() + 1);
65
66        Self {
67            r#type: self.r#type,
68            inner: self.inner,
69            augmentation: Some(vec![0; padding]),
70        }
71    }
72
73    pub fn from(r#type: T, inner: Vec<u8>, augmentation: Option<Vec<u8>>) -> Self {
74        Self {
75            r#type,
76            inner,
77            augmentation,
78        }
79    }
80
81    pub fn encode(self) -> Vec<u8> {
82        proto::Communication::from(self).encode_to_vec()
83    }
84
85    pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, error::DecodeError> {
86        Self::try_from(proto::Communication::decode(bytes.as_ref())?)
87    }
88}
89
90impl<T> TryFrom<proto::Communication> for Communication<T>
91where
92    T: CommunicableType,
93{
94    type Error = error::DecodeError;
95
96    fn try_from(value: proto::Communication) -> Result<Self, Self::Error> {
97        Ok(Self::from(
98            T::try_from(value.r#type).map_err(|_| error::DecodeError)?,
99            value.inner,
100            value.augmentation,
101        ))
102    }
103}
104
105impl<T> From<Communication<T>> for proto::Communication
106where
107    T: CommunicableType,
108{
109    fn from(value: Communication<T>) -> Self {
110        proto::Communication {
111            r#type: value.r#type.into(),
112            inner: value.inner,
113            augmentation: value.augmentation,
114        }
115    }
116}
117
118pub struct LocalCommunication {}
119pub struct RemoteCommunication {}