Skip to content

Commit

Permalink
Introduced NewTypes for name, description, tags
Browse files Browse the repository at this point in the history
Introduced NewTypes due to be consistent over our code base.
  • Loading branch information
mtwardawski committed Jan 30, 2024
1 parent 3b32509 commit 57cbb67
Show file tree
Hide file tree
Showing 5 changed files with 437 additions and 128 deletions.
18 changes: 15 additions & 3 deletions opendut-types/proto/opendut/types/topology/device.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ message DeviceId {

message DeviceDescriptor {
opendut.types.topology.DeviceId id = 1;
string name = 2;
string description = 3;
opendut.types.topology.DeviceName name = 2;
opendut.types.topology.DeviceDescription description = 3;
opendut.types.util.NetworkInterfaceName interface = 4;
repeated string tags = 5;
repeated opendut.types.topology.DeviceTag tags = 5;
}

message DeviceName {
string value = 1;
}

message DeviceDescription {
string value = 1;
}

message DeviceTag {
string value = 1;
}
127 changes: 72 additions & 55 deletions opendut-types/src/peer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::fmt;
use std::io::{Read, Write};
use std::ops::Not;

use base64::Engine;
use base64::prelude::BASE64_URL_SAFE;
use base64::Engine;
use serde::{Deserialize, Serialize};
use url::Url;
use uuid::Uuid;
Expand All @@ -18,7 +18,6 @@ pub mod state;
pub struct PeerId(pub Uuid);

impl PeerId {

pub const NIL: Self = Self(Uuid::from_bytes([0; 16]));

pub fn random() -> Self {
Expand All @@ -45,18 +44,16 @@ pub struct IllegalPeerId {
}

impl TryFrom<&str> for PeerId {

type Error = IllegalPeerId;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Uuid::parse_str(value)
.map(Self)
.map_err(|_| IllegalPeerId { value: String::from(value) })
Uuid::parse_str(value).map(Self).map_err(|_| IllegalPeerId {
value: String::from(value),
})
}
}

impl TryFrom<String> for PeerId {

type Error = IllegalPeerId;

fn try_from(value: String) -> Result<Self, Self::Error> {
Expand All @@ -70,12 +67,10 @@ impl fmt::Display for PeerId {
}
}


#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct PeerName(pub(crate) String);

impl PeerName {

pub const MIN_LENGTH: usize = 4;
pub const MAX_LENGTH: usize = 64;

Expand All @@ -86,10 +81,22 @@ impl PeerName {

#[derive(thiserror::Error, Clone, Debug)]
pub enum IllegalPeerName {
#[error("Peer name '{value}' is too short. Expected at least {expected} characters, got {actual}.")]
TooShort { value: String, expected: usize, actual: usize },
#[error("Peer name '{value}' is too long. Expected at most {expected} characters, got {actual}.")]
TooLong { value: String, expected: usize, actual: usize },
#[error(
"Peer name '{value}' is too short. Expected at least {expected} characters, got {actual}."
)]
TooShort {
value: String,
expected: usize,
actual: usize,
},
#[error(
"Peer name '{value}' is too long. Expected at most {expected} characters, got {actual}."
)]
TooLong {
value: String,
expected: usize,
actual: usize,
},
#[error("Peer name '{value}' contains invalid characters.")]
InvalidCharacter { value: String },
}
Expand All @@ -101,7 +108,6 @@ impl From<PeerName> for String {
}

impl TryFrom<String> for PeerName {

type Error = IllegalPeerName;

fn try_from(value: String) -> Result<Self, Self::Error> {
Expand All @@ -112,27 +118,25 @@ impl TryFrom<String> for PeerName {
expected: Self::MIN_LENGTH,
actual: length,
})
}
else if length > Self::MAX_LENGTH {
} else if length > Self::MAX_LENGTH {
Err(IllegalPeerName::TooLong {
value,
expected: Self::MAX_LENGTH,
actual: length,
})
} else if crate::util::valid_start_and_end_of_a_name(&value).not()
|| value.chars().any(|c| crate::util::valid_characters_in_name(&c).not()) {
Err(IllegalPeerName::InvalidCharacter {
value
})
}
else {
|| value
.chars()
.any(|c| crate::util::valid_characters_in_name(&c).not())
{
Err(IllegalPeerName::InvalidCharacter { value })
} else {
Ok(Self(value))
}
}
}

