diff --git a/readme.md b/readme.md index 75ccfba..e77154e 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,61 @@ -Twitch bot written in rust +Twitch chat bot written in rust + +# Quick Start + +Runs the bot's binary crate + +1. Generate a twitch access token + + - Get a Bot Chat Token here - https://twitchtokengenerator.com + - More Info - https://dev.twitch.tv/docs/authentication + +2. Define an `.env` file with the following + +``` +login_name=BOTNAME +access_token=ACCESS_TOKEN +bot_channels=BOTNAME +prefix=` +bot_admins=ADMIN +``` + +3. Build & run -# Compile & Run ``` cargo run -``` \ No newline at end of file +``` + +# Example Code + +**Quick Start Main** + +Uses Env defined variables to create and run the bot + +```rust +use botcore::bot::Bot; + +mod botcore; + +#[tokio::main] +pub async fn main() { + + /* 1. Create the bot using env */ + let bot = Bot::new(); + + /* 2. Run the bot */ + bot.run().await; + +} +``` + +# Crate Rust Documentation + +Clean Build Documentation +``` +cargo clean && cargo doc +``` + +Open Crate Doc +``` +cargo doc --open +``` diff --git a/src/botcore.rs b/src/botcore.rs index e69de29..96f1e66 100644 --- a/src/botcore.rs +++ b/src/botcore.rs @@ -0,0 +1 @@ +pub mod bot; \ No newline at end of file diff --git a/src/botcore/bot.rs b/src/botcore/bot.rs new file mode 100644 index 0000000..f01a489 --- /dev/null +++ b/src/botcore/bot.rs @@ -0,0 +1,104 @@ + + +use tokio::sync::{mpsc::UnboundedReceiver, Mutex}; +use twitch_irc::{login::StaticLoginCredentials, message::ServerMessage, SecureTCPTransport, TwitchIRCClient}; +use dotenv::dotenv; +use std::env; + +/// Twitch chat bot +pub struct Bot { + /// Prefix for commands + _prefix: char, + /// inbound chat msg stream + incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>, + /// outbound chat client msg stream + client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, + /// joined channels + botchannels: Vec<String>, +} + + +impl Bot { + + /// Creates a new `Bot` using env variables + /// + /// Be sure the following is defined in an `.env` file + /// - login_name + /// - access_token + /// - bot_channels + /// - prefix + /// - bot_admins + pub fn new() -> Bot { + + dotenv().ok(); + let bot_login_name = env::var("login_name").unwrap().to_owned(); + let oauth_token = env::var("access_token").unwrap().to_owned(); + let prefix = env::var("prefix") + .unwrap() + .to_owned() + .chars() + .next() + .expect("ERROR : when defining prefix"); + + let mut botchannels = Vec::new(); + + for chnl in env::var("bot_channels").unwrap().split(',') { + botchannels.push(chnl.to_owned()); + } + + Bot::new_from(bot_login_name, oauth_token, prefix, botchannels) + + + } + + /// Creates a new `Bot` using bot information + /// + /// Bot joined channels will include channels from `.env` and `botchannels` argument + pub fn new_from(bot_login_name:String,oauth_token:String,prefix:char,botchannels:Vec<String>) -> Bot { + + dotenv().ok(); + let bot_login_name = bot_login_name; + + let config = twitch_irc::ClientConfig::new_simple(StaticLoginCredentials::new( + bot_login_name.to_owned(), + Some(oauth_token.to_owned()), + )); + + let (incoming_messages, client) = + TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config); + + let mut botchannels_all = Vec::new(); + botchannels_all.extend(botchannels); + + for chnl in env::var("bot_channels").unwrap().split(',') { + botchannels_all.push(chnl.to_owned()); + } + + Bot { + _prefix : prefix, + incoming_msgs : Mutex::new(incoming_messages), + client, + botchannels : botchannels_all, + } + } + + /// Runs the bot + pub async fn run(self) { + + for chnl in &self.botchannels { + self.client.join(chnl.to_owned()).unwrap(); + } + + let join_handle = tokio::spawn(async move { + let mut in_msgs_lock = self.incoming_msgs.lock().await; + while let Some(message) = in_msgs_lock.recv().await { + //sprintln!("Received message: {:?}", message); + dbg!("Received message: {:?}", message); + } + drop(in_msgs_lock); + }); + + join_handle.await.unwrap(); + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6448eeb..93f840e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,40 +1,26 @@ -use dotenv::dotenv; -use twitch_irc::{login::StaticLoginCredentials, ClientConfig, SecureTCPTransport, TwitchIRCClient}; -use std::env; +//! Example simple Binary crate that creates & runs bot based on `.env` +//! Be sure the followig is defined in `.env` +//! - login_name +//! - access_token +//! - bot_channels +//! - prefix +//! - bot_admins +//! +//! Bot access tokens be generated here - +//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> +//! - More Info - <https://dev.twitch.tv/docs/authentication> + +pub use botcore::bot::Bot; mod botcore; #[tokio::main] pub async fn main() { - - dotenv().ok(); - let login_name = env::var("login_name").unwrap().to_owned(); - let oauth_token = env::var("access_token").unwrap().to_owned(); - let mut botchannels = Vec::new(); + /* 1. Create the bot using env */ + let bot = Bot::new(); - for chnl in env::var("bot_channels").unwrap().split(',') { - botchannels.push(chnl.to_owned()); - } - - let config = ClientConfig::new_simple(StaticLoginCredentials::new( - login_name.to_owned(), - Some(oauth_token.to_owned()), - )); - - let (mut incoming_messages, client) = - TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config); - - for chnl in botchannels { - client.join(chnl.to_owned()).unwrap(); - } - - let join_handle = tokio::spawn(async move { - while let Some(message) = incoming_messages.recv().await { - println!("Received message: {:?}", message); - } - }); - - join_handle.await.unwrap(); + /* 2. Run the bot */ + bot.run().await; }