datex_core/datex_values/primitives/
endpoint.rs

1use regex::Regex;
2
3use crate::{utils::{buffers::{self, append_u8, append_u16, read_u8, read_slice, read_u16}, color::Color}};
4
5#[derive(Debug, Clone, PartialEq)]
6pub enum EndpointType {
7	Id,
8	PersonAlias,
9	InstitutionAlias
10}
11
12
13#[derive(Debug, Clone, PartialEq)]
14pub struct Endpoint {
15	name: String,
16	endpoint_type: EndpointType,
17	instance: u16,
18	binary: Vec<u8> // 1 byte type, 18 bytes name, 2 bytes instance
19}
20
21impl Endpoint {
22	
23	pub const ANY_INSTANCE:u16 = 0;
24
25	// create default id endpoint (@@1234567890, @@local)
26	pub fn new(name_binary:&Vec<u8>, instance: u16) -> Endpoint {
27		let mut name = buffers::buffer_to_hex(name_binary.to_vec()); 
28		name = Regex::new(r"(00)*$").unwrap().replace_all(&name, "").to_string();
29		if name == "" { name = "local".to_string() }
30		else if name == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"  { name = "any".to_string() }
31
32		Endpoint {
33			name,
34			endpoint_type: EndpointType::Id,
35			instance,
36			binary: Self::to_binary(EndpointType::Id, name_binary, instance)
37		}
38	}
39
40	// create alias endpoint (@person)
41	pub fn new_person(name:&str, instance: u16) -> Endpoint {
42		Endpoint {
43			name: name.trim_matches(char::from(0)).to_string(),
44			endpoint_type: EndpointType::PersonAlias,
45			instance,
46			binary: Self::to_binary(EndpointType::PersonAlias, &Self::encode_name_binary(name.to_string()), instance)
47		}
48	}
49
50	// create institution endpoint (@+institution)
51	pub fn new_institution(name:&str, instance: u16) -> Endpoint {
52		Endpoint {
53			name: name.trim_matches(char::from(0)).to_string(),
54			endpoint_type: EndpointType::InstitutionAlias,
55			instance,
56			binary: Self::to_binary(EndpointType::InstitutionAlias, &Self::encode_name_binary(name.to_string()), instance)
57		}
58	}
59
60	pub fn new_from_binary(binary:&Vec<u8>) -> Endpoint {
61		let index = &mut 0;
62		let endpoint_type_bin = read_u8(binary, index);
63		let endpoint_type = match endpoint_type_bin {
64			2 => EndpointType::InstitutionAlias,
65			1 => EndpointType::PersonAlias,
66			_ => EndpointType::Id
67		};
68
69		let name = &read_slice(binary, index, 18);
70		let instance = read_u16(binary, index);
71
72		match endpoint_type {
73			EndpointType::InstitutionAlias => Self::new_institution(&Self::decode_name_binary(name), instance),
74			EndpointType::PersonAlias => Self::new_person(&Self::decode_name_binary(name), instance),
75			EndpointType::Id => Self::new(name, instance)
76		}
77
78	}
79
80
81	// convert string name to binary representation
82	fn encode_name_binary(name: String) -> Vec<u8> {
83		if name.len()>18 {
84			panic!("Endpoint name exceeds maximum of 18 bytes");
85		}
86		// TODO: maybe 6 bit charset?
87		return String::into_bytes(name);
88	}
89
90	// convert binary representation with null terminators to string
91	fn decode_name_binary(name_binary: &Vec<u8>) -> String {
92		if name_binary.len()>18 {
93			panic!("Endpoint name exceeds maximum of 18 bytes");
94		}
95
96		let name_utf8 = String::from_utf8(name_binary.to_vec()).expect("could not read endpoint name");
97		// remove \0
98		return name_utf8.trim_matches(char::from(0)).to_string();
99	}
100
101
102	// get the binary representation for an endpoint
103	// 1 byte type, 18 bytes name, 2 bytes instance
104	fn to_binary(endpoint_type: EndpointType, name_binary:&Vec<u8>, instance: u16) -> Vec<u8> {
105		if name_binary.len()>18 { // might include null terminator
106			panic!("Endpoint name exceeds maximum of 18 bytes");
107		}
108		let name_sized = &mut name_binary.to_vec();
109		name_sized.resize(18, 0);
110		let binary = &mut Vec::<u8>::with_capacity(21);
111
112		append_u8(binary, endpoint_type as u8);
113		binary.extend_from_slice(name_sized);
114		append_u16(binary, instance);
115
116		return binary.to_vec()
117	}
118
119
120	pub fn get_binary(&self) -> &Vec<u8>{
121		return &self.binary;
122	}
123
124	pub fn get_type(&self) -> &EndpointType {
125		return &self.endpoint_type;
126	}
127
128	pub fn get_instance(&self) -> u16 {
129		return self.instance;
130	}
131
132	pub fn to_string(&self, colorized:bool) -> String {
133		let mut main = match self.endpoint_type {
134			EndpointType::Id => format!("{}@@{}",				 	(if colorized {Color::ENDPOINT.as_ansi_rgb()} else {"".to_string()}), self.name),
135			EndpointType::PersonAlias => format!("{}@{}", 			(if colorized {Color::EndpointPerson.as_ansi_rgb()} else {"".to_string()}), self.name),
136			EndpointType::InstitutionAlias => format!("{}@+{}", 	(if colorized {Color::EndpointInstitution.as_ansi_rgb()} else {"".to_string()}), self.name)
137		};
138		// if self.subspaces.is_some() {
139		// 	for subspace in self.subspaces.as_ref().unwrap() {
140		// 		if colorized {main += &Color::DEFAULT.as_ansi_rgb()}
141		// 		main += ".";
142		// 		if colorized {main += &Color::DefaultLight.as_ansi_rgb()}
143		// 		main += &subspace;
144		// 	}
145		// }
146
147		if self.instance != Endpoint::ANY_INSTANCE {
148			main += &format!("/{:04X}", self.instance);
149		}
150		
151		return main;
152	}
153
154}