diff --git a/.env.example b/.env.example index e337009..48597bb 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,5 @@ # Discord Token DISCORD_TOKEN="Enter your Discord secret token" + +# MongoDB connection string +MONGO_URI="Enter your Mongo connection string" diff --git a/Cargo.lock b/Cargo.lock index aa3f3c2..6a7d3ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1857,6 +1857,7 @@ name = "yorokobot" version = "0.1.0" dependencies = [ "mongodb", + "serde", "serenity", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index d2890ff..630f974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ edition = "2021" serenity = { version="0.11", default-features = false, features = ["client", "gateway", "rustls_backend", "model" ] } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } mongodb = "2.3.0" +serde = { version = "1.0", features = [ "derive" ] } diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..2f5bfc6 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,11 @@ +services: + mongodb: + image: mongo:latest + + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: root + MONGO_INITDB_DATABASE: yorokobot + + ports: + - 27017:27017 diff --git a/src/client.rs b/src/client.rs index 8bf394d..0263d61 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,8 @@ +//! Module containing the Yorokobot client and used structs + +use crate::errors::ClientsError; + +use mongodb::{options::ClientOptions as MongoClientOptions, Client as MongoClient}; use serenity::{prelude::GatewayIntents, Client as DiscordClient}; /// Yorokobot's client. @@ -8,50 +13,89 @@ use serenity::{prelude::GatewayIntents, Client as DiscordClient}; /// # async fn run() { /// use yorokobot::client::{Client, ClientCredentials}; /// -/// let token = String::from("Your discord token"); +/// let discord_token = String::from("Your discord token"); +/// let mongo_uri = String::from("Your Mongo URI"); /// /// let credentials = ClientCredentials { -/// discord_token: &token, +/// discord_token: &discord_token, +/// mongo_uri: &mongo_uri, /// }; /// -/// let mut client = Client::new(credentials).await; +/// let mut client = Client::new(credentials).await.expect("Error creating client"); /// /// client.connect().await; /// /// # } /// ``` -/// pub struct Client { + /// The Serenity Discord Client discord_client: DiscordClient, + + /// The MongoDB Client + mongodb_client: Option, + + /// MongoDB Client Options + mongodb_options: MongoClientOptions, } /// Yorokobot connection credentials pub struct ClientCredentials<'a> { /// Token for Discord API pub discord_token: &'a String, + + /// MongoDB connection string. + pub mongo_uri: &'a String, } impl<'a> Client { /// Create a Yorokobot client - pub async fn new(credentials: ClientCredentials<'a>) -> Client { - let discord_client = - DiscordClient::builder(credentials.discord_token, GatewayIntents::empty()) - .await - .expect("Could not create Discord Client"); + pub async fn new(credentials: ClientCredentials<'a>) -> Result { + let discord_client = match DiscordClient::builder( + credentials.discord_token, + GatewayIntents::empty(), + ) + .await + { + Ok(c) => c, + Err(e) => return Err(ClientsError::Discord(e)), + }; - Client { discord_client } + let mongodb_options = match MongoClientOptions::parse(credentials.mongo_uri).await { + Ok(o) => o, + Err(e) => return Err(ClientsError::Database(e)), + }; + + Ok(Client { + discord_client, + mongodb_options, + mongodb_client: None, + }) } /// Start connection to Discord API. /// Wrap [`serenity::client::Client`] start method. - pub async fn connect_discord(&mut self) { - if let Err(error) = self.discord_client.start().await { - println!("Could not connect to Discord: {:?}", error); + pub async fn connect_discord(&mut self) -> Result<(), ClientsError> { + match self.discord_client.start().await { + Ok(_) => Ok(()), + Err(e) => Err(ClientsError::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) { - self.connect_discord().await; + pub async fn connect(&mut self) -> Result<(), ClientsError> { + self.connect_mongodb()?; + self.connect_discord().await?; + + Ok(()) } } diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..8da20e0 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,14 @@ +//! Common Yorokobot errors + +use mongodb::error::Error as MongoError; +use serenity::prelude::SerenityError; + +/// The kind of errors that can be returned by Client::new +#[derive(Debug)] +pub enum ClientsError { + /// Serenity error while building client + Discord(SerenityError), + + ///Mongo error while parsing options + Database(MongoError), +} diff --git a/src/lib.rs b/src/lib.rs index c18a41e..27b41a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,5 +6,6 @@ #![deny(missing_docs)] #![deny(warnings)] -/// Module containing the Yorokobot client and used structs pub mod client; + +pub mod errors; diff --git a/src/main.rs b/src/main.rs index e135ec0..3b488d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,27 @@ use std::env; -use yorokobot::client::{Client, ClientCredentials}; +use yorokobot::{ + client::{Client, ClientCredentials}, + errors::ClientsError, +}; #[tokio::main] async fn main() { let discord_token = env::var("DISCORD_TOKEN").expect("Cannot fetch Discord token"); + let mongodb_uri = env::var("MONGODB_URI").expect("Cannot fetch Mongo URI"); + let credentials = ClientCredentials { discord_token: &discord_token, + mongo_uri: &mongodb_uri, }; - let mut client = Client::new(credentials).await; + let mut client = Client::new(credentials) + .await + .expect("Could not create client"); - client.connect_discord().await; + client.connect().await.unwrap_or_else(|error| match error { + ClientsError::Database(e) => panic!("Could not connect to database: {:?}", e), + ClientsError::Discord(e) => panic!("Could not connect to Discord: {:?}", e), + }); }