impl TryFrom<&str> for PeerName {

type Error = IllegalPeerName;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Expand All @@ -150,21 +154,26 @@ impl fmt::Display for PeerName {
pub struct PeerLocation(pub(crate) String);

impl PeerLocation {

pub const MIN_LENGTH: usize = 0;
pub const MAX_LENGTH: usize = 64;

pub fn value(self) -> String {
self.0
}

pub fn new(location: &str) -> PeerLocation { Self { 0: String::from(location) } }
pub fn new(location: &str) -> PeerLocation {
todo!("delete new function")
}
}

#[derive(thiserror::Error, Clone, Debug)]
pub enum IllegalLocation {
#[error("Peer location '{value}' is too long. Expected at most {expected} characters, got {actual}.")]
TooLong { value: String, expected: usize, actual: usize },
TooLong {
value: String,
expected: usize,
actual: usize,
},
#[error("Peer location '{value}' contains invalid characters.")]
InvalidCharacter { value: String },
#[error("Peer location '{value}' contains invalid start or end characters.")]
Expand All @@ -178,7 +187,6 @@ impl From<PeerLocation> for String {
}

impl TryFrom<String> for PeerLocation {

type Error = IllegalLocation;

fn try_from(value: String) -> Result<Self, Self::Error> {
Expand All @@ -190,22 +198,19 @@ impl TryFrom<String> for PeerLocation {
actual: length,
})
} else if crate::util::valid_start_and_end_of_location(&value).not() {
Err(IllegalLocation::InvalidStartEndCharacter {
value
})
} else if value.chars().any(|c| crate::util::valid_characters_in_location(&c).not()) {
Err(IllegalLocation::InvalidCharacter {
value
})
}
else {
Err(IllegalLocation::InvalidStartEndCharacter { value })
} else if value
.chars()
.any(|c| crate::util::valid_characters_in_location(&c).not())
{
Err(IllegalLocation::InvalidCharacter { value })
} else {
Ok(Self(value))
}
}
}

impl TryFrom<&str> for PeerLocation {

type Error = IllegalLocation;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Expand Down Expand Up @@ -235,17 +240,18 @@ pub struct PeerSetup {
}

impl PeerSetup {

pub fn encode(&self) -> Result<String, PeerSetupEncodeError> {

let json = serde_json::to_string(self)
.map_err(|cause| PeerSetupEncodeError { details: format!("Serialization failed due to: {}", cause) })?;
let json = serde_json::to_string(self).map_err(|cause| PeerSetupEncodeError {
details: format!("Serialization failed due to: {}", cause),
})?;

let compressed = {
let mut buffer = Vec::new();
brotli::CompressorReader::new(json.as_bytes(), 4096, 11, 20)
.read_to_end(&mut buffer)
.map_err(|cause| PeerSetupEncodeError { details: format!("Compression failed due to: {}", cause) } )?;
.map_err(|cause| PeerSetupEncodeError {
details: format!("Compression failed due to: {}", cause),
})?;
buffer
};

Expand All @@ -255,32 +261,41 @@ impl PeerSetup {
}

pub fn decode(encoded: &str) -> Result<Self, PeerSetupDecodeError> {

let compressed = BASE64_URL_SAFE.decode(encoded.as_bytes())
.map_err(|cause| PeerSetupDecodeError { details: format!("Base64 decoding failed due to: {}", cause) } )?;
let compressed = BASE64_URL_SAFE
.decode(encoded.as_bytes())
.map_err(|cause| PeerSetupDecodeError {
details: format!("Base64 decoding failed due to: {}", cause),
})?;

let json = {
let mut buffer = Vec::new();
brotli::DecompressorWriter::new(&mut buffer, 4096)
.write_all(compressed.as_slice())
.map_err(|cause| PeerSetupDecodeError { details: format!("Decompression failed due to: {}", cause) } )?;
.map_err(|cause| PeerSetupDecodeError {
details: format!("Decompression failed due to: {}", cause),
})?;
buffer
};

let decoded = serde_json::from_slice(&json)
.map_err(|cause| PeerSetupDecodeError { details: format!("Deserialization failed due to: {}", cause) })?;
let decoded = serde_json::from_slice(&json).map_err(|cause| PeerSetupDecodeError {
details: format!("Deserialization failed due to: {}", cause),
})?;

Ok(decoded)
}
}

#[derive(thiserror::Error, Debug)]
#[error("PeerSetup could not be encoded. {details}")]
pub struct PeerSetupEncodeError { details: String }
pub struct PeerSetupEncodeError {
details: String,
}

#[derive(thiserror::Error, Debug)]
#[error("PeerSetup could not be decoded. {details}")]
pub struct PeerSetupDecodeError { details: String }
pub struct PeerSetupDecodeError {
details: String,
}

#[cfg(test)]
#[allow(non_snake_case)]
Expand All @@ -294,14 +309,13 @@ mod tests {

#[test]
fn A_PeerSetup_should_be_encodable() -> Result<()> {

let setup = PeerSetup {
id: PeerId::try_from("01bf3f8c-cc7c-4114-9520-91bce71dcead").unwrap(),
carl: Url::parse("https://carl.opendut.local")?,
vpn: VpnPeerConfig::Netbird {
management_url: Url::parse("https://netbird.opendut.local/api")?,
setup_key: SetupKey::from(Uuid::parse_str("d79c202f-bbbf-4997-844e-678f27606e1c")?),
}
},
};

let encoded = setup.encode()?;
Expand All @@ -315,21 +329,24 @@ mod tests {

#[test]
fn A_PeerName_should_contain_valid_characters() -> Result<()> {
let peer_name = PeerName::try_from("asd123".to_string()).expect("Failed to create peer name");
let peer_name =
PeerName::try_from("asd123".to_string()).expect("Failed to create peer name");
assert_eq!(peer_name.0, "asd123");
Ok(())
}

#[test]
fn A_PeerName_may_contain_a_hyphen() -> Result<()> {
let peer_name = PeerName::try_from("asd-123".to_string()).expect("Failed to create peer name");
let peer_name =
PeerName::try_from("asd-123".to_string()).expect("Failed to create peer name");
assert_eq!(peer_name.0, "asd-123");
Ok(())
}

#[test]
fn A_PeerName_may_contain_an_underscore() -> Result<()> {
let peer_name = PeerName::try_from("asd-123".to_string()).expect("Failed to create peer name");
let peer_name =
PeerName::try_from("asd-123".to_string()).expect("Failed to create peer name");
assert_eq!(peer_name.0, "asd-123");
Ok(())
}
Expand Down
Loading

0 comments on commit 57cbb67

Please sign in to comment.