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 let id = iq.id_mut();
47 if id.is_empty() {
48 *id = make_id();
49 }
50 id
51 }
52 Self::Message(message) => message.id.get_or_insert_with(|| Id(make_id())).0.as_ref(),
53 Self::Presence(presence) => presence.id.get_or_insert_with(make_id),
54 }
55 }
56}
57
58impl From<Iq> for Stanza {
59 fn from(other: Iq) -> Self {
60 Self::Iq(other)
61 }
62}
63
64impl From<Presence> for Stanza {
65 fn from(other: Presence) -> Self {
66 Self::Presence(other)
67 }
68}
69
70impl From<Message> for Stanza {
71 fn from(other: Message) -> Self {
72 Self::Message(other)
73 }
74}
75
76impl TryFrom<Stanza> for Message {
77 type Error = Stanza;
78
79 fn try_from(other: Stanza) -> Result<Self, Self::Error> {
80 match other {
81 Stanza::Message(st) => Ok(st),
82 other => Err(other),
83 }
84 }
85}
86
87impl TryFrom<Stanza> for Presence {
88 type Error = Stanza;
89
90 fn try_from(other: Stanza) -> Result<Self, Self::Error> {
91 match other {
92 Stanza::Presence(st) => Ok(st),
93 other => Err(other),
94 }
95 }
96}
97
98impl TryFrom<Stanza> for Iq {
99 type Error = Stanza;
100
101 fn try_from(other: Stanza) -> Result<Self, Stanza> {
102 match other {
103 Stanza::Iq(st) => Ok(st),
104 other => Err(other),
105 }
106 }
107}
108
109impl From<Stanza> for XmppStreamElement {
110 fn from(other: Stanza) -> Self {
111 Self::Stanza(other)
112 }
113}
114
115#[derive(Debug)]
117pub enum Event {
118 Online {
120 bound_jid: Jid,
126 resumed: bool,
130 },
131 Disconnected(Error),
133 Stanza(Stanza),
135}
136
137impl Event {
138 pub fn is_online(&self) -> bool {
140 matches!(&self, Event::Online { .. })
141 }
142
143 pub fn get_jid(&self) -> Option<&Jid> {
145 match *self {
146 Event::Online { ref bound_jid, .. } => Some(bound_jid),
147 _ => None,
148 }
149 }
150
151 pub fn as_stanza(&self) -> Option<&Stanza> {
153 match *self {
154 Event::Stanza(ref stanza) => Some(stanza),
155 _ => None,
156 }
157 }
158
159 pub fn into_stanza(self) -> Option<Stanza> {
161 match self {
162 Event::Stanza(stanza) => Some(stanza),
163 _ => None,
164 }
165 }
166}