1#![allow(clippy::large_enum_variant)]
2use crate::Result;
3use crate::{
4 common::utils::{compute_hash, from_bytes, option_of_bytes},
5 Addr,
6};
7
8use serde::{Deserialize, Serialize};
9use std::mem::{replace, swap};
10use std::time::SystemTime;
11use uuid::Uuid;
12#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
16pub enum Content {
17 Text(String),
18 Binary(Vec<u8>),
19 Command(Action),
20}
21impl std::fmt::Display for Action {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 match self {
24 action @ Self::Shutdown => write!(f, "{}", action.as_text()),
25 cont @ Self::Continue => write!(f, "{}", cont.as_text()),
26 Self::Echo(s) => write!(f, "Echo({})", s),
27 }
28 }
29}
30
31use Content::*;
32#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
34pub enum Mail {
35 Trade(Msg),
37 Bulk(Vec<Msg>),
39 Blank,
41}
42use Mail::*;
43
44impl Mail {
45 pub fn message(&self) -> &Msg {
47 match self {
48 Trade(ref msg) => msg,
49 _ => panic!("message is supported only on Trade variant"),
50 }
51 }
52 pub fn messages(&self) -> &Vec<Msg> {
54 match self {
55 Bulk(ref msgs) => msgs,
56 _ => panic!("messages is supported only on Bulk variant"),
57 }
58 }
59 pub fn take(self) -> Msg {
61 match self {
62 Trade(msg) => msg,
63 _ => panic!(),
64 }
65 }
66 pub fn take_all(self) -> Vec<Msg> {
68 match self {
69 Bulk(msgs) => msgs,
70 _ => panic!(),
71 }
72 }
73 pub fn command_equals(&self, action: Action) -> bool {
75 if !self.is_command() {
76 return false;
77 }
78 match self {
79 Trade(_) => self.message().command_equals(action),
80 bulk @ Bulk(_) => bulk.messages()[0].command_equals(action),
81 _ => false,
82 }
83 }
84 pub fn is_command(&self) -> bool {
86 match self {
87 trade @ Trade(_) => trade.message().is_command(),
88 bulk @ Bulk(ref _msgs)
89 if bulk.messages().len() == 1 && bulk.messages()[0].is_command() =>
90 {
91 true
92 }
93 _ => false,
94 }
95 }
96
97 pub fn action(&self) -> Option<Action> {
100 if !self.is_command() {
101 return None;
102 }
103 match self {
104 Trade(msg) => msg.action(),
105 bulk @ Bulk(_) => bulk.messages()[0].action(),
106 _ => None,
107 }
108 }
109
110 pub(crate) fn fold(mails: Vec<Option<Mail>>) -> Mail {
113 Bulk(
114 mails
115 .into_iter()
116 .map(Mail::from)
117 .flat_map(|mail| match mail {
118 trade @ Trade(_) => vec![trade.take()],
119 bulk @ Bulk(_) => bulk.take_all(),
120 _ => unreachable!(),
121 })
122 .collect::<Vec<_>>(),
123 )
124 }
125 pub fn is_blank(mail: &Mail) -> bool {
127 matches!(mail, Blank)
128 }
129 pub(crate) fn inbound(mail: &Mail) -> bool {
131 match mail {
132 Trade(ref msg) => msg.inbound(),
133 _ => false,
134 }
135 }
136 pub(crate) fn split(mail: Mail) -> Option<(Vec<Msg>, Vec<Msg>)> {
138 match mail {
139 Blank => None,
140 trade @ Trade(_) if Mail::inbound(&trade) => Some((vec![trade.take()], Vec::new())),
141 trade @ Trade(_) if !Mail::inbound(&trade) => Some((Vec::new(), vec![trade.take()])),
142 Trade(_) => unreachable!(),
143 Bulk(msgs) => match msgs.into_iter().partition::<Vec<Msg>, _>(Msg::inbound) {
144 (v1, v2) if v1.is_empty() & v2.is_empty() => None,
145 or_else @ (_, _) => Some(or_else),
146 },
147 }
148 }
149
150 pub(crate) fn partition(mails: Vec<Option<Mail>>) -> Option<(Vec<Msg>, Vec<Msg>)> {
152 match mails
153 .into_iter()
154 .map(Mail::from)
155 .filter(|mail| !Mail::is_blank(mail))
156 .flat_map(|mail| match mail {
157 trade @ Trade(_) => vec![trade.take()],
158 Bulk(msgs) => msgs,
159 _ => panic!(),
160 })
161 .partition::<Vec<Msg>, _>(Msg::inbound)
162 {
163 (v1, v2) if v1.is_empty() & v2.is_empty() => None,
164 or_else @ (_, _) => Some(or_else),
165 }
166 }
167 pub fn set_from(mail: &mut Option<Mail>, from: &Addr) {
169 match mail {
170 Some(mail) => match mail {
171 Trade(msg) => msg.set_from(from),
172 Bulk(msgs) => {
173 for msg in msgs.iter_mut() {
174 msg.set_from(from);
175 }
176 }
177 Blank => (),
178 },
179 None => (),
180 }
181 }
182}
183
184impl From<Option<Mail>> for Mail {
185 fn from(opt: Option<Mail>) -> Self {
186 match opt {
187 Some(mail) => mail,
188 None => Mail::Blank,
189 }
190 }
191}
192
193impl From<Vec<Msg>> for Mail {
194 fn from(msgs: Vec<Msg>) -> Self {
195 Bulk(msgs)
196 }
197}
198#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
201#[non_exhaustive]
202pub enum Action {
203 Shutdown,
205 Echo(String),
207 Continue,
209}
210impl Action {
211 fn as_text(&self) -> &str {
213 match self {
214 Self::Shutdown => "Shutdown",
215 Self::Echo(_) => "Echo",
216 Self::Continue => "Continue",
217 }
218 }
219 pub fn inner(&self) -> &str {
221 match self {
222 Self::Shutdown => "",
223 Self::Continue => "",
224 Self::Echo(s) => s,
225 }
226 }
227
228 pub fn execute(&mut self, _input: Mail) -> Option<Mail> {
231 match self {
232 Self::Echo(text) => Some(Msg::echo(&text.chars().rev().collect::<String>()).into()),
233 _ => None,
234 }
235 }
236}
237#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
239pub struct Msg {
240 id: u64,
241 from: Option<Addr>,
242 to: Option<Addr>,
243 content: Option<Content>,
244 dispatched: Option<SystemTime>,
245}
246
247impl Msg {
248 pub fn new(content: Option<Vec<u8>>, from: &str, to: &str) -> Self {
250 Self {
251 id: compute_hash(&Uuid::new_v4()),
252 from: Some(Addr::new(from)),
253 to: Some(Addr::new(to)),
254 content: content.map(Binary),
255 dispatched: None,
256 }
257 }
258 pub fn with_binary_content(content: Option<Vec<u8>>) -> Self {
260 Self {
261 id: compute_hash(&Uuid::new_v4()),
262 from: None,
263 to: None,
264 content: content.map(Binary),
265 dispatched: None,
266 }
267 }
268
269 pub fn from_text(content: &str) -> Self {
283 Self {
284 id: compute_hash(&Uuid::new_v4()),
285 from: None,
286 to: None,
287 content: Some(Text(content.to_string())),
288 dispatched: Some(SystemTime::now()),
289 }
290 }
291 pub fn with_text(content: &str, from: &str, to: &str) -> Self {
293 Self {
294 id: compute_hash(&Uuid::new_v4()),
295 from: Some(Addr::new(from)),
296 to: Some(Addr::new(to)),
297 content: Some(Text(content.to_string())),
298 dispatched: Some(SystemTime::now()),
299 }
300 }
301 pub fn as_text(&self) -> Option<&str> {
304 match self.content {
305 Some(Binary(ref bytes)) => {
306 let text: Result<&str> = from_bytes(bytes);
307 text.ok()
308 }
309 Some(Text(ref s)) => Some(s),
310 Some(Command(ref action)) => Some(action.inner()),
311 None => None,
312 }
313 }
314 pub fn is_command(&self) -> bool {
316 matches!(self.content, Some(Command(_)))
317 }
318 pub fn command_equals(&self, action: Action) -> bool {
320 if !self.is_command() {
321 return false;
322 }
323 if let Some(Content::Command(ref own_action)) = self.content {
324 return own_action.as_text() == action.as_text();
325 }
326 false
327 }
328 pub fn action(&self) -> Option<Action> {
331 if !self.is_command() {
332 return None;
333 }
334 match self.content {
335 Some(Command(ref action)) => Some(action.clone()),
336 _ => None,
337 }
338 }
339
340 pub fn as_bytes(&self) -> Vec<u8> {
343 option_of_bytes(self).unwrap_or_default()
344 }
345 pub fn text_reply(&mut self, reply: &str) {
347 swap(&mut self.from, &mut self.to);
348 let _ignore = replace(&mut self.content, Some(Text(reply.to_string())));
349 }
350
351 pub fn update_text_content(&mut self, reply: &str) {
353 let _ignore = replace(&mut self.content, Some(Text(reply.to_string())));
354 }
355 pub fn with_content_and_to(&mut self, new_content: Vec<u8>, new_to: &str) {
357 self.content = Some(Binary(new_content));
358 self.to = Some(Addr::new(new_to));
359 }
360 pub fn with_content(&mut self, new_content: Vec<u8>) {
362 self.content = Some(Binary(new_content));
363 }
364 pub fn set_recipient_addr(&mut self, addr: &Addr) {
366 self.to = Some(addr.clone());
367 }
368 pub fn set_recipient(&mut self, new_to: &str) {
370 self.to = Some(Addr::new(new_to));
371 }
372 pub fn set_recipient_ip(&mut self, new_to_ip: &str) {
374 if let Some(ref mut addr) = self.to {
375 addr.with_ip(new_to_ip);
376 }
377 }
378 pub fn set_recipient_port(&mut self, new_port: u16) {
380 if let Some(ref mut addr) = self.to {
381 addr.with_port(new_port);
382 }
383 }
384 pub fn get_recipient_port(&self) -> u16 {
386 if let Some(addr) = &self.to {
387 return addr.get_port().expect("port");
388 }
389 0
390 }
391 pub fn binary_reply(&mut self, reply: Option<Vec<u8>>) {
393 swap(&mut self.from, &mut self.to);
394 let _ignore = replace(&mut self.content, reply.map(Binary));
395 }
396 pub fn binary_content(&self) -> Option<Vec<u8>> {
398 match &self.content {
399 Some(Binary(data)) => Some(data.to_vec()),
400 _ => None,
401 }
402 }
403 pub fn binary_content_out(&mut self) -> Option<Vec<u8>> {
406 match self.content.take() {
407 Some(Binary(data)) => Some(data),
408 content @ Some(_) => {
409 self.content = content;
410 None
411 }
412 _ => None,
413 }
414 }
415 pub fn get_to(&self) -> &Option<Addr> {
417 &self.to
418 }
419 pub fn get_id(&self) -> &u64 {
421 &self.id
422 }
423 pub fn id_as_string(&self) -> String {
426 self.get_id().to_string()
427 }
428
429 pub fn get_to_id(&self) -> u64 {
431 match self.to {
432 Some(ref addr) => addr.get_id(),
433 None => 0,
434 }
435 }
436
437 pub fn get_from(&self) -> &Option<Addr> {
439 &self.from
440 }
441 pub fn inbound(&self) -> bool {
443 match self.to {
444 Some(ref addr) => addr.is_local(),
445 None => false,
446 }
447 }
448 pub fn set_from(&mut self, from: &Addr) {
451 let _ignore = std::mem::replace(&mut self.from, Some(from.clone()));
452 }
453
454 pub fn shutdown() -> Self {
456 let mut cmd = Msg::default();
457 let _ignore = std::mem::replace(&mut cmd.content, Some(Content::Command(Action::Shutdown)));
458 cmd
459 }
460 pub fn echo(s: &str) -> Self {
462 let mut cmd = Msg::default();
463 let _ignore = std::mem::replace(
464 &mut cmd.content,
465 Some(Content::Command(Action::Echo(s.to_string()))),
466 );
467 cmd
468 }
469}
470
471impl Default for Mail {
472 fn default() -> Self {
473 Mail::Blank
474 }
475}
476
477impl From<Msg> for Mail {
478 fn from(msg: Msg) -> Self {
479 Mail::Trade(msg)
480 }
481}
482
483pub(crate) enum RichMail {
485 RichContent(Mail, bool, i64, Option<Addr>, Option<Addr>),
486}
487use RichMail::RichContent;
488impl RichMail {
489 pub(crate) fn mail(&self) -> &Mail {
490 let RichContent(mail, _, _, _, _) = self;
491 mail
492 }
493 pub(crate) fn mail_out(&mut self) -> Mail {
494 let RichContent(mail, _, _, _, _) = self;
495 std::mem::replace(mail, Mail::Blank)
496 }
497
498 pub(crate) fn replace_mail(&mut self, msgs: Vec<Msg>) {
499 let RichContent(mail, _, _, _, _) = self;
500 *mail = Mail::Bulk(msgs);
501 }
502 pub(crate) fn to(&self) -> Option<&Addr> {
503 let RichContent(_, _, _, _, to) = self;
504 to.as_ref()
505 }
506 pub(crate) fn from(&self) -> Option<&Addr> {
507 let RichContent(_, _, _, from, _) = self;
508 from.as_ref()
509 }
510 pub(crate) fn inbound(&self) -> bool {
511 let RichContent(_, inbound, _, _, _) = self;
512 *inbound
513 }
514 pub(crate) fn seq(&self) -> i64 {
515 let RichContent(_, _, seq, _, _) = self;
516 *seq
517 }
518}
519
520impl std::fmt::Display for Msg {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 {
523 write!(f, "Msg({}), ", &self.id)?;
524 let _rs = match self.from {
525 Some(ref from) => write!(f, "from: {}, ", from),
526 None => write!(f, "from: None, "),
527 };
528 let _rs = match self.to {
529 Some(ref to) => write!(f, "to: {}, ", to),
530 None => write!(f, "to: None, "),
531 };
532 match self.content {
533 Some(ref content) => write!(f, "content: {}", content),
534 None => write!(f, "content: None"),
535 }
536 }
537 }
538}
539
540impl std::fmt::Display for Content {
541 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
542 match self {
543 Text(text) => {
544 write!(f, "Text({})", text)
545 }
546 Binary(binary) => {
547 write!(f, "Binary(..) -> length {}", binary.len())
548 }
549 Command(c) => {
550 write!(f, "Command({})", c)
551 }
552 }
553 }
554}
555
556impl std::fmt::Display for Mail {
557 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
558 match self {
559 Trade(msg) => {
560 write!(f, "Trade({})", msg)
561 }
562 Bulk(ref msgs) => {
563 writeln!(f, "Bulk({})", msgs.len())?;
564 if !msgs.is_empty() {
565 for msg in msgs.iter().take(msgs.len() - 1) {
566 let _ = write!(f, "{}", msg);
567 let _rs = writeln!(f);
568 }
569 write!(f, "{}", msgs[msgs.len() - 1])
570 } else {
571 write!(f, " Empty")
572 }
573 }
574 Blank => write!(f, "Blank"),
575 }
576 }
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582 use crate::common::utils::{from_bytes, option_of_bytes};
583
584 #[test]
585 fn create_trade_msg_test_content_and_to() {
586 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
587 assert_eq!(
588 from_bytes(&msg.binary_content_out().unwrap()).ok(),
589 Some("Content")
590 );
591 assert_eq!(msg.get_to(), &Some(Addr::new("addr_to")));
592 println!("{}", msg);
593 }
594
595 #[test]
596 fn create_trade_msg_test_from() {
597 let msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
598 assert_eq!(msg.get_from(), &Some(Addr::new("addr_from")));
599 println!("{}", msg);
600 }
601
602 #[test]
603 fn create_trade_msg_test_alter_content_and_to() {
604 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
605 assert_eq!(msg.binary_content(), option_of_bytes(&"Content"));
606 assert_eq!(msg.get_to(), &Some(Addr::new("addr_to")));
607 msg.with_content_and_to(option_of_bytes(&"New content").unwrap(), "New_to");
608 assert_eq!(msg.binary_content(), option_of_bytes(&"New content"));
609 assert_eq!(msg.get_to(), &Some(Addr::new("New_to")));
610 }
611
612 #[test]
613 fn set_recipient_test_1() {
614 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
615 assert_eq!(msg.get_to(), &Some(Addr::new("addr_to")));
616 msg.set_recipient("The new recipient");
617 assert_eq!(msg.get_to(), &Some(Addr::new("The new recipient")));
618 }
619
620 #[test]
621 fn binary_reply_test_1() {
622 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
623 msg.binary_reply(option_of_bytes(&"Reply"));
624 assert_eq!(msg.get_to(), &Some(Addr::new("addr_from")));
625 assert_eq!(msg.get_from(), &Some(Addr::new("addr_to")));
626 assert_eq!(msg.binary_content(), option_of_bytes(&"Reply"));
627 }
628 #[test]
629 fn text_reply_test_1() {
630 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
631 assert_eq!(msg.binary_content(), option_of_bytes(&"Content"));
632 msg.text_reply("Reply");
633 assert_eq!(msg.get_to(), &Some(Addr::new("addr_from")));
634 assert_eq!(msg.get_from(), &Some(Addr::new("addr_to")));
635 assert_eq!(msg.binary_content(), option_of_bytes(&"Reply"));
636 }
637 #[test]
638 fn as_text_test_1() {
639 let mut msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
640 assert_eq!(msg.binary_content(), option_of_bytes(&"Content"));
641 assert_eq!(msg.as_text(), Some("Content"));
642
643 msg.update_text_content("Updated content");
644 assert_eq!(msg.binary_content(), option_of_bytes(&"Updated content"));
645 assert_eq!(msg.as_text(), Some("Updated content"));
646 }
647 #[test]
648 fn outbound_mgs_test_1() {
649 let mut trade_msg = Msg::new(option_of_bytes(&"Content"), "addr_from", "addr_to");
650 assert!(trade_msg.inbound());
651
652 trade_msg.set_recipient_ip("89.89.89.89");
653 assert!(!trade_msg.inbound());
654 }
655 #[test]
656 fn test_mail_partition() {
657 let mut mails = vec![
658 Some(Mail::Blank),
659 Some(Mail::Blank),
660 None,
661 Some(Trade(Msg::with_text("mail", "from", "to"))),
662 ];
663
664 let mut m1 = Msg::with_text("mail", "from1", "to1");
665 let mut addr1 = Addr::new("add1");
666 addr1.with_port(9999);
667 m1.set_recipient_addr(&addr1);
668 mails.push(Some(Trade(m1)));
669 let mut addr2 = addr1.clone();
670 addr2.with_port(1111);
671 let mut m2 = Msg::with_text("mail", "from2", "to2");
672 m2.set_recipient_addr(&addr2);
673 mails.push(Some(Bulk(vec![m2])));
674
675 let mut m3 = Msg::with_text("mail", "from3", "to3");
676 m3.set_recipient_ip("89.89.89.89");
677 mails.push(Some(Bulk(vec![m3])));
678
679 if let Some((ref v1, ref v2)) = Mail::partition(mails) {
680 v1.iter().for_each(|msg| {
681 if let Some(ref addr) = msg.get_to() {
682 assert!(addr.is_local());
683 }
684 });
685
686 v2.iter().for_each(|msg| {
687 if let Some(ref addr) = msg.get_to() {
688 assert!(!addr.is_local());
689 }
690 });
691 }
692 }
693
694 #[test]
695 fn mail_print_test() {
696 let m = Msg::with_text("mail", "from", "to");
697 let mail = Mail::Trade(m);
698 println!("{}", mail);
699
700 let m1 = Msg::with_text("mail", "from", "to");
701 let m2 = Msg::with_text("mail", "from", "to");
702 let m3 = Msg::with_text("mail", "from", "to");
703 let bulk_mail = Mail::Bulk(vec![]);
704 println!("{}", bulk_mail);
705
706 let bulk_mail = Mail::Bulk(Vec::new());
707 println!("{}", bulk_mail);
708
709 let bulk_mail = Mail::Bulk(vec![m1, m2, m3]);
710 println!("Bulk {}", bulk_mail);
711
712 let m1 = Msg::with_text("mail", "from", "to");
713 let bulk_mail = Mail::Bulk(vec![m1]);
714 println!("Bulk {}", bulk_mail);
715
716 println!("Bulk {}", Mail::Blank);
717 }
718
719 #[test]
720 fn mail_is_command_test_1() {
721 let trade_mail: Mail = Msg::with_text("Some text", "from", "to").into();
722 assert!(!trade_mail.is_command());
723
724 let bulk = Mail::Bulk(vec![Msg::with_text("Some text", "from", "to")]);
725 assert!(!bulk.is_command());
726 }
727}