rust_commit_tracker/services/
discord.rs1use crate::core::Config;
2use crate::models::{DiscordEmbed, EmbedAuthor, EmbedData, EmbedField, EmbedFooter};
3use crate::services::scraper::CommitResult;
4use chrono;
5use std::error::Error;
6
7pub struct DiscordNotifier {
8 client: reqwest::Client,
9 config: Config,
10}
11
12impl DiscordNotifier {
13 pub fn new(config: Config) -> Self {
14 Self {
15 client: reqwest::Client::new(),
16 config,
17 }
18 }
19
20 pub async fn send_commit_notification(
21 &self,
22 result: &CommitResult,
23 ) -> Result<(), Box<dyn Error>> {
24 let embed = self.build_embed(result);
25
26 let response = self
27 .client
28 .post(&self.config.discord.webhook_url)
29 .header("Content-Type", "application/json")
30 .json(&embed)
31 .send()
32 .await?;
33
34 if !response.status().is_success() {
35 return Err(
36 format!("Discord webhook failed with status: {}", response.status()).into(),
37 );
38 }
39
40 Ok(())
41 }
42
43 fn build_embed(&self, result: &CommitResult) -> DiscordEmbed {
44 let commit = &result.commit;
45
46 DiscordEmbed {
47 embeds: vec", commit.changeset, commit.link()),
70 inline: true,
71 },
72 ],
73 footer: EmbedFooter {
74 text: format!(
75 "{} • Commit {} of {}",
76 self.config.discord.bot_name,
77 self.format_number(result.total_commits - result.position + 1),
78 self.format_number(result.total_commits)
79 ),
80 icon_url: self.config.discord.bot_avatar_url.clone(),
81 },
82 timestamp: chrono::Utc::now().to_rfc3339(),
83 }],
84 }
85 }
86
87 fn format_number(&self, num: u32) -> String {
88 let num_str = num.to_string();
90 let chars: Vec<char> = num_str.chars().collect();
91 let mut result = String::new();
92
93 for (i, &ch) in chars.iter().enumerate() {
94 if i > 0 && (chars.len() - i) % 3 == 0 {
95 result.push(',');
96 }
97 result.push(ch);
98 }
99
100 result
101 }
102}