Merge pull request 'Custom Exec Bodies for BotCommand and Listeners' (#9) from dev into main

Reviewed-on: #9
This commit is contained in:
modulatingforce 2024-01-29 05:46:43 -05:00
commit c0102ba052
7 changed files with 411 additions and 291 deletions

View file

@ -5,12 +5,11 @@ test ModulatingForceBot
## Usage ## Usage
1. Set the following environment variables ; either on environment variables or in an .env file 1. Set the following environment variables ; either on environment variables or in an `.env` file
`login_name = <botname>` ```
login_name = <botname>
`access_token = <oath token>` access_token = <oath token>
bot_channels = <chnl1>,<chnl2>
`bot_channels = <chnl1>,<chnl2>` prefix = <prefix>
```
`prefix = <prefix>`

View file

@ -16,22 +16,14 @@ use std::collections::HashMap;
use rand::Rng; use rand::Rng;
//mod sub::ratelimiter;
use crate::core::ratelimiter::RateLimiter; use crate::core::ratelimiter::RateLimiter;
use crate::core::ratelimiter; use crate::core::ratelimiter;
// use crate::core::ratelimiter;
// pub fn init() -> ()
// {
// println!("I was here");
// }
use crate::core::botmodules; use crate::core::botmodules;
use crate::core::botmodules::ModulesManager; use crate::core::botmodules::ModulesManager;
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ChType { pub enum ChType {
Channel(String), Channel(String),
} }
@ -45,41 +37,116 @@ pub enum ModType {
pub use ModType::BotModule; pub use ModType::BotModule;
pub enum EnType { #[derive(Clone)]
Enabled(ChType), pub struct Chat {
pub ratelimiters : HashMap<ChType,RateLimiter>, // used to limit messages sent per channel
pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>,
} }
pub use EnType::Enabled; impl Chat {
// pub enum ModStatusType {
// Enabled(EnType),
// Disabled(EnType),
// Enabled(ModType),
// Disabled(ModType),
// }
pub struct BotInstance { 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) -> () {
/*
formats message before sending to TwitchIRC
- [x] Custom String Formatting (e.g., adding random black spaces)
- [x] Ratelimiter Handling
- [ ] Checkf if BotActions is Enabled & Caller is Allowed to Run
*/
// 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
{
prefix : char, prefix : char,
bot_channel : ChType, bot_channel : ChType,
pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>,
pub incoming_messages : UnboundedReceiver<ServerMessage>, 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, pub botmodules : ModulesManager,
twitch_oauth : String, twitch_oauth : String,
pub bot_channels : Vec<ChType>, pub bot_channels : Vec<ChType>,
/*bot_commands : Vec[BotCommand],
bot_listeners : Vec[Listener],
bot_routines : Vec[Routine],*/
// botactionsdb : botactionsdb:botactions,
// identity : identitymodule,
} }
impl BotInstance {
pub fn init() -> BotInstance { impl BotInstance
{
pub fn init() -> BotInstance
{
dotenv().ok(); dotenv().ok();
let login_name = env::var("login_name").unwrap().to_owned(); let login_name = env::var("login_name").unwrap().to_owned();
@ -115,47 +182,52 @@ impl BotInstance {
// ratelimiters are a hashmap of channel and a corresponding rate limiter // ratelimiters are a hashmap of channel and a corresponding rate limiter
let n = RateLimiter::new(); let n = RateLimiter::new();
ratelimiters.insert(Channel(String::from(chnl)),n); ratelimiters.insert(Channel(String::from(chnl)),n);
//self.chat.ratelimiters.insert(Channel(String::from(chnl)),n);
} }
// let bm = &mut ModulesManager::init();
let b = BotInstance { let b = BotInstance {
prefix : prefix, prefix : prefix,
bot_channel : Channel(login_name) , bot_channel : Channel(login_name) ,
incoming_messages : incoming_messages, incoming_messages : incoming_messages,
//client : client,
chat : Chat {
ratelimiters : ratelimiters,
client : client, client : client,
ratelimiters : ratelimiters, // used to limit messages sent per channel } ,
// botmodules : HashMap::new(),
botmodules : ModulesManager::init(), botmodules : ModulesManager::init(),
twitch_oauth : oauth_token, twitch_oauth : oauth_token,
bot_channels : botchannels, bot_channels : botchannels,
/*bot_commands : Vec[BotCommand],
bot_listeners : Vec[Listener],
bot_routines : Vec[Routine],*/
// botactionsdb : botactionsdb:botactions,
// identity : identitymodule,
}; };
println!("{:?}",b.ratelimiters); println!("{:?}",b.chat.ratelimiters);
b b
} }
pub async fn runner(mut self) -> () {
pub async fn run(mut self) -> () {
let join_handle = tokio::spawn(async move { let join_handle = tokio::spawn(async move {
while let Some(message) = self.incoming_messages.recv().await { while let Some(message) = self.incoming_messages.recv().await {
// Below can be used to debug if I want to capture all messages // Below can be used to debug if I want to capture all messages
// println!("Received message: {:?}", message); //println!("Received message: {:?}", message);
match message { match message {
ServerMessage::Notice(msg) => { ServerMessage::Notice(msg) => {
if let Some(chnl) = msg.channel_login { // if let Some(chnl) = msg.channel_login {
println!("NOTICE : (#{}) {}", chnl, msg.message_text); // 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) => { ServerMessage::Privmsg(msg) => {
@ -164,7 +236,9 @@ impl BotInstance {
println!("Privmsg section"); println!("Privmsg section");
// b.listener_main_prvmsg(&msg); // b.listener_main_prvmsg(&msg);
self.listener_main_prvmsg(&msg).await; self.listener_main_prvmsg(msg).await;
// - BotCommand listener should likely need to be called within the above
}, },
ServerMessage::Whisper(msg) => { ServerMessage::Whisper(msg) => {
@ -193,44 +267,74 @@ impl BotInstance {
// PRIVATE FUNCTIONS // PRIVATE FUNCTIONS
async fn listener_main_prvmsg(&mut self,msg:& PrivmsgMessage) -> () { async fn listener_main_prvmsg(&mut self,msg:PrivmsgMessage) -> () {
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
// // [ ] 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)
// // let contextratelimiter = ratelimiters.get_mut(&msg.channel_login).expect("ERROR: Issue with Rate limiters"); for (_m,acts) in &self.botmodules.botactions {
let contextratelimiter = self.ratelimiters for a in acts {
.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() { match a {
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 { crate::core::botmodules::BotAction::C(c) => {
let blankspace: &str = "󠀀"; /*
outmsg.push_str(blankspace); BotCommand handling -
- [x] Checks if the input message is a prefix with command name or alias
*/
let inpt = msg.message_text.split("\n").next().expect("ERROR during BotCommand");
// [x] Check if a bot command based on ...
// [x] prefix + command
if inpt == self.prefix.to_string() + c.command.as_str() {
c.execute(self.chat.clone(), msg.clone()).await;
} }
// client.say_in_reply_to(&msg,outmsg).await.unwrap(); // [x] prefix + alias
self.client.say_in_reply_to(msg,outmsg).await.unwrap(); for alias in &c.alias {
println!("(#{}) > {}", msg.channel_login, "rate limit counter increase"); if inpt == self.prefix.to_string() + alias.as_str() {
contextratelimiter.increment_counter(); c.execute(self.chat.clone(), msg.clone()).await;
println!("{:?}",self.ratelimiters); }
}
}, },
ratelimiter::LimiterResp::Skip => {
(); // do nothing otherwise crate::core::botmodules::BotAction::L(l) => l.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"); println!("End of Separate Listener Main prvmsg");
} }
} }
// ======================================
// ======================================
// ======================================
// ======================================
// UNIT TEST MODULES
#[cfg(test)]
mod tests {
fn always() {
assert_eq!(1,1);
}
}

View file

@ -39,6 +39,7 @@ pub enum ChType {
pub use ChType::Channel; pub use ChType::Channel;
use twitch_irc::message::PrivmsgMessage;
use crate::core::botinstance::{self, BotInstance}; use crate::core::botinstance::{self, BotInstance};
@ -55,170 +56,153 @@ pub enum ModStatusType {
Disabled(StatusLvl), Disabled(StatusLvl),
} }
// pub use EnType::Enabled; pub enum BotAction
{
#[derive(Debug)]
pub enum BotAction {
C(BotCommand), C(BotCommand),
L(Listener), L(Listener),
R(Routine), R(Routine),
} }
#[derive(Debug)]
impl BotAction {
pub async fn execute(&self,m:botinstance::Chat,n:PrivmsgMessage){
match self {
BotAction::L(a) => a.execute(m,n).await,
BotAction::C(a) => a.execute(m,n).await,
_ => (),
}
}
}
pub trait BotActionTrait
{
fn add_to_bot(self, bot:BotInstance);
fn add_to_modmgr(self,modmgr:&mut ModulesManager);
}
pub struct BotCommand { pub struct BotCommand {
pub module : ModType, pub module : ModType,
pub command : String, // command call name pub command : String, // command call name
pub alias : Vec<String>, // String of alternative names pub alias : Vec<String>, // String of alternative names
// bot_prefix : char, // although should be global? // bot_prefix : char, // although should be global?
// exec_body : fn, pub exec_body : bot_actions::actions_util::ExecBody,
pub help : String, pub help : String,
} }
impl BotCommand { impl BotCommand
pub fn add_to_bot(self, bot:BotInstance) { {
// let mut mgr = bot.botmodules; pub async fn execute(&self,m:botinstance::Chat,n:PrivmsgMessage){
// let nmod = self.module.clone(); (self.exec_body)(m,n).await;
// mgr.add_botaction(nmod, BotAction::C(self)); }
let mut mgr = bot.botmodules; }
//let nmod = self.module.clone();
// mgr.add_botaction(self.module.clone(), BotAction::C(self));
self.add_to_modmgr(&mut mgr);
impl BotActionTrait for BotCommand
{
fn add_to_bot(self, mut bot:BotInstance) {
let mgr = &mut bot.botmodules;
self.add_to_modmgr(mgr);
} }
fn add_to_modmgr(self, modmgr:&mut ModulesManager) {
modmgr.add_botaction(self.module.clone(), BotAction::C(self))
}
pub fn add_to_modmgr(self, modmgr:&mut ModulesManager) { }
// // let mut mgr = bot.botmodules;
// // let nmod = self.module.clone();
// // mgr.add_botaction(nmod, BotAction::C(self));
// let mut mgr = modmgr; pub mod bot_actions {
// //let nmod = self.module.clone();
// mgr.add_botaction(self.module.clone(), BotAction::C(self)); pub mod actions_util {
// let mut mgr = modmgr;
// //let nmod = self.module.clone(); use std::future::Future;
modmgr.add_botaction(self.module.clone(), BotAction::C(self)); use std::boxed::Box;
use std::pin::Pin;
use crate::core::botinstance::Chat;
use twitch_irc::message::PrivmsgMessage;
pub type ExecBody = Box<dyn Fn(Chat,PrivmsgMessage) -> Pin<Box<dyn Future<Output=()> + Send>> + Send + Sync>;
pub fn asyncbox<T>(f: fn(Chat,PrivmsgMessage) -> T) -> ExecBody
where
T: Future<Output=()> + Send + 'static,
{
Box::new(move |a,b| Box::pin(f(a,b)))
}
} }
} }
#[derive(Debug)]
struct Listener {
module : ModType, pub struct Listener
name : String, {
// exec_body : fn, pub module : ModType,
help : String pub name : String,
pub exec_body : bot_actions::actions_util::ExecBody,
pub help : String
} }
impl Listener
{
pub async fn execute(&self,m:botinstance::Chat,n:PrivmsgMessage){
(self.exec_body)(m,n).await;
}
}
impl BotActionTrait for Listener
{
fn add_to_bot(self, mut bot:BotInstance) {
let mgr = &mut bot.botmodules;
self.add_to_modmgr(mgr);
}
fn add_to_modmgr(self, modmgr:&mut ModulesManager) {
modmgr.add_botaction(self.module.clone(), BotAction::L(self))
}
}
#[derive(Debug)] #[derive(Debug)]
struct Routine {} struct Routine {}
pub struct ModulesManager
#[derive(Debug)] {
pub struct ModulesManager {
statusdb: HashMap<ModType,Vec<ModStatusType>>, statusdb: HashMap<ModType,Vec<ModStatusType>>,
botactions: HashMap<ModType,Vec<BotAction>>, pub botactions: HashMap<ModType,Vec<BotAction>>,
} }
impl ModulesManager { impl ModulesManager
{
pub fn init() -> ModulesManager { pub fn init() -> ModulesManager
{
// initializes the modulers manager
// Ideally, this should have added known modules based on
// directory structure and API user recommendations
let mut m = HashMap::new();
let mut act = HashMap::new();
// -- some processing including adding into the hashmap
// let newmodule = BotModule(String::from("GambaCore"));
// let newlistener = Listener {
// module : BotModule(String::from("experiments").to_owned()),
// name : String::from("socklistener"),
// help : String::from("This will listen and react to sock randomly"),
// };
// // As a Demonstration, the listener's Module is added and Enabled at Instance level let m = HashMap::new();
// let statusvector = m let act = HashMap::new();
// .entry(BotModule(String::from("experiments")))
// .or_insert(Vec::new());
// statusvector.push(ModStatusType::Enabled(StatusLvl::Instance));
// let modactions = act
// .entry( BotModule(String::from("experiments")))
// .or_insert(Vec::new());
// modactions.push(BotAction::L(newlistener));
let mut mgr = ModulesManager { let mut mgr = ModulesManager {
statusdb : m, statusdb : m,
botactions : act, botactions : act,
}; };
// // -- This area can be where bot actions are imported to the bot's module manager
// // -- Below can be used to validate what occurs when dup BotCommands are added // initialize custom crate modules
// let bcmd = BotCommand {
// module : BotModule(String::from("experiments 001")),
// command : String::from("DUPCMD1"), // command call name
// alias : vec![String::from("DUPALIAS1A"),String::from("DUPALIAS1B")], // String of alternative names
// // bot_prefix : char, // although should be global?
// // exec_body : fn,
// help : String::from("DUPCMD1 tester"),
// };
// mgr.add_botaction(BotModule(String::from("experiments 001")), BotAction::C(bcmd));
// let bcmd = BotCommand {
// module : BotModule(String::from("experiments 002")),
// command : String::from("DUPCMD2"), // command call name
// alias : vec![String::from("DUPALIAS2A"),String::from("DUPALIAS2B")], // String of alternative names
// // bot_prefix : char, // although should be global?
// // exec_body : fn,
// help : String::from("DUPCMD2 tester"),
// };
// mgr.add_botaction(BotModule(String::from("experiments 002")), BotAction::C(bcmd));
// -- Below working demonstration of BotCommand.add_to_modmgr()
// BotCommand {
// module : BotModule(String::from("experiments 003")),
// command : String::from("DUPCMD3"), // command call name
// alias : vec![String::from("DUPALIAS3A"),String::from("DUPALIAS3B")], // String of alternative names
// // bot_prefix : char, // although should be global?
// // exec_body : fn,
// help : String::from("DUPCMD3 tester"),
// }.add_to_modmgr(&mut mgr);
// crate::core::botmodules::BotCommand{
// module : BotModule(String::from("experiments 003")),
// command : String::from("DUPCMD3"), // command call name
// alias : vec![String::from("DUPALIAS3A"),String::from("DUPALIAS3B")], // String of alternative names
// // bot_prefix : char, // although should be global?
// // exec_body : fn,
// help : String::from("DUPCMD3 tester"),
// };
// // => 2023.12.22 - [x] MF : How can I call submods:init() ?
// // => 2023.12.22 - this was answered - needed to pub modules in main.rs
// crate::core::botinstance::init(); // works
// crate::core::init(); // works
//crate::submods::
//crate::arbfile;
crate::modules::init(&mut mgr); crate::modules::init(&mut mgr);
println!(">> Modules Manager : End of Init"); println!(">> Modules Manager : End of Init");
println!(">> Modules Manager : {:?}",mgr);
mgr mgr
} }
@ -247,8 +231,10 @@ impl ModulesManager {
Ok("") Ok("")
} }
//pub fn add_botaction(mut self, in_module:ModType, in_action:BotAction ) -> ModulesManager {
pub fn add_botaction(&mut self, in_module:ModType, in_action:BotAction ) -> () { // pub fn add_botaction(mut self, in_module:ModType, in_action:BotAction<F> ) -> ModulesManager<F> {
//pub fn add_botaction(&mut self, in_module:ModType, in_action:BotAction ) -> () {
pub fn add_botaction(&mut self, in_module:ModType, in_action:BotAction ) {
/* /*
adds a BotAction to the Modules Manager - This will require a BotModule passed as well adds a BotAction to the Modules Manager - This will require a BotModule passed as well
This will including the logic of a valid add This will including the logic of a valid add
@ -276,7 +262,8 @@ impl ModulesManager {
// - If BotAction to Add is a BotCommand , In Module Manager DB (botactions), // - If BotAction to Add is a BotCommand , In Module Manager DB (botactions),
// Check All Other BotAction Command Names & Aliases to ensure they don't conflict // Check All Other BotAction Command Names & Aliases to ensure they don't conflict
fn find_conflict_module(mgr:& ModulesManager, act:& BotAction) -> Option<ModType> { fn find_conflict_module(mgr:& ModulesManager, act:& BotAction) -> Option<ModType>
{
// Some(BotModule(String::from("GambaCore"))) // Some(BotModule(String::from("GambaCore")))
@ -289,70 +276,70 @@ impl ModulesManager {
// BotAction::R(r) => None, // BotAction::R(r) => None,
// } // }
if let BotAction::C(incmd) = act { // if let BotAction::C(incmd) = act {
// let n = & mgr.botactions; // // let n = & mgr.botactions;
let d = &mgr.botactions; // let d = &mgr.botactions;
for (module,moduleactions) in d { // for (module,moduleactions) in d {
for modact in moduleactions.iter() { // for modact in moduleactions.iter() {
if let BotAction::C(dbcmd) = &modact { // if let BotAction::C(dbcmd) = &modact {
// At this point, there is an command incmd and looked up dbcmd // // At this point, there is an command incmd and looked up dbcmd
// [x] check if given botcommand c.command:String conflicts with any in botactions // // [x] check if given botcommand c.command:String conflicts with any in botactions
if incmd.command.to_lowercase() == dbcmd.command.to_lowercase() { // if incmd.command.to_lowercase() == dbcmd.command.to_lowercase() {
// Returning State - with the identified module // // Returning State - with the identified module
// return Some((module.clone(),BotAction::C(*dbcmd.clone()))); // // return Some((module.clone(),BotAction::C(*dbcmd.clone())));
// return Some(incmd); // for some reason I keep getting issues // // return Some(incmd); // for some reason I keep getting issues
//return Some(BotModule(String::from("GambaCore"))); // works // //return Some(BotModule(String::from("GambaCore"))); // works
return Some(module.clone()); // works // return Some(module.clone()); // works
// return Some(dbcmd.clone()); // // return Some(dbcmd.clone());
} // }
for a in &dbcmd.alias { // for a in &dbcmd.alias {
if incmd.command.to_lowercase() == a.to_lowercase() { // if incmd.command.to_lowercase() == a.to_lowercase() {
// Returning State - with the identified module // // Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd))); // // return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works // return Some(module.clone()); // works
} // }
} // }
// [x] Then do the same check except for each c.alias // // [x] Then do the same check except for each c.alias
for inalias in &incmd.alias { // for inalias in &incmd.alias {
if inalias.to_lowercase() == dbcmd.command.to_lowercase() { // if inalias.to_lowercase() == dbcmd.command.to_lowercase() {
// Returning State - with the identified module // // Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd))); // // return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works // return Some(module.clone()); // works
} // }
for a in &dbcmd.alias { // for a in &dbcmd.alias {
if inalias.to_lowercase() == a.to_lowercase() { // if inalias.to_lowercase() == a.to_lowercase() {
// Returning State - with the identified module // // Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd))); // // return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works // return Some(module.clone()); // works
} // }
} // }
} // }
} // }
} // }
} // }
// return Some(BotModule(String::from("GambaCore"))) // // return Some(BotModule(String::from("GambaCore")))
} // }
// for all other scenarios (e.g., Listener, Routine), find no conflicts // for all other scenarios (e.g., Listener, Routine), find no conflicts
@ -365,7 +352,8 @@ impl ModulesManager {
// panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , probmod ); // panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , probmod );
// } // }
match find_conflict_module(&self, &in_action) { match find_conflict_module(&self, &in_action) {
Some(c) => panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , c ), // Some(c) => panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , c ),
Some(c) => panic!("ERROR: Could not add module; there was a conflict with existing module {:?}", c ),
None => (), None => (),
} }
@ -385,9 +373,14 @@ impl ModulesManager {
modactions.push(in_action); modactions.push(in_action);
println!(">> Modules Manager : Called Add bot Action"); println!(">> Modules Manager : Called Add bot Action");
println!(">> Modules Manager : {:?}",&self); //println!(">> Modules Manager : {:?}",&self);
(); //();
//let mgr = self;
//mgr
//self
} }

View file

@ -5,7 +5,7 @@ const TIME_THRESHOLD_S: u64 = 30;
const MSG_THRESHOLD: u32 = 20; const MSG_THRESHOLD: u32 = 20;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct RateLimiter { pub struct RateLimiter {
timer: Instant, timer: Instant,
msgcounter: u32, msgcounter: u32,

View file

@ -1,22 +1,9 @@
// use twitch_irc::login::StaticLoginCredentials;
// use twitch_irc::ClientConfig;
// use twitch_irc::SecureTCPTransport;
// use twitch_irc::TwitchIRCClient;
// use twitch_irc::message::ServerMessage;
// use std::env;
// // use std::time::Instant;
// use rand::Rng;
// use dotenv::dotenv;
// // mod helpers;
// use std::collections::HashMap;
pub mod core; pub mod core;
pub mod modules; pub mod modules;
use std::process::Output;
use crate::core::botinstance::BotInstance; use crate::core::botinstance::BotInstance;
#[tokio::main] #[tokio::main]
@ -24,7 +11,6 @@ pub async fn main() {
let bot = BotInstance::init(); let bot = BotInstance::init();
bot.runner().await;
bot.run().await;
} }

View file

@ -19,12 +19,18 @@ mod experiments;
// [ ] init() function that accepts bot instance - this is passed to init() on submodules // [ ] init() function that accepts bot instance - this is passed to init() on submodules
pub fn init(mgr:&mut ModulesManager) -> () { // pub fn init<F>(mgr:ModulesManager<F>) -> ModulesManager<F>
// pub fn init<F>(mgr:ModulesManager<F>)
// where
// // F: std::future::Future + Send,
// // F : Send,
// F : Send + ?Sized,
pub fn init(mgr:&mut ModulesManager)
{
// Modules initializer loads modules into the bot // Modules initializer loads modules into the bot
// this is achieved by calling submodules that also have fn init() defined // this is achieved by calling submodules that also have fn init() defined
experiments::init(mgr); experiments::init(mgr)
//();
();
} }

View file

@ -12,22 +12,54 @@
// mod crate::modules; // mod crate::modules;
//use crate::modules; //use crate::modules;
use crate::core::botmodules::{ModulesManager,BotCommand,BotModule}; use std::future::Future;
pub fn init(mgr:&mut ModulesManager) -> () { use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait, BotCommand};
use crate::core::botmodules::bot_actions::actions_util;
use crate::core::botinstance::{self};
use twitch_irc::message::PrivmsgMessage;
pub fn init(mgr:&mut ModulesManager)
{
BotCommand { BotCommand {
module : BotModule(String::from("experiments 004")), module : BotModule(String::from("experiments 004")),
command : String::from("DUPCMD4"), // command call name command : String::from("test"), // command call name
alias : vec![String::from("DUPALIAS4A"),String::from("DUPALIAS4B")], // String of alternative names alias : vec![String::from("tester"),String::from("testy")], // String of alternative names
// bot_prefix : char, // although should be global? exec_body : actions_util::asyncbox(testy) ,
// exec_body : fn,
help : String::from("DUPCMD4 tester"), help : String::from("DUPCMD4 tester"),
}.add_to_modmgr(mgr); }.add_to_modmgr(mgr);
println!("At Experiments module");
let list1 = Listener {
module : BotModule(String::from("experiments 004")),
name : String::from("GoodGirl Listener"),
exec_body : actions_util::asyncbox(good_girl) ,
help : String::from("")
};
list1.add_to_modmgr(mgr);
(); }
async fn good_girl(mut chat:botinstance::Chat,msg:PrivmsgMessage)
{
println!("In GoodGirl()");
//println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
if msg.sender.name == "ModulatingForce" && msg.message_text.contains("GoodGirl") {
chat.say_in_reply_to(&msg,String::from("GoodGirl")).await;
}
}
async fn testy(mut _chat:botinstance::Chat,_msg:PrivmsgMessage)
{
println!("testy triggered!")
} }