diff --git a/src/discord.rs b/src/discord.rs index 756126a..55579d9 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -4,6 +4,8 @@ use serenity::{ prelude::*, }; +use serde_json::json; + mod erreur { include!("erreur.rs"); } @@ -12,24 +14,97 @@ mod erreur { pub struct ConnectionInfoDiscord { pub token: String, pub prefix: String, + pub api: mattermost_api::client::Mattermost, + pub salon: String, } -static mut _PREFIX: Option = None; +/// Structure qui stocke les informations dont le bot a besoin pour communiquer avec Mattermost +struct InformationsBot { + prefix: Option, + api: Option, + salon: Option, +} -/// Récupère le string du prefix -/// Attention, on fait paniqué le programme si la valeur est vide, pour éviter +/// Implémentation pour utiliser facilement les valeurs de la structure +/// Normalement, rien ne panique car si `start_discord` +/// n'as pas encore été appellé on panique avant d'arriver ici. +/// +/// On fait quand même le match pour être sûr. +impl InformationsBot { + const err: String = String::from("Erreur lors de la récupération des informations\nTips: start_discord n'a peut-être pas été appelée..."); + + /// Créer une structure vide + pub fn nouveau_vide() -> Self { + Self { + prefix: None, + api: None, + salon: None, + } + } + + /// Créer une structure personnalisée. + pub fn nouveau( + prefix: String, + api: mattermost_api::client::Mattermost, + salon: String, + ) -> Option { + Some(Self { + prefix: Some(prefix), + api: Some(api), + salon: Some(salon), + }) + } + + /// Récupère préfix, sinon panique + pub fn recuperation_prefix(self) -> String { + match self.prefix { + Some(prefix) => prefix, + None => panic!( + "{}", + erreur::message_erreur(&format!("[Recup-Prefix] {}", Self::err)) + ), + } + } + + /// Récupère API, sinon panique + pub fn recuperation_API(self) -> mattermost_api::client::Mattermost { + match self.api { + Some(api) => api, + None => panic!( + "{}", + erreur::message_erreur(&format!("[Recup-API] {}", Self::err)) + ), + } + } + + /// Récupère le salon, sinon panique + pub fn recuperation_salon(self) -> String { + match self.salon { + Some(salon) => salon, + None => panic!( + "{}", + erreur::message_erreur(&format!("[Recup-Salon] {}", Self::err)) + ), + } + } +} + +static mut _INFO: Option = None; + +/// Récupère les informations qui sont nécessaire à la communication avec Mattermost +/// Attention, on fait paniqué le programme si l valeur est vide, pour éviter /// ça, il faut appeller cette fonction seulement quand `start_discord` -/// a été appellé car c'est elle qui ajoute le préfixe à `_PREFIX` +/// a été appellé car c'est elle qui ajoute le préfixe à `_INFO` /// /// Je sais que c'est vraiment naze de faire ça (variable static + blocs unsafe) /// mais c'est la seul solution que j'ai trouvé en évitant de trop étoffé avec du -/// code pas très utile. -unsafe fn recuperation_prefix() -> String { - match &_PREFIX { - Some(p) => p.to_string(), +/// code Discord pas très utile. +unsafe fn recuperation_info() -> &'static InformationsBot { + match &_INFO { + Some(info) => info, None => panic!( "{}", - erreur::message_erreur("[RUST] Erreur lors de la récupération du préfix Discord\nTips: start_discord function may not have been called...") + erreur::message_erreur(&format!("[Recup-InfosBot] {}", InformationsBot::err)) ), } } @@ -41,11 +116,11 @@ impl EventHandler for Handler { // Appellé quand un message est récupérer par le bot async fn message(&self, ctx: Context, msg: Message) { #[allow(unused_assignments)] - // Rust doit penser que `prefix` n'est pas utilisé à cause de la confusion apporté par le bloc unsafe - let mut prefix = String::from(""); + let mut infos = &InformationsBot::nouveau_vide(); unsafe { - prefix = recuperation_prefix(); + infos = recuperation_info(); } + let prefix = infos.recuperation_prefix(); if msg.content == format!("{}info", prefix) { let reponse = "\ Bot réalisé dans le cadre du cours de Programmation avancée.\n\ @@ -60,11 +135,12 @@ impl EventHandler for Handler { } else { /* Dans ce cas là, ce n'est pas une commande, alors c'est un message. * Il faut l'envoyer à Mattermost. */ + envoie_msg_mattermost(msg).await } } // Fonction appellé quand le bot est lancé et connecté - async fn ready(&self, _: Context, _ready: Ready) { + async fn ready(&self, _: Context, _: Ready) { println!("Écoute les évènements Discord..."); } } @@ -72,8 +148,8 @@ impl EventHandler for Handler { /// Lance le bot Discord pub async fn start_discord(informations: ConnectionInfoDiscord) { unsafe { - // On définit notre préfix - _PREFIX = Some(informations.prefix); + // On enregistre tout de suite nos informations + _INFO = InformationsBot::nouveau(informations.prefix, informations.api, informations.salon); } // Client Discord (https://docs.rs/serenity/latest/serenity/client/index.html) @@ -90,6 +166,46 @@ pub async fn start_discord(informations: ConnectionInfoDiscord) { // Lance le bot if let Err(err) = client.start().await { // Si une erreur apparaît - erreur::affiche_message_erreur(&format!("Erreur Discord : {:?}", err)); + erreur::affiche_message_erreur(&format!("Erreur lancement discord : {:?}", err)); + } +} + +/// Ne peut pas être async (limitation de serde_json) +fn recuperation_salon() -> String { + String::from("temp") +} + +/// Envoie un message sur Mattermost +async fn envoie_msg_mattermost(msg: Message) { + #[allow(unused_assignments)] + let mut infos = &InformationsBot::nouveau_vide(); + unsafe { + infos = recuperation_info(); + } + let res = infos + .recuperation_API() + .query::( + "POST", + "post", + None, + Some( + &json!( // d'après la documentation : https://api.mattermost.com/#tag/WebSocket + { + "channel_id": recuperation_salon(), + "message": msg + } + ) + .to_string(), + ), + ) + .await; + + match res { + Ok(res) => { + println!("{}", res); + } + Err(e) => { + erreur::affiche_message_erreur(&format!("[Discord -> Mattermost] Erreur: {}", e)); + } } }