1use rand::{thread_rng, Rng};
8use xmpp_parsers::{
9 iq::Iq,
10 jid::Jid,
11 message::{Id, Message},
12 presence::Presence,
13};
14use xso::{AsXml, FromXml};
15
16use crate::xmlstream::XmppStreamElement;
17use crate::Error;
18
19pub(crate) fn make_id() -> String {
20 let id: u64 = thread_rng().gen();
21 format!("{}", id)
22}
23
24#[derive(FromXml, AsXml, Debug)]
26#[xml()]
27pub enum Stanza {
28 #[xml(transparent)]
30 Iq(Iq),
31
32 #[xml(transparent)]
34 Message(Message),
35
36 #[xml(transparent)]
38 Presence(Presence),
39}
40
41impl Stanza {
42 pub fn ensure_id(&mut self) -> &str {
44 match self {
45 Self::Iq(iq) => {
46 if iq.id.is_empty() {
47 iq.id = make_id();
48 }
49 &iq.id
50 }
51 Self::Message(message) => message.id.get_or_insert_with(|| Id(make_id())).0.as_ref(),
52 Self::Presence(presence) => presence.id.get_or_insert_with(make_id),
53 }
54 }
55}
56
57impl From<Iq> for Stanza {
58 fn from(other: Iq) -> Self {
59 Self::Iq(other)
60 }
61}
62
63impl From<Presence> for Stanza {
64 fn from(other: Presence) -> Self {
65 Self::Presence(other)
66 }
67}
68
69impl From<Message> for Stanza {
70 fn from(other: Message) -> Self {
71 Self::Message(other)
72 }
73}
74
75impl TryFrom<Stanza> for Message {
76 type Error = Stanza;
77
78 fn try_from(other: Stanza) -> Result<Self, Self::Error> {
79 match other {
80 Stanza::Message(st) => Ok(st),
81 other => Err(other),
82 }
83 }
84}
85
86impl TryFrom<Stanza> for Presence {
87 type Error = Stanza;
88
89 fn try_from(other: Stanza) -> Result<Self, Self::Error> {
90 match other {
91 Stanza::Presence(st) => Ok(st),
92 other => Err(other),
93 }
94 }
95}
96
97impl TryFrom<Stanza> for Iq {
98 type Error = Stanza;
99
100 fn try_from(other: Stanza) -> Result<Self, Self::Error> {
101 match other {
102 Stanza::Iq(st) => Ok(st),
103 other => Err(other),
104 }
105 }
106}
107
108impl From<Stanza> for XmppStreamElement {
109 fn from(other: Stanza) -> Self {
110 Self::Stanza(other)
111 }
112}
113
114#[derive(Debug)]
116pub enum Event {
117 Online {
119 bound_jid: Jid,
125 resumed: bool,
129 },
130 Disconnected(Error),
132 Stanza(Stanza),
134}
135
136impl Event {
137 pub fn is_online(&self) -> bool {
139 matches!(&self, Event::Online { .. })
140 }
141
142 pub fn get_jid(&self) -> Option<&Jid> {
144 match *self {
145 Event::Online { ref bound_jid, .. } => Some(bound_jid),
146 _ => None,
147 }
148 }
149
150 pub fn as_stanza(&self) -> Option<&Stanza> {
152 match *self {
153 Event::Stanza(ref stanza) => Some(stanza),
154 _ => None,
155 }
156 }
157
158 pub fn into_stanza(self) -> Option<Stanza> {
160 match self {
161 Event::Stanza(stanza) => Some(stanza),
162 _ => None,
163 }
164 }
165}