From 8df494c949746295c72e813a0c66e0de1b4552df Mon Sep 17 00:00:00 2001 From: Victor Mignot Date: Tue, 8 Nov 2022 09:05:49 -0500 Subject: [PATCH] Started to create Mongo models --- src/client.rs | 46 +++++++++++++----------------------------- src/database.rs | 6 ++++++ src/database/client.rs | 44 ++++++++++++++++++++++++++++++++++++++++ src/database/models.rs | 37 +++++++++++++++++++++++++++++++++ src/env_catcher.rs | 0 src/errors.rs | 10 ++++----- src/lib.rs | 9 +++++++-- src/main.rs | 19 ++++++++++------- 8 files changed, 125 insertions(+), 46 deletions(-) create mode 100644 src/database.rs create mode 100644 src/database/client.rs create mode 100644 src/database/models.rs create mode 100644 src/env_catcher.rs diff --git a/src/client.rs b/src/client.rs index 0263d61..76a3335 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,8 +1,7 @@ //! Module containing the Yorokobot client and used structs -use crate::errors::ClientsError; +use crate::{database::Client as DatabaseClient, errors::ClientError, DatabaseCredentials}; -use mongodb::{options::ClientOptions as MongoClientOptions, Client as MongoClient}; use serenity::{prelude::GatewayIntents, Client as DiscordClient}; /// Yorokobot's client. @@ -27,15 +26,12 @@ use serenity::{prelude::GatewayIntents, Client as DiscordClient}; /// /// # } /// ``` -pub struct Client { +pub struct Client<'a> { /// The Serenity Discord Client discord_client: DiscordClient, - /// The MongoDB Client - mongodb_client: Option, - - /// MongoDB Client Options - mongodb_options: MongoClientOptions, + /// The database client + database_client: DatabaseClient<'a>, } /// Yorokobot connection credentials @@ -44,12 +40,12 @@ pub struct ClientCredentials<'a> { pub discord_token: &'a String, /// MongoDB connection string. - pub mongo_uri: &'a String, + pub db_credentials: &'a DatabaseCredentials, } -impl<'a> Client { +impl<'a> Client<'a> { /// Create a Yorokobot client - pub async fn new(credentials: ClientCredentials<'a>) -> Result { + pub async fn new(credentials: ClientCredentials<'a>) -> Result { let discord_client = match DiscordClient::builder( credentials.discord_token, GatewayIntents::empty(), @@ -57,43 +53,29 @@ impl<'a> Client { .await { Ok(c) => c, - Err(e) => return Err(ClientsError::Discord(e)), + Err(e) => return Err(ClientError::Discord(e)), }; - let mongodb_options = match MongoClientOptions::parse(credentials.mongo_uri).await { - Ok(o) => o, - Err(e) => return Err(ClientsError::Database(e)), - }; + let database_client = DatabaseClient::new(credentials.db_credentials); Ok(Client { discord_client, - mongodb_options, - mongodb_client: None, + database_client, }) } /// Start connection to Discord API. /// Wrap [`serenity::client::Client`] start method. - pub async fn connect_discord(&mut self) -> Result<(), ClientsError> { + pub async fn connect_discord(&mut self) -> Result<(), ClientError> { match self.discord_client.start().await { Ok(_) => Ok(()), - Err(e) => Err(ClientsError::Discord(e)), + Err(e) => Err(ClientError::Discord(e)), } } - /// Connect to the Mongo Database - pub fn connect_mongodb(&mut self) -> Result<(), ClientsError> { - self.mongodb_client = match MongoClient::with_options(self.mongodb_options.clone()) { - Ok(c) => Some(c), - Err(e) => return Err(ClientsError::Database(e)), - }; - - Ok(()) - } - /// Connect client to the Mongo database then to the Discord API. - pub async fn connect(&mut self) -> Result<(), ClientsError> { - self.connect_mongodb()?; + pub async fn connect(&mut self) -> Result<(), ClientError> { + self.database_client.connect().await?; self.connect_discord().await?; Ok(()) diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..a1c1f48 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,6 @@ +//! Module for database interaction and wrapping + +pub mod client; +mod models; + +pub use {client::Client, mongodb::options::ClientOptions as DatabaseCredentials}; diff --git a/src/database/client.rs b/src/database/client.rs new file mode 100644 index 0000000..55a6879 --- /dev/null +++ b/src/database/client.rs @@ -0,0 +1,44 @@ +use mongodb::Client as MongoClient; + +use crate::errors::ClientError; +use crate::DatabaseCredentials; + +/// Database client +pub struct Client<'a> { + mongo_client: Option, + // database: Option, + credentials: &'a DatabaseCredentials, +} + +impl<'a> Client<'a> { + /// Create a new database client + pub fn new(credentials: &'a DatabaseCredentials) -> Client { + return Client { + credentials, + mongo_client: None, + // database: None, + }; + } + + /// Connect the client + pub async fn connect(&mut self) -> Result<(), ClientError> { + self.mongo_client = match MongoClient::with_options(self.credentials.clone()) { + Ok(c) => Some(c), + Err(e) => return Err(ClientError::Database(e)), + }; + + if let None = self.mongo_client.as_ref().unwrap().default_database() { + // TODO: + // Implement an Environment Variable catcher to wrap std::env::var() + // As we often call it and always have to use a match control flow + + // TODO: + // Complete error kind to be more specific. + // Ex: DatabaseConnection + + todo!(); + } + + Ok(()) + } +} diff --git a/src/database/models.rs b/src/database/models.rs new file mode 100644 index 0000000..011c40c --- /dev/null +++ b/src/database/models.rs @@ -0,0 +1,37 @@ +//! Bot data models + +#![allow(dead_code)] + +use serde::{Deserialize, Serialize}; + +/// All the models within Mongo COllections +pub enum CollectionModels { + /// Discord Guild + Guild(Guild), + + /// Yorokobot tags + Tag(Tag), +} + +/// Settings for a server +#[derive(Debug, Serialize, Deserialize)] +pub struct GuildSettings { + admin_only_can_tag: bool, + server_ban_list: Vec, +} + +/// Server infos +#[derive(Debug, Serialize, Deserialize)] +pub struct Guild { + discord_guild_id: String, + bot_settings: GuildSettings, +} + +/// Tags +#[derive(Debug, Serialize, Deserialize)] +pub struct Tag { + name: String, + guild: String, + is_nsfw: bool, + subscribers: Vec, +} diff --git a/src/env_catcher.rs b/src/env_catcher.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/errors.rs b/src/errors.rs index 8da20e0..5891260 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,14 +1,14 @@ //! Common Yorokobot errors -use mongodb::error::Error as MongoError; -use serenity::prelude::SerenityError; +pub use mongodb::error::Error as DatabaseError; +pub use serenity::prelude::SerenityError as DiscordError; /// The kind of errors that can be returned by Client::new #[derive(Debug)] -pub enum ClientsError { +pub enum ClientError { /// Serenity error while building client - Discord(SerenityError), + Discord(DiscordError), ///Mongo error while parsing options - Database(MongoError), + Database(DatabaseError), } diff --git a/src/lib.rs b/src/lib.rs index 27b41a9..af10ddb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,11 @@ #![deny(missing_docs)] #![deny(warnings)] -pub mod client; - +mod client; +mod database; pub mod errors; + +pub use crate::{ + client::{Client, ClientCredentials}, + database::DatabaseCredentials, +}; diff --git a/src/main.rs b/src/main.rs index 9267d17..fa2e3c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,7 @@ use log::error; use std::env; -use yorokobot::{ - client::{Client, ClientCredentials}, - errors::ClientsError, -}; +use yorokobot::{errors::ClientError, Client, ClientCredentials, DatabaseCredentials}; #[tokio::main] async fn main() -> std::process::ExitCode { @@ -27,9 +24,17 @@ async fn main() -> std::process::ExitCode { } }; + let db_credentials = match DatabaseCredentials::parse(mongodb_uri).await { + Ok(c) => c, + Err(_) => { + error!(target: "bot_warn_errors", "Could not parse database credentials."); + return std::process::ExitCode::FAILURE; + } + }; + let credentials = ClientCredentials { discord_token: &discord_token, - mongo_uri: &mongodb_uri, + db_credentials: &db_credentials, }; let mut client = match Client::new(credentials).await { @@ -42,10 +47,10 @@ async fn main() -> std::process::ExitCode { if let Err(error) = client.connect().await { match error { - ClientsError::Database(e) => { + ClientError::Database(e) => { error!(target: "bot_warn_errors", "Could not connect to database: {:?}", e) } - ClientsError::Discord(e) => { + ClientError::Discord(e) => { error!(target: "bot_warn_errors", "Could not connect to Discord: {:?}", e) } };