rocketchat_message/lib.rs
1//! # RocketChat Message for Rust
2//! This library is an implementation of rocket chat hooks for messages
3//!
4//! * Send text example
5//!
6//! ```
7//! let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
8//!
9//! client.send_text("Text").await?;
10//! ```
11//!
12//! * Send message example
13//!
14//! ```
15//! let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
16//!
17//! let msg = RocketChatMessage::new()
18//! .set_text("Text")
19//! .set_attachments(vec![RocketChatAttachment::new()
20//! .set_title("Attachment title")
21//! .set_title_link("https://google.fr")
22//! .set_text("Attachment text")
23//! .set_author_name("Author name")
24//! .set_color("#c97149")]);
25//!
26//! client.send_message(msg).await?;
27//! ```
28//!
29//! * Send messages example
30//!
31//! ```
32//! let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
33//!
34//! let msgs = vec![
35//! RocketChatMessage::new().set_text("Message1"),
36//! RocketChatMessage::new().set_text("Message2"),
37//! ];
38//!
39//! client.send_messages(msgs).await?;
40//! ```
41
42use anyhow::*;
43use reqwest::blocking::Response;
44use serde::Serialize;
45
46/// A structure representing a rocket chat client
47#[derive(Debug)]
48pub struct RocketChat {
49 /// Webhook url from rocket chat
50 webhook_url: String,
51 /// Channel used to send messages (@user or #channel)
52 channel: String,
53}
54
55impl RocketChat {
56 /// Creates a new rocket chat client
57 ///
58 /// ```
59 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
60 /// ```
61 pub fn new<S: Into<String>>(webhook_url: S, channel: S) -> Self {
62 Self {
63 webhook_url: webhook_url.into(),
64 channel: channel.into(),
65 }
66 }
67
68 /// Changes the channel to post messages
69 ///
70 /// ```
71 /// let mut client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
72 ///
73 /// client = client.set_channel("#channel2");
74 /// ```
75 pub fn set_channel<S: Into<String>>(mut self, channel: S) -> Self {
76 self.channel = channel.into();
77 self
78 }
79
80 /// Send simple text message
81 ///
82 /// ```
83 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
84 ///
85 /// client.send_text("Text").await?;
86 /// ```
87 pub async fn send_text<S: Into<String>>(&self, msg: S) -> Result<reqwest::Response, Error> {
88 let msg = RocketChatMessage::new().set_text(msg.into());
89
90 self.send_message(msg).await
91 }
92
93 /// Send simple text message (sync)
94 ///
95 /// ```
96 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
97 ///
98 /// client.send_text_sync("Text");
99 /// ```
100 pub fn send_text_sync<S: Into<String>>(&self, msg: S) -> Result<Response, Error> {
101 let msg = RocketChatMessage::new().set_text(msg.into());
102
103 self.send_message_sync(msg)
104 }
105
106 /// Send a rocket chat message
107 ///
108 /// ```
109 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
110 /// let msg = RocketChatMessage::new().set_text("Text");
111 ///
112 /// client.send_message(msg).await;
113 /// ```
114 pub async fn send_message(&self, msg: RocketChatMessage) -> Result<reqwest::Response, Error> {
115 let client = reqwest::Client::new();
116
117 let msg = RocketChatMessagePayload::from((msg, self.channel.clone()));
118
119 let res = client
120 .post(&self.webhook_url)
121 .json(&msg)
122 .send()
123 .await
124 .map_err(|e| anyhow!("Request error: {:?}", e.status()))?;
125
126 if res.status() == 200 {
127 Ok(res)
128 } else {
129 Err(anyhow!("Response error: {}", res.status())) // Manage error if status is not 200
130 }
131 }
132
133 /// Send a rocket chat message (sync)
134 ///
135 /// ```
136 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
137 /// let msg = RocketChatMessage::new().set_text("Text");
138 ///
139 /// client.send_message_sync(msg);
140 /// ```
141 pub fn send_message_sync(&self, msg: RocketChatMessage) -> Result<Response, Error> {
142 let client = reqwest::blocking::Client::new();
143
144 let msg = RocketChatMessagePayload::from((msg, self.channel.clone()));
145
146 let res = client
147 .post(&self.webhook_url)
148 .json(&msg)
149 .send()
150 .map_err(|e| anyhow!("Request error: {:?}", e.status()))?;
151
152 if res.status() == 200 {
153 Ok(res)
154 } else {
155 Err(anyhow!("Response error: {}", res.status())) // Manage error if status is not 200
156 }
157 }
158
159 /// Send multiple messages at the same time on the same channel
160 ///
161 /// ```
162 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
163 ///
164 /// let msgs = vec![
165 /// RocketChatMessage::new().set_text("Text"),
166 /// RocketChatMessage::new().set_text("Text2"),
167 /// ];
168 ///
169 /// client.send_messages(msgs).await?;
170 /// ```
171 pub async fn send_messages(&self, msgs: Vec<RocketChatMessage>) -> Result<(), Error> {
172 for msg in msgs {
173 self.send_message(msg).await?;
174 }
175 Ok(())
176 }
177
178 /// Send multiple messages at the same time on the same channel (sync)
179 ///
180 /// ```
181 /// let client = RocketChat::new("ROCKET_CHAT_WEBHOOK_URL", "#channel");
182 ///
183 /// let msgs = vec![
184 /// RocketChatMessage::new().set_text("Text"),
185 /// RocketChatMessage::new().set_text("Text2"),
186 /// ];
187 ///
188 /// client.send_messages_sync(msgs);
189 /// ```
190 pub fn send_messages_sync(&self, msgs: Vec<RocketChatMessage>) -> Result<(), Error> {
191 for msg in msgs {
192 self.send_message_sync(msg)?;
193 }
194 Ok(())
195 }
196}
197
198/// A structure representing a rocket chat field for attachments
199#[derive(Serialize, Default)]
200pub struct Field {
201 /// Size of field (default false by rocket chat)
202 pub short: Option<bool>,
203 /// Title of field
204 pub title: String,
205 /// Value of field
206 pub value: String,
207}
208
209impl Field {
210 /// Create new field
211 ///
212 /// ```
213 /// let field = Field::new();
214 /// ```
215 pub fn new() -> Self {
216 Field::default()
217 }
218
219 /// Change the title of the field
220 ///
221 /// ```
222 /// let field = Field::new().set_title("Title");
223 /// ```
224 pub fn set_title<S: Into<String>>(mut self, title: S) -> Self {
225 self.title = title.into();
226 self
227 }
228
229 /// Change the value of the field
230 ///
231 /// ```
232 /// let field = Field::new().set_value("Value");
233 /// ```
234 pub fn set_value<S: Into<String>>(mut self, value: S) -> Self {
235 self.value = value.into();
236 self
237 }
238
239 /// Change the short of the field
240 ///
241 /// ```
242 /// let field = Field::new().set_short(true);
243 /// ```
244 pub fn set_short(mut self, value: bool) -> Self {
245 self.short = Some(value);
246 self
247 }
248}
249
250/// A structure representing a rocket chat attachment
251#[derive(Serialize, Default)]
252pub struct RocketChatAttachment {
253 /// Title of attachment
254 pub title: Option<String>,
255 /// Link for title of attachment
256 pub title_link: Option<String>,
257 /// Color on border left of attachment
258 pub color: Option<String>,
259 /// Author name of attachment
260 pub author_name: Option<String>,
261 /// Author icon of attachment (displayed only if author name is defined)
262 pub author_icon: Option<String>,
263 /// Text of attachment
264 pub text: Option<String>,
265 /// Image of attachment
266 pub image_url: Option<String>,
267 /// Fields of attachment
268 pub fields: Vec<Field>,
269}
270
271impl RocketChatAttachment {
272 /// Create new attachment
273 ///
274 /// ```
275 /// let attachment = RocketChatAttachment::new();
276 /// ```
277 pub fn new() -> Self {
278 RocketChatAttachment::default()
279 }
280
281 /// Change the title of the attachment
282 ///
283 /// ```
284 /// let attachment = RocketChatAttachment::new().set_title("Title");
285 /// ```
286 pub fn set_title<S: Into<String>>(mut self, title: S) -> Self {
287 self.title = Some(title.into());
288 self
289 }
290
291 /// Change the title link of attachment
292 ///
293 /// ```
294 /// let attachment = RocketChatAttachment::new().set_title_link("https://google.fr");
295 /// ```
296 pub fn set_title_link<S: Into<String>>(mut self, title_link: S) -> Self {
297 self.title_link = Some(title_link.into());
298 self
299 }
300
301 /// Change the color of attachment
302 ///
303 /// ```
304 /// let attachment = RocketChatAttachment::new().set_color("#c97149");
305 /// ```
306 pub fn set_color<S: Into<String>>(mut self, color: S) -> Self {
307 self.color = Some(color.into());
308 self
309 }
310
311 /// Change the author name & icon of attachment
312 ///
313 /// ```
314 /// let attachment = RocketChatAttachment::new().set_author("Author Name", Some("ICON_URL"));
315 /// ```
316 pub fn set_author<S: Into<String>>(mut self, name: S, icon: Option<S>) -> Self {
317 self.author_name = Some(name.into());
318 if let Some(icon) = icon {
319 self.author_icon = Some(icon.into());
320 }
321 self
322 }
323
324 /// Change the content of attachment
325 ///
326 /// ```
327 /// let attachment = RocketChatAttachment::new().set_text("Text");
328 /// ```
329 pub fn set_text<S: Into<String>>(mut self, text: S) -> Self {
330 self.text = Some(text.into());
331 self
332 }
333
334 /// Change the image of attachment
335 ///
336 /// ```
337 /// let attachment = RocketChatAttachment::new().set_image("IMAGE_URL");
338 /// ```
339 pub fn set_image<S: Into<String>>(mut self, url: S) -> Self {
340 self.image_url = Some(url.into());
341 self
342 }
343
344 /// Change the fields of attachment
345 ///
346 /// ```
347 /// let attachment = RocketChatAttachment::new().set_fields(vec![Field::new()
348 /// .set_title("Field title")
349 /// .set_value("Field value")
350 /// .set_short(true)]);
351 /// ```
352 pub fn set_fields(mut self, fields: Vec<Field>) -> Self {
353 self.fields = fields;
354 self
355 }
356}
357
358#[derive(Serialize, Default)]
359struct RocketChatMessagePayload {
360 text: Option<String>,
361 channel: Option<String>,
362 attachments: Vec<RocketChatAttachment>,
363}
364
365impl From<(RocketChatMessage, String)> for RocketChatMessagePayload {
366 fn from(message: (RocketChatMessage, String)) -> Self {
367 Self {
368 text: message.0.text,
369 channel: Some(message.1),
370 attachments: message.0.attachments,
371 }
372 }
373}
374
375/// A structure representing a rocket chat message
376#[derive(Serialize, Default)]
377// #[serde(rename_all = "camelCase")]
378pub struct RocketChatMessage {
379 /// Text on top of attachments
380 pub text: Option<String>,
381 /// Attachments linked to message
382 pub attachments: Vec<RocketChatAttachment>,
383}
384
385impl RocketChatMessage {
386 /// Create new message
387 ///
388 /// ```
389 /// let message = RocketChatMessage::new();
390 /// ```
391 pub fn new() -> Self {
392 RocketChatMessage::default()
393 }
394
395 /// Change the content of message
396 ///
397 /// ```
398 /// let message = RocketChatMessage::new().set_text("Text");
399 /// ```
400 pub fn set_text<S: Into<String>>(mut self, text: S) -> Self {
401 self.text = Some(text.into());
402 self
403 }
404
405 /// Change the attachments of message
406 ///
407 /// ```
408 /// let attachments = vec![RocketChatAttachment::new().set_title("Title")]
409 /// let message = RocketChatMessage::new().set_attachments(attachments);
410 /// ```
411 pub fn set_attachments(mut self, attachments: Vec<RocketChatAttachment>) -> Self {
412 self.attachments = attachments;
413 self
414 }
415}