1use std::{fmt, str::FromStr, collections::{HashMap, hash_map::RandomState}};
2use std::collections::LinkedList;
3use itertools::Itertools;
4use serde_derive::Deserialize;
5use crate::error::MessageCompressionError;
6
7const MESSAGE_SEPARATOR : char = 0x0 as char;
8const VEC_SEPARATOR : char = 0xFF as char;
9
10#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Default)]
11pub enum MessageType {
12 #[default]
13 Unknown,
14 Text,
15 Audio,
16 Photo,
17 ModuleInfo
18}
19
20impl FromStr for MessageType {
21 type Err = String;
22
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 Ok(match s {
25 "Unknown" => Self::Unknown,
26 "Text" => Self::Text,
27 "Audio" => Self::Audio,
28 "Photo" => Self::Photo,
29 "ModuleInfo" => Self::ModuleInfo,
30 _ => Err(format!("{s} is not a valid MessageType."))?
31 })
32 }
33}
34
35impl fmt::Display for MessageType {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{}", match self {
38 Self::Unknown => "Unknown",
39 Self::Text => "Text",
40 Self::Audio => "Audio",
41 Self::Photo => "Photo",
42 Self::ModuleInfo => "ModuleInfo"
43 })
44 }
45}
46
47#[derive(Debug, PartialEq, Eq, Default)]
48pub struct Message {
49 pub text: String,
50 pub starting_module: String,
51 pub request_topic: String,
52 pub response_topics: LinkedList<String>,
53 pub sender: String,
54 pub message_type: MessageType,
55 pub params: HashMap<String, String, RandomState>,
56}
57
58impl Clone for Message {
59 fn clone(&self) -> Self {
60 Self {
61 text: self.text.clone(),
62 starting_module: self.starting_module.clone(),
63 request_topic: self.request_topic.clone(),
64 response_topics: self.response_topics.clone(),
65 sender: self.sender.clone(),
66 message_type: self.message_type.clone(),
67 params: self.params.clone(),
68 }
69 }
70}
71
72impl Message {
73
74 pub fn empty() -> Self {
75 Self::default()
76 }
77
78 pub fn compress(&self) -> String {
79 let params = self.params.iter()
80 .map(|(k, v)| format!("{k}{MESSAGE_SEPARATOR}{v}"));
81
82 [
83 self.text.clone(),
84 self.starting_module.clone(),
85 self.request_topic.clone(),
86 Itertools::intersperse(
87 self.response_topics.iter()
88 .cloned(), VEC_SEPARATOR.to_string()
89 ).collect(),
90 self.sender.clone(),
91 self.message_type.to_string()
92 ]
93 .into_iter()
94 .chain(params)
95 .collect::<Vec<String>>()
96 .join(MESSAGE_SEPARATOR.to_string().as_str())
97 }
98
99 pub fn decompress(comp_str: &str) -> Result<Self, MessageCompressionError> {
125 let binding = comp_str.to_string();
126 let ser_msg = binding.split(MESSAGE_SEPARATOR).collect::<Vec<&str>>();
127
128 let get_field = |index :usize, default: String| {
129 ser_msg
130 .get(index).copied()
131 .map_or(default, ToString::to_string)
132 };
133
134 let get_vec = |index :usize, field_name: &str| {
135 Ok(ser_msg
136 .get(index)
137 .ok_or_else(|| MessageCompressionError::FieldNotFound(field_name.to_string()))?
138 .split(VEC_SEPARATOR)
139 .map(ToString::to_string)
140 .collect::<LinkedList<String>>())
141 };
142
143 let get_params = |start: usize| {
144 let mut param_name = String::new();
145 let mut params: HashMap<String, String> = HashMap::new();
146 for (i, param) in ser_msg.iter().enumerate().skip(start) {
147 if i % 2 == 0 {
148 param_name = (*param).to_string();
149 } else {
150 params.insert(param_name.clone(), (*param).to_string());
151 }
152 }
153 params
154 };
155
156 Ok(Self{
157 text: get_field(0, String::new()),
158 starting_module: get_field(1, String::new()),
159 request_topic: get_field(2, String::new()),
160 response_topics: get_vec(3,"response_topics")?,
161 sender: get_field(4, String::new()),
162 message_type: get_field(5, MessageType::default().to_string()).parse::<MessageType>()
163 .or(Err(MessageCompressionError::DecompressionError()))?,
164 params: get_params(6)
165 })
166 }
167
168 pub fn reply(&self, text: String, message_type: MessageType) -> Result<(String, Self), crate::error::Error> {
169 let mut response_topics = self.response_topics.clone();
170 let topic = response_topics.pop_front().ok_or(crate::error::Error::ReplyError)?;
171 let response = Self {
172 text,
173 starting_module: self.starting_module.clone(),
174 request_topic: self.request_topic.clone(),
175 response_topics,
176 sender: self.sender.clone(),
177 message_type,
178 params: HashMap::default(),
179 };
180 Ok((topic, response))
181 }
182
183}
184
185impl fmt::Display for Message {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(f, "{}", self.compress())
188 }
189}