Merge pull request 'Custom Exec Bodies for BotCommand and Listeners' (#9) from dev into main
Reviewed-on: #9
This commit is contained in:
commit
c0102ba052
7 changed files with 411 additions and 291 deletions
15
README.md
15
README.md
|
@ -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>`
|
|
|
@ -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,36 +182,37 @@ 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 {
|
||||||
|
|
||||||
|
@ -154,8 +222,12 @@ impl BotInstance {
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn add_to_modmgr(self, modmgr:&mut ModulesManager) {
|
impl BotActionTrait for BotCommand
|
||||||
// // let mut mgr = bot.botmodules;
|
{
|
||||||
// // let nmod = self.module.clone();
|
fn add_to_bot(self, mut bot:BotInstance) {
|
||||||
// // mgr.add_botaction(nmod, BotAction::C(self));
|
let mgr = &mut bot.botmodules;
|
||||||
// let mut mgr = modmgr;
|
self.add_to_modmgr(mgr);
|
||||||
// //let nmod = self.module.clone();
|
}
|
||||||
// mgr.add_botaction(self.module.clone(), BotAction::C(self));
|
|
||||||
// let mut mgr = modmgr;
|
fn add_to_modmgr(self, modmgr:&mut ModulesManager) {
|
||||||
// //let nmod = self.module.clone();
|
modmgr.add_botaction(self.module.clone(), BotAction::C(self))
|
||||||
modmgr.add_botaction(self.module.clone(), BotAction::C(self));
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub mod bot_actions {
|
||||||
|
|
||||||
|
pub mod actions_util {
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -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;
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
||||||
|
//();
|
||||||
();
|
|
||||||
}
|
}
|
|
@ -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!")
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue