Custom Exec Bodies for BotCommand and Listeners #9

Merged
modulatingforce merged 14 commits from dev into main 2024-01-29 05:46:43 -05:00
5 changed files with 296 additions and 160 deletions
Showing only changes of commit 4184527d19 - Show all commits

View file

@ -145,7 +145,10 @@ impl Chat {
pub struct BotInstance {
pub struct BotInstance<F>
where
F: std::future::Future + ?Sized,
{
prefix : char,
bot_channel : ChType,
//pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>,
@ -153,7 +156,7 @@ pub struct BotInstance {
// 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<F>,
twitch_oauth : String,
pub bot_channels : Vec<ChType>,
/*bot_commands : Vec[BotCommand],
@ -163,10 +166,18 @@ pub struct BotInstance {
// identity : identitymodule,
}
impl BotInstance {
pub fn init() -> BotInstance {
impl<F> BotInstance<F>
where
F: std::future::Future + 'static,
{
pub fn init() -> BotInstance<F>
where
F: std::future::Future + 'static,
{
dotenv().ok();
let login_name = env::var("login_name").unwrap().to_owned();
@ -237,6 +248,53 @@ impl BotInstance {
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);
}
}
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) -> () {
@ -341,3 +399,21 @@ impl BotInstance {
// ======================================
// ======================================
// ======================================
// ======================================
// UNIT TEST MODULES
#[cfg(test)]
mod tests {
fn always() {
assert_eq!(1,1);
}
}

View file

@ -59,130 +59,154 @@ pub enum ModStatusType {
// pub use EnType::Enabled;
#[derive(Debug)]
pub enum BotAction {
C(BotCommand),
L(Listener),
pub enum BotAction<F>
where
F: std::future::Future + ?Sized,
{
//C(BotCommand),
L(Listener<F>),
R(Routine),
}
pub trait BotActionTrait {
pub trait BotActionTrait<F>
where
F: std::future::Future,
{
// async fn execute(&self,m:&mut BotInstance,n:&PrivmsgMessage);
// fn add_to_bot(self, bot:BotInstance) -> Result<String,Box<dyn Error>>;
fn add_to_bot(self, bot:BotInstance);
fn add_to_modmgr(self, modmgr:&mut ModulesManager);
fn add_to_bot(self, bot:BotInstance<F>);
fn add_to_modmgr(self, modmgr:&mut ModulesManager<F>);
}
// #[derive(Debug)]
// pub struct BotCommand {
// pub module : ModType,
// pub command : String, // command call name
// pub alias : Vec<String>, // String of alternative names
// // bot_prefix : char, // although should be global?
// exec_body : fn(&BotInstance<F>,&PrivmsgMessage),
// pub help : String,
// }
// impl BotCommand {
// // pub fn add_to_bot(self, bot:BotInstance) {
// // // let mut mgr = bot.botmodules;
// // // let nmod = self.module.clone();
// // // 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);
// // }
// // 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;
// // // //let nmod = self.module.clone();
// // // mgr.add_botaction(self.module.clone(), BotAction::C(self));
// // // let mut mgr = modmgr;
// // // //let nmod = self.module.clone();
// // modmgr.add_botaction(self.module.clone(), BotAction::C(self));
// // }
// }
// impl BotActionTrait for BotCommand {
// // fn add_to_bot(&self) -> Result<String,Box<dyn Error>> {
// // println!("Calling Add to Bot");
// // Ok(String::from("Hello"))
// // }
// fn add_to_bot(self, bot:BotInstance) {
// // let mut mgr = bot.botmodules;
// // let nmod = self.module.clone();
// // 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);
// }
// fn add_to_modmgr<F>(self, modmgr:&mut ModulesManager<F>) {
// // // let mut mgr = bot.botmodules;
// // // let nmod = self.module.clone();
// // // mgr.add_botaction(nmod, BotAction::C(self));
// // let mut mgr = modmgr;
// // //let nmod = self.module.clone();
// // mgr.add_botaction(self.module.clone(), BotAction::C(self));
// // let mut mgr = modmgr;
// // //let nmod = self.module.clone();
// modmgr.add_botaction(self.module.clone(), BotAction::C(self));
// }
// // => 12.23 - MF: NOTE : The exec body is defined ad module level , not this core level
// // fn exec_body(&self,m:&BotInstance,n:&PrivmsgMessage){
// // // => 12.23 - [ ] #todo requires field
// // // (&self.exec)(String::from("Hello from BotAction Trait"))
// // //self.exec_body(m,n)
// // }
// // fn execute(&self,m:&mut BotInstance,n:&PrivmsgMessage){
// // // => 12.23 - [ ] #todo requires field
// // // (&self.exec)(String::from("Hello from BotAction Trait"))
// // //self.exec_body(m,n)
// // (self.exec_body)(m,n)
// // }
// }
// #[derive(Debug)]
// pub struct Listener {
// pub module : ModType,
// pub name : String,
// pub exec_body : fn(&mut BotInstance,&PrivmsgMessage) ,
// pub help : String
// }
#[derive(Debug)]
pub struct BotCommand {
pub module : ModType,
pub command : String, // command call name
pub alias : Vec<String>, // String of alternative names
// bot_prefix : char, // although should be global?
exec_body : fn(&BotInstance,&PrivmsgMessage),
pub help : String,
}
impl BotCommand {
// pub fn add_to_bot(self, bot:BotInstance) {
// // let mut mgr = bot.botmodules;
// // let nmod = self.module.clone();
// // 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);
// }
// 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;
// // //let nmod = self.module.clone();
// // mgr.add_botaction(self.module.clone(), BotAction::C(self));
// // let mut mgr = modmgr;
// // //let nmod = self.module.clone();
// modmgr.add_botaction(self.module.clone(), BotAction::C(self));
// }
}
impl BotActionTrait for BotCommand {
// fn add_to_bot(&self) -> Result<String,Box<dyn Error>> {
// println!("Calling Add to Bot");
// Ok(String::from("Hello"))
// }
fn add_to_bot(self, bot:BotInstance) {
// let mut mgr = bot.botmodules;
// let nmod = self.module.clone();
// 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);
}
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;
// //let nmod = self.module.clone();
// mgr.add_botaction(self.module.clone(), BotAction::C(self));
// let mut mgr = modmgr;
// //let nmod = self.module.clone();
modmgr.add_botaction(self.module.clone(), BotAction::C(self));
}
// => 12.23 - MF: NOTE : The exec body is defined ad module level , not this core level
// fn exec_body(&self,m:&BotInstance,n:&PrivmsgMessage){
// // => 12.23 - [ ] #todo requires field
// // (&self.exec)(String::from("Hello from BotAction Trait"))
// //self.exec_body(m,n)
// }
// fn execute(&self,m:&mut BotInstance,n:&PrivmsgMessage){
// // => 12.23 - [ ] #todo requires field
// // (&self.exec)(String::from("Hello from BotAction Trait"))
// //self.exec_body(m,n)
// (self.exec_body)(m,n)
// }
}
#[derive(Debug)]
pub struct Listener {
pub struct Listener<F: ?Sized>
where
F: std::future::Future,
{
pub module : ModType,
pub name : String,
pub exec_body : fn(&mut BotInstance,&PrivmsgMessage) ,
//pub exec_body : fn(&mut BotInstance,&PrivmsgMessage) ,
pub exec_body : fn(&mut Box<BotInstance<F>>,&PrivmsgMessage) -> F ,
pub help : String
}
impl Listener {
impl<F> Listener<F>
where
F: std::future::Future,
{
async fn execute(&self,m:&mut BotInstance,n:&PrivmsgMessage){
async fn execute(&self,m:&mut Box<BotInstance<F>>,n:&PrivmsgMessage){
// => 12.23 - [ ] #todo requires field
// (&self.exec)(String::from("Hello from BotAction Trait"))
//self.exec_body(m,n)
(self.exec_body)(m,n)
(self.exec_body)(m,n).await;
}
}
impl BotActionTrait for Listener {
impl<F> BotActionTrait<F> for Listener<F>
where
F: std::future::Future,
{
// fn add_to_bot(&self) -> Result<String,Box<dyn Error>> {
// println!("Calling Add to Bot");
// Ok(String::from("Hello"))
// }
fn add_to_bot(self, bot:BotInstance) {
fn add_to_bot(self, bot:BotInstance<F>) {
// let mut mgr = bot.botmodules;
// let nmod = self.module.clone();
// mgr.add_botaction(nmod, BotAction::C(self));
@ -193,7 +217,7 @@ impl BotActionTrait for Listener {
self.add_to_modmgr(&mut mgr);
}
fn add_to_modmgr(self, modmgr:&mut ModulesManager) {
fn add_to_modmgr(self, modmgr:&mut ModulesManager<F>) {
// // let mut mgr = bot.botmodules;
// // let nmod = self.module.clone();
// // mgr.add_botaction(nmod, BotAction::C(self));
@ -237,14 +261,20 @@ struct Routine {}
#[derive(Debug)]
pub struct ModulesManager {
pub struct ModulesManager<F: ?Sized>
where
F: std::future::Future,
{
statusdb: HashMap<ModType,Vec<ModStatusType>>,
botactions: HashMap<ModType,Vec<BotAction>>,
botactions: HashMap<ModType,Vec<BotAction<F>>>,
}
impl ModulesManager {
impl<F> ModulesManager<F>
where
F: std::future::Future,
{
pub fn init() -> ModulesManager {
pub fn init() -> ModulesManager<F> {
// initializes the modulers manager
// Ideally, this should have added known modules based on
@ -341,7 +371,7 @@ impl ModulesManager {
println!(">> Modules Manager : End of Init");
println!(">> Modules Manager : {:?}",mgr);
//println!(">> Modules Manager : {:?}",mgr);
mgr
}
@ -371,7 +401,7 @@ impl 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> ) -> () {
/*
adds a BotAction to the Modules Manager - This will require a BotModule passed as well
This will including the logic of a valid add
@ -399,7 +429,10 @@ impl ModulesManager {
// - 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
fn find_conflict_module(mgr:& ModulesManager, act:& BotAction) -> Option<ModType> {
fn find_conflict_module<F>(mgr:& ModulesManager<F>, act:& BotAction<F>) -> Option<ModType>
where
F: std::future::Future,
{
// Some(BotModule(String::from("GambaCore")))
@ -412,70 +445,70 @@ impl ModulesManager {
// 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() {
if let BotAction::C(dbcmd) = &modact {
// At this point, there is an command incmd and looked up dbcmd
// for modact in moduleactions.iter() {
// if let BotAction::C(dbcmd) = &modact {
// // 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() {
// Returning State - with the identified module
// return Some((module.clone(),BotAction::C(*dbcmd.clone())));
// return Some(incmd); // for some reason I keep getting issues
//return Some(BotModule(String::from("GambaCore"))); // works
return Some(module.clone()); // works
// return Some(dbcmd.clone());
}
// if incmd.command.to_lowercase() == dbcmd.command.to_lowercase() {
// // Returning State - with the identified module
// // return Some((module.clone(),BotAction::C(*dbcmd.clone())));
// // return Some(incmd); // for some reason I keep getting issues
// //return Some(BotModule(String::from("GambaCore"))); // works
// return Some(module.clone()); // works
// // return Some(dbcmd.clone());
// }
for a in &dbcmd.alias {
if incmd.command.to_lowercase() == a.to_lowercase() {
// Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works
// for a in &dbcmd.alias {
// if incmd.command.to_lowercase() == a.to_lowercase() {
// // Returning State - with the identified module
// // return Some((module.clone(),BotAction::C(dbcmd)));
// 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() {
// Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works
// if inalias.to_lowercase() == dbcmd.command.to_lowercase() {
// // Returning State - with the identified module
// // return Some((module.clone(),BotAction::C(dbcmd)));
// return Some(module.clone()); // works
}
// }
for a in &dbcmd.alias {
if inalias.to_lowercase() == a.to_lowercase() {
// Returning State - with the identified module
// return Some((module.clone(),BotAction::C(dbcmd)));
return Some(module.clone()); // works
// for a in &dbcmd.alias {
// if inalias.to_lowercase() == a.to_lowercase() {
// // Returning State - with the identified module
// // return Some((module.clone(),BotAction::C(dbcmd)));
// 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
@ -488,7 +521,8 @@ impl ModulesManager {
// panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , probmod );
// }
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 => (),
}
@ -508,7 +542,7 @@ impl ModulesManager {
modactions.push(in_action);
println!(">> Modules Manager : Called Add bot Action");
println!(">> Modules Manager : {:?}",&self);
//println!(">> Modules Manager : {:?}",&self);
();
}

View file

@ -17,14 +17,17 @@
pub mod core;
pub mod modules;
use std::process::Output;
use crate::core::botinstance::BotInstance;
#[tokio::main]
pub async fn main() {
let bot = BotInstance::init();
let bot:BotInstance<dyn std::future::Future<Output = ()>> = BotInstance::init();
//let bot = BotInstance::init();
bot.run().await;
bot.runner().await;
}

View file

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

View file

@ -12,12 +12,15 @@
// mod crate::modules;
//use crate::modules;
use crate::core::botmodules::{ModulesManager,BotCommand,Listener,BotModule,BotActionTrait};
use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait};
use crate::core::botinstance::BotInstance;
use twitch_irc::message::PrivmsgMessage;
pub fn init(mgr:&mut ModulesManager) -> () {
pub fn init<F>(mgr:&mut ModulesManager<F>) -> ()
where
F: std::future::Future,
{
// BotCommand {
@ -55,7 +58,24 @@ pub fn init(mgr:&mut ModulesManager) -> () {
// ()
// }
async fn good_girl(bot:&mut BotInstance,msg:&PrivmsgMessage) {
// async fn good_girl<F>(bot:&mut BotInstance<F>,msg:&PrivmsgMessage)
// where
// F: std::future::Future,
// {
// println!("In GoodGirl()");
// println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
// if msg.sender.name == "ModulatingForce" && msg.message_text.contains("GoodGirl") {
// bot.chat.say_in_reply_to(msg,String::from("GoodGirl")).await;
// }
// }
async fn good_girl<F>(bot:&mut Box<BotInstance<F>>,msg:&PrivmsgMessage)
where
F: std::future::Future,
{
println!("In GoodGirl()");
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);