forcebot_rs/src/core/botinstance.rs

447 lines
14 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use tokio::sync::mpsc::UnboundedReceiver;
use twitch_irc::login::StaticLoginCredentials;
use twitch_irc::ClientConfig;
use twitch_irc::SecureTCPTransport;
use twitch_irc::TwitchIRCClient;
use twitch_irc::message::PrivmsgMessage;
use twitch_irc::message::ServerMessage;
use twitch_irc::transport::tcp::TCPTransport;
use twitch_irc::transport::tcp::TLS;
use std::env;
use dotenv::dotenv;
use std::collections::HashMap;
use rand::Rng;
//mod sub::ratelimiter;
use crate::core::ratelimiter::RateLimiter;
use crate::core::ratelimiter;
// use crate::core::ratelimiter;
// pub fn init() -> ()
// {
// println!("I was here");
// }
// use crate::core::botmodules::BotAction
use crate::core::botmodules;
use crate::core::botmodules::ModulesManager;
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ChType {
Channel(String),
}
pub use ChType::Channel;
pub enum ModType {
BotModule(String),
}
pub use ModType::BotModule;
// pub enum EnType {
// Enabled(ChType),
// }
// pub use EnType::Enabled;
// pub enum ModStatusType {
// Enabled(EnType),
// Disabled(EnType),
// Enabled(ModType),
// Disabled(ModType),
// }
#[derive(Clone)]
pub struct Chat {
pub ratelimiters : HashMap<ChType,RateLimiter>, // used to limit messages sent per channel
pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>,
}
impl Chat {
pub fn init_channel(&mut self, chnl:ChType) -> () {
let n = RateLimiter::new();
self.ratelimiters.insert(chnl,n);
}
pub async fn say_in_reply_to(&mut self, msg:& PrivmsgMessage , mut outmsg:String) -> () {
// envelops a message before sending a message
// [x] This could include additional formatting (e.g., add in random number of blank spaces)
// [x] Incrementing or checking with RateLimiters
// [ ] For BotActions of Enabled Modules , checking whether the caller is Permissible to run the command ?
// self.client.say_in_reply_to(msg,outmsg).await.unwrap();
// // let contextratelimiter = ratelimiters.get_mut(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
let contextratelimiter = self.ratelimiters
.get_mut(&Channel(String::from(&msg.channel_login)))
.expect("ERROR: Issue with Rate limiters");
// let contextratelimiter = self.ratelimiters.get(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
match contextratelimiter.check_limiter() {
ratelimiter::LimiterResp::Allow => {
let maxblanks = rand::thread_rng().gen_range(1..=20);
//let mut outmsg = "GotTrolled ".to_owned();
// let mut outmsg = "annytfLurk ".to_owned();
for _i in 1..maxblanks {
let blankspace: &str = "󠀀";
outmsg.push_str(blankspace);
}
// client.say_in_reply_to(&msg,outmsg).await.unwrap();
self.client.say_in_reply_to(msg,outmsg).await.unwrap();
println!("(#{}) > {}", msg.channel_login, "rate limit counter increase");
contextratelimiter.increment_counter();
println!("{:?}",self.ratelimiters);
},
ratelimiter::LimiterResp::Skip => {
(); // do nothing otherwise
}
}
}
async fn say(&self, _:String, _:String) -> () {
// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
// self.client.say(msg,outmsg).await.unwrap();
}
async fn me(&self, _:String, _:String) -> () {
// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
// self.client.me(msg,outmsg).await.unwrap();
}
async fn me_in_reply_to(&self, _:String, _:String) -> () {
// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
// self.client.me(msg,outmsg).await.unwrap();
}
}
// pub struct BotInstance<F>
// where
// // F: std::future::Future + ?Sized,
// // F: std::future::Future,
// //F: std::future::Future + Send,
// F: Send + ?Sized,
pub struct BotInstance
{
prefix : char,
bot_channel : ChType,
//pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>,
pub incoming_messages : UnboundedReceiver<ServerMessage>,
// pub ratelimiters : HashMap<ChType,RateLimiter>, // used to limit messages sent per channel
pub chat : Chat,
// botmodules : HashMap<ModType,Vec<EnType>>,
// pub botmodules : ModulesManager<F>,
pub botmodules : ModulesManager,
//pub botmodules : &'static mut ModulesManager,
twitch_oauth : String,
pub bot_channels : Vec<ChType>,
/*bot_commands : Vec[BotCommand],
bot_listeners : Vec[Listener],
bot_routines : Vec[Routine],*/
// botactionsdb : botactionsdb:botactions,
// identity : identitymodule,
}
// impl<F> BotInstance<F>
// where
// // F: std::future::Future + 'static,
// //F: 'static,
// //F: std::future::Future + Send + ?Sized 'static,
// F: Send + ?Sized + 'static,
impl BotInstance
{
// pub fn init() -> BotInstance<F>
// where
// F: std::future::Future + 'static,
pub fn init() -> BotInstance
{
dotenv().ok();
let 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");
/*
Vector of channels to join
*/
let mut botchannels = Vec::new();
for chnl in env::var("bot_channels").unwrap().split(',') {
// println!("(Env Var # {})",chnl);
botchannels.push(Channel(String::from(chnl)));
}
let config = ClientConfig::new_simple(
StaticLoginCredentials::new(login_name.to_owned(), Some(oauth_token.to_owned()))
);
let (incoming_messages, client) =
TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config);
// hashmap for channels and their associated ratelimiters
let mut ratelimiters = HashMap::new();
for Channel(chnl) in &botchannels {
// For each channel in botchannels
client.join(chnl.to_owned()).unwrap();
// ratelimiters are a hashmap of channel and a corresponding rate limiter
let n = RateLimiter::new();
ratelimiters.insert(Channel(String::from(chnl)),n);
//self.chat.ratelimiters.insert(Channel(String::from(chnl)),n);
}
// let bm = &mut ModulesManager::init();
let b = BotInstance {
prefix : prefix,
bot_channel : Channel(login_name) ,
incoming_messages : incoming_messages,
//client : client,
chat : Chat {
ratelimiters : ratelimiters,
client : client,
} ,
// ratelimiters : ratelimiters, // used to limit messages sent per channel
// botmodules : HashMap::new(),
botmodules : ModulesManager::init(),
//botmodules : bm,
twitch_oauth : oauth_token,
bot_channels : botchannels,
/*bot_commands : Vec[BotCommand],
bot_listeners : Vec[Listener],
bot_routines : Vec[Routine],*/
// botactionsdb : botactionsdb:botactions,
// identity : identitymodule,
};
println!("{:?}",b.chat.ratelimiters);
b
}
pub async fn runner(mut self) -> () {
let join_handle = tokio::spawn(async move {
while let Some(message) = self.incoming_messages.recv().await {
// Below can be used to debug if I want to capture all messages
//println!("Received message: {:?}", message);
match message {
ServerMessage::Notice(msg) => {
// if let Some(chnl) = msg.channel_login {
// println!("NOTICE : (#{}) {}", chnl, msg.message_text);
// }
match msg.channel_login {
Some(chnl) => println!("NOTICE : (#{}) {}", chnl, msg.message_text),
None => println!("NOTICE : {}", msg.message_text),
}
}
ServerMessage::Privmsg(msg) => {
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
println!("Privmsg section");
// b.listener_main_prvmsg(&msg);
self.listener_main_prvmsg(msg).await;
// - BotCommand listener should likely need to be called within the above
},
ServerMessage::Whisper(msg) => {
println!("(w) {}: {}", msg.sender.name, msg.message_text);
},
ServerMessage::Join(msg) => {
println!("JOINED: {}", msg.channel_login);
},
ServerMessage::Part(msg) => {
println!("PARTED: {}", msg.channel_login);
},
_ => {}
}
}
});
join_handle.await.unwrap();
}
// pub async fn run(mut self) -> () {
// let join_handle = tokio::spawn(async move {
// while let Some(message) = self.incoming_messages.recv().await {
// // Below can be used to debug if I want to capture all messages
// // println!("Received message: {:?}", message);
// match message {
// ServerMessage::Notice(msg) => {
// if let Some(chnl) = msg.channel_login {
// println!("NOTICE : (#{}) {}", chnl, msg.message_text);
// }
// }
// ServerMessage::Privmsg(msg) => {
// println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
// println!("Privmsg section");
// // b.listener_main_prvmsg(&msg);
// self.listener_main_prvmsg(&msg).await;
// // - BotCommand listener should likely need to be called within the above
// },
// ServerMessage::Whisper(msg) => {
// println!("(w) {}: {}", msg.sender.name, msg.message_text);
// },
// ServerMessage::Join(msg) => {
// println!("JOINED: {}", msg.channel_login);
// },
// ServerMessage::Part(msg) => {
// println!("PARTED: {}", msg.channel_login);
// },
// _ => {}
// }
// }
// });
// join_handle.await.unwrap();
// }
// -----------------
// PRIVATE FUNCTIONS
async fn listener_main_prvmsg(&mut self,msg:PrivmsgMessage) -> () {
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
// // // let contextratelimiter = ratelimiters.get_mut(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
// let contextratelimiter = self.ratelimiters
// .get_mut(&Channel(String::from(&msg.channel_login)))
// .expect("ERROR: Issue with Rate limiters");
// // let contextratelimiter = self.ratelimiters.get(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
// match contextratelimiter.check_limiter() {
// ratelimiter::LimiterResp::Allow => {
// let maxblanks = rand::thread_rng().gen_range(1..=20);
// //let mut outmsg = "GotTrolled ".to_owned();
// let mut outmsg = "annytfLurk ".to_owned();
// for _i in 1..maxblanks {
// let blankspace: &str = "󠀀";
// outmsg.push_str(blankspace);
// }
// // client.say_in_reply_to(&msg,outmsg).await.unwrap();
// self.client.say_in_reply_to(msg,outmsg).await.unwrap();
// println!("(#{}) > {}", msg.channel_login, "rate limit counter increase");
// contextratelimiter.increment_counter();
// println!("{:?}",self.ratelimiters);
// },
// ratelimiter::LimiterResp::Skip => {
// (); // do nothing otherwise
// }
// self.chat.say_in_reply_to(msg,String::from("annytfLurk")).await;
// // [ ] Need to run through all Listener Bodies for Enabled Modules for the context of the message (e.g., ModStatus is Enabled in the context for the channel)
for (_m,acts) in &self.botmodules.botactions {
for a in acts {
if let crate::core::botmodules::BotAction::L(lsnr) = a {
lsnr.execute(self.chat.clone(),msg.clone()).await;
}
}
};
// // [ ] There should be a BotCommand Listener to check for prefixes ran
println!("End of Separate Listener Main prvmsg");
}
}
// ======================================
// ======================================
// ======================================
// ======================================
// UNIT TEST MODULES
#[cfg(test)]
mod tests {
fn always() {
assert_eq!(1,1);
}
}