cargo-fmt

This commit is contained in:
modulatingforce 2025-02-06 09:41:54 -05:00
parent 8eaa56dd0c
commit cd69a35ec1
22 changed files with 1140 additions and 1075 deletions
forcebot_core/src
moderator_reactor/src
new_empty_bot/src
simple_command_bot/src
simple_debug_listener/src
simple_module_example/src

View file

@ -1,30 +1,30 @@
//! WIP Fun forcebot with catered customizations #todo //! WIP Fun forcebot with catered customizations #todo
//! //!
//! Custom modules that can be managed in chat through `disable` and `enable` commands //! Custom modules that can be managed in chat through `disable` and `enable` commands
//! - `besty` - uses a custom prefix tp trigger //! - `besty` - uses a custom prefix tp trigger
//! - `guests` //! - `guests`
//! - `pyramid` //! - `pyramid`
//! - `quiet` //! - `quiet`
//! //!
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot}; use forcebot_core::{
custom_mods::{debug, guest_badge, pyramid},
Bot,
};
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* Create the bot using env */ /* Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
@ -33,14 +33,11 @@ pub async fn main() {
bot.load_module(guest_badge::create_module()).await; bot.load_module(guest_badge::create_module()).await;
bot.load_module(pyramid::create_module()).await; bot.load_module(pyramid::create_module()).await;
bot.load_module(debug::create_module()).await; bot.load_module(debug::create_module()).await;
/* 3. Run the bot */ /* 3. Run the bot */
bot.run().await; bot.run().await;
} }
pub mod funbot_objs { pub mod funbot_objs {
use std::sync::Arc; use std::sync::Arc;
@ -50,8 +47,9 @@ pub mod funbot_objs {
/// Create a Module with a loaded Command object /// Create a Module with a loaded Command object
pub fn create_module() -> Module { pub fn create_module() -> Module {
let mut custom_mod = Module::new( let mut custom_mod = Module::new(
vec!["besty".to_string()], vec!["besty".to_string()],
"Now Aware of besty xdd666 ".to_string()); "Now Aware of besty xdd666 ".to_string(),
);
custom_mod.load_command(create_cmd_test()); custom_mod.load_command(create_cmd_test());
// custom_mod.set_status_by_default(Status::Disabled); // custom_mod.set_status_by_default(Status::Disabled);
@ -61,16 +59,22 @@ pub mod funbot_objs {
/// Create a Command Object /// Create a Command Object
fn create_cmd_test() -> Command { fn create_cmd_test() -> Command {
let mut cmd = Command::new(
let mut cmd = Command::new(vec!["remind besty".to_string()],"annytfYandere ".to_string()); vec!["remind besty".to_string()],
"annytfYandere ".to_string(),
);
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _= bot.chat.lock().await.say_in_reply_to( let _ = bot
&msg, "annytfYandere he's mine".to_string()).await; .chat
return Result::Ok("Success".to_string()); .lock()
.await
.say_in_reply_to(&msg, "annytfYandere he's mine".to_string())
.await;
return Result::Ok("Success".to_string());
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
cmd.set_exec_fn(execution_async(execbody)); cmd.set_exec_fn(execution_async(execbody));
@ -79,6 +83,5 @@ pub mod funbot_objs {
cmd.set_min_badge(Badge::Vip); cmd.set_min_badge(Badge::Vip);
cmd cmd
} }
} }

View file

@ -1,12 +1,12 @@
//! Example simple Binary crate that creates & runs bot based on `.env` //! Example simple Binary crate that creates & runs bot based on `.env`
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
@ -14,11 +14,9 @@ use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* 1. Create the bot using env */ /* 1. Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
/* 2. Run the bot */ /* 2. Run the bot */
bot.run().await; bot.run().await;
} }

View file

@ -1,19 +1,19 @@
//! Simple Module with a Command //! Simple Module with a Command
//! //!
//! Adding objects through packages provides controls , //! Adding objects through packages provides controls ,
//! such as moderators, and brodcasters can disable or enable mods //! such as moderators, and brodcasters can disable or enable mods
//! //!
//! Here, moderators or above can enable or disable the `test` //! Here, moderators or above can enable or disable the `test`
//! module with the command `<prefix> disable test` //! module with the command `<prefix> disable test`
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
@ -21,7 +21,6 @@ use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* Create the bot using env */ /* Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
@ -30,43 +29,41 @@ pub async fn main() {
/* Run the bot */ /* Run the bot */
bot.run().await; bot.run().await;
} }
pub mod custom_mod { pub mod custom_mod {
use std::sync::Arc; use std::sync::Arc;
use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use forcebot_core::{execution_async, Badge, Bot, Command, Module};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
/// Module definition with a loaded command /// Module definition with a loaded command
pub fn new() -> Module { pub fn new() -> Module {
/* 1. Create a new module */ /* 1. Create a new module */
let mut custom_mod = Module::new( let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string());
vec!["test".to_string()],
"".to_string());
/* 2. Load the cmd into a new module */ /* 2. Load the cmd into a new module */
custom_mod.load_command(cmd_test()); custom_mod.load_command(cmd_test());
custom_mod custom_mod
} }
/// Command definition /// Command definition
pub fn cmd_test() -> Command { pub fn cmd_test() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _= bot.chat.lock().await.say_in_reply_to( let _ = bot
&msg, "test return".to_string()).await; .chat
.lock()
.await
.say_in_reply_to(&msg, "test return".to_string())
.await;
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */
@ -76,4 +73,4 @@ pub mod custom_mod {
cmd cmd
} }
} }

View file

@ -1,5 +1,5 @@
pub mod bot; pub mod bot;
pub mod bot_objects; pub mod bot_objects;
pub mod modules;
pub mod built_in_mods; pub mod built_in_mods;
pub mod chat; pub mod chat;
pub mod modules;

View file

@ -1,37 +1,44 @@
// use async_recursion::async_recursion; // use async_recursion::async_recursion;
use tokio::sync::{mpsc::UnboundedReceiver, Mutex};
use twitch_irc::{login::StaticLoginCredentials, message::{PrivmsgMessage, ServerMessage}, SecureTCPTransport, TwitchIRCClient};
use dotenv::dotenv; use dotenv::dotenv;
use std::{env, sync::{Arc, RwLock}, time::{Duration, Instant}}; use std::{
env,
sync::{Arc, RwLock},
time::{Duration, Instant},
};
use tokio::sync::{mpsc::UnboundedReceiver, Mutex};
use twitch_irc::{
login::StaticLoginCredentials,
message::{PrivmsgMessage, ServerMessage},
SecureTCPTransport, TwitchIRCClient,
};
// use crate::{Badge, Command, Listener, Module}; // use crate::{Badge, Command, Listener, Module};
use super::{bot_objects::command::Command, built_in_mods, chat::Chat}; use super::{bot_objects::command::Command, built_in_mods, chat::Chat};
use crate::botcore::{bot_objects::Badge, chat};
use crate::botcore::bot_objects::listener::Listener;
use super::super::botcore::modules::Module; use super::super::botcore::modules::Module;
use crate::botcore::bot_objects::listener::Listener;
use crate::botcore::{bot_objects::Badge, chat};
// use super:: // use super::
use super:: {bot_objects::built_in_objects, modules::{self, Status}}; use super::{
bot_objects::built_in_objects,
modules::{self, Status},
};
/// Twitch chat bot /// Twitch chat bot
pub struct Bot pub struct Bot {
{
/// Prefix for commands /// Prefix for commands
prefix: String, prefix: String,
/// inbound chat msg stream /// inbound chat msg stream
incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>, incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>,
/// outbound chat client msg stream /// outbound chat client msg stream
pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>,
/// *preferred* bot enforced outbound chat client msg stream /// *preferred* bot enforced outbound chat client msg stream
pub chat : Mutex<Chat>, pub chat: Mutex<Chat>,
/// joined channels /// joined channels
botchannels: Vec<String>, botchannels: Vec<String>,
/// admin chatters /// admin chatters
admins : Vec<String>, admins: Vec<String>,
/// listeners /// listeners
listeners: Mutex<Vec<Listener>>, listeners: Mutex<Vec<Listener>>,
/// commands /// commands
@ -39,21 +46,18 @@ pub struct Bot
/// modules /// modules
modules: RwLock<Vec<Module>>, modules: RwLock<Vec<Module>>,
/// channel module status /// channel module status
channel_module_status: RwLock<Vec<(String,String,modules::Status)>>, channel_module_status: RwLock<Vec<(String, String, modules::Status)>>,
/// chatter guest badges - chatter,channel,Badge,start_time,duration /// chatter guest badges - chatter,channel,Badge,start_time,duration
chatter_guest_badges: Mutex<Vec<(String,String,Badge,Instant,Duration)>>, chatter_guest_badges: Mutex<Vec<(String, String, Badge, Instant, Duration)>>,
/// Message cache /// Message cache
message_cache: Mutex<Vec<PrivmsgMessage>>, message_cache: Mutex<Vec<PrivmsgMessage>>,
// /// channel_quiet // /// channel_quiet
// channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>, // channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>,
} }
impl Bot {
impl Bot
{
/// Creates a new `Bot` using env variables /// Creates a new `Bot` using env variables
/// ///
/// Be sure the following is defined in an `.env` file /// Be sure the following is defined in an `.env` file
/// - login_name /// - login_name
/// - access_token /// - access_token
@ -62,35 +66,29 @@ impl Bot
/// - bot_admins /// - bot_admins
// #[async_recursion] // #[async_recursion]
pub async fn new() -> Arc<Bot> { pub async fn new() -> Arc<Bot> {
dotenv().ok(); dotenv().ok();
let bot_login_name = env::var("login_name").unwrap().to_owned(); let bot_login_name = env::var("login_name").unwrap().to_owned();
let oauth_token = env::var("access_token").unwrap().to_owned(); let oauth_token = env::var("access_token").unwrap().to_owned();
let prefix = env::var("prefix") let prefix = env::var("prefix").unwrap().to_owned();
.unwrap()
.to_owned();
let mut botchannels = Vec::new(); let mut botchannels = Vec::new();
for chnl in env::var("bot_channels").unwrap().split(',') { for chnl in env::var("bot_channels").unwrap().split(',') {
botchannels.push(chnl.to_owned()); botchannels.push(chnl.to_owned());
} }
Bot::new_from(bot_login_name, oauth_token, prefix, botchannels).await Bot::new_from(bot_login_name, oauth_token, prefix, botchannels).await
} }
/// Creates a new `Bot` using bot information /// Creates a new `Bot` using bot information
/// ///
/// Bot will join `botchannels` argument /// Bot will join `botchannels` argument
pub async fn new_from(bot_login_name:String, pub async fn new_from(
oauth_token:String, bot_login_name: String,
prefix:String, oauth_token: String,
botchannels:Vec<String>) -> Arc<Bot> { prefix: String,
botchannels: Vec<String>,
) -> Arc<Bot> {
dotenv().ok(); dotenv().ok();
let bot_login_name = bot_login_name; let bot_login_name = bot_login_name;
@ -105,49 +103,45 @@ impl Bot
let mut botchannels_all = Vec::new(); let mut botchannels_all = Vec::new();
botchannels_all.extend(botchannels); botchannels_all.extend(botchannels);
let mut admins = Vec::new(); let mut admins = Vec::new();
if let Ok(value) = env::var("bot_admins") { if let Ok(value) = env::var("bot_admins") {
for admin in value.split(',') { for admin in value.split(',') {
admins.push(String::from(admin)) admins.push(String::from(admin))
} }
} }
let bot = Bot { let bot = Bot {
prefix, prefix,
incoming_msgs : Mutex::new(incoming_messages), incoming_msgs: Mutex::new(incoming_messages),
client : client.clone(), client: client.clone(),
chat : Mutex::new(Chat::new(client).await), chat: Mutex::new(Chat::new(client).await),
botchannels : botchannels_all, botchannels: botchannels_all,
listeners : Mutex::new(vec![]), listeners: Mutex::new(vec![]),
commands : Mutex::new(vec![]), commands: Mutex::new(vec![]),
admins, admins,
modules: RwLock::new(vec![]), modules: RwLock::new(vec![]),
channel_module_status: RwLock::new(vec![]), channel_module_status: RwLock::new(vec![]),
chatter_guest_badges: Mutex::new(vec![]), chatter_guest_badges: Mutex::new(vec![]),
message_cache : Mutex::new(vec![]), message_cache: Mutex::new(vec![]),
// channel_quiet_yn : RwLock::new(vec![]), // channel_quiet_yn : RwLock::new(vec![]),
}; };
async fn load_modules(bot:Bot) -> Bot { async fn load_modules(bot: Bot) -> Bot {
// let mut bot1 = bot; // let mut bot1 = bot;
// bot1.chat = Some(Chat::new(client, bot1)); // bot1.chat = Some(Chat::new(client, bot1));
for cmd in built_in_objects::create_commands() { for cmd in built_in_objects::create_commands() {
bot.load_command(cmd).await; bot.load_command(cmd).await;
} }
built_in_mods::load_built_in_mods(&bot).await; built_in_mods::load_built_in_mods(&bot).await;
bot
bot
} }
let bot = load_modules(bot).await; let bot = load_modules(bot).await;
let bot = Arc::new(bot); let bot = Arc::new(bot);
// let lock = bot.chat.lock().await; // let lock = bot.chat.lock().await;
@ -160,15 +154,13 @@ impl Bot
// lock.set_parent_bot(bot.clone()); // lock.set_parent_bot(bot.clone());
println!("Joined - {:?}",bot.botchannels); println!("Joined - {:?}", bot.botchannels);
bot.clone() bot.clone()
} }
/// Runs the bot /// Runs the bot
pub async fn run(self:Arc<Self>) { pub async fn run(self: Arc<Self>) {
for chnl in &self.botchannels { for chnl in &self.botchannels {
self.client.join(chnl.to_owned()).unwrap(); self.client.join(chnl.to_owned()).unwrap();
} }
@ -177,24 +169,21 @@ impl Bot
let bot = self; let bot = self;
let join_handle = tokio::spawn(async move { let join_handle = tokio::spawn(async move {
let a = bot.clone(); let a = bot.clone();
let mut in_msgs_lock = a.incoming_msgs.lock().await; let mut in_msgs_lock = a.incoming_msgs.lock().await;
while let Some(message) = in_msgs_lock.recv().await { while let Some(message) = in_msgs_lock.recv().await {
// dbg!(message.clone()) ; // dbg!(message.clone()) ;
let bot_listener_lock = bot.listeners.lock().await; let bot_listener_lock = bot.listeners.lock().await;
for listener in bot_listener_lock.iter() { for listener in bot_listener_lock.iter() {
let a = listener.clone(); let a = listener.clone();
if a.cond_triggered(bot.clone(),message.clone()).await { if a.cond_triggered(bot.clone(), message.clone()).await {
let _ = listener.execute_fn(bot.clone(),message.clone()).await; let _ = listener.execute_fn(bot.clone(), message.clone()).await;
} }
} }
if let ServerMessage::Privmsg(msg) = message.clone() { if let ServerMessage::Privmsg(msg) = message.clone() {
// let mut cache_lock = bot.message_cache.lock().await; // let mut cache_lock = bot.message_cache.lock().await;
let mut cache_lock = bot.message_cache.lock().await; let mut cache_lock = bot.message_cache.lock().await;
cache_lock.push(msg.clone()); cache_lock.push(msg.clone());
@ -203,91 +192,78 @@ impl Bot
let cmd_lock = bot.commands.lock().await; let cmd_lock = bot.commands.lock().await;
for cmd in cmd_lock.iter() { for cmd in cmd_lock.iter() {
let a = cmd.clone(); let a = cmd.clone();
if a.command_triggered(bot.clone(),msg.clone()).await { if a.command_triggered(bot.clone(), msg.clone()).await {
let _ = cmd.execute_fn(bot.clone(), message.clone()).await;
let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
} }
} }
fn get_enabled_channel_modules(bot: Arc<Bot>, channel: String) -> Vec<Module> {
let botmodules_lock = bot.modules.read().unwrap();
let botmodules_cpy = botmodules_lock.clone();
drop(botmodules_lock);
fn get_enabled_channel_modules(bot: Arc<Bot>,channel:String) -> Vec<Module> { let mut enabled_mods = Vec::new();
let botmodules_lock = bot.modules.read().unwrap(); 'module_loop: for module in &*botmodules_cpy {
let botmodules_cpy = botmodules_lock.clone(); // dbg!("try cms read");
drop(botmodules_lock); let cms_lock = bot.channel_module_status.read().unwrap();
let mut enabled_mods = Vec::new(); for channel_flags in cms_lock.iter() {
if channel_flags.0 == channel {
'module_loop: for module in &*botmodules_cpy { if module.get_names().contains(&channel_flags.1)
&& channel_flags.2 == Status::Disabled
// dbg!("try cms read"); {
let cms_lock = bot.channel_module_status.read().unwrap(); continue 'module_loop;
}
for channel_flags in cms_lock.iter() {
if channel_flags.0 == channel {
if module.get_names().contains(&channel_flags.1) && channel_flags.2 == Status::Disabled {
continue 'module_loop;
} }
} }
enabled_mods.push(module.clone());
} }
enabled_mods.push(module.clone());
enabled_mods
} }
enabled_mods for module in
get_enabled_channel_modules(bot.clone(), msg.clone().channel_login)
{
} for listener in module.get_listeners() {
let a = listener.clone();
if a.cond_triggered(bot.clone(), message.clone()).await {
for module in get_enabled_channel_modules(bot.clone(), msg.clone().channel_login) { let _ = listener.execute_fn(bot.clone(), message.clone()).await;
}
for listener in module.get_listeners() { }
for cmd in module.get_commands() {
let a = listener.clone(); let a = cmd.clone();
if a.cond_triggered(bot.clone(),message.clone()).await { if a.command_triggered(bot.clone(), msg.clone()).await {
let _ = cmd.execute_fn(bot.clone(), message.clone()).await;
let _ = listener.execute_fn(bot.clone(),message.clone()).await; }
} }
} }
for cmd in module.get_commands() { } else {
};
let a = cmd.clone();
if a.command_triggered(bot.clone(),msg.clone()).await {
let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
}
}
}
} else {} ;
} }
drop(in_msgs_lock); drop(in_msgs_lock);
}); });
join_handle.await.unwrap(); join_handle.await.unwrap();
} }
/// Loads a `Listener` into the bot /// Loads a `Listener` into the bot
pub async fn load_listener(&self,l : Listener) { pub async fn load_listener(&self, l: Listener) {
let a = Arc::new(self); let a = Arc::new(self);
let mut listlock = a.listeners.lock().await; let mut listlock = a.listeners.lock().await;
listlock.push(l); listlock.push(l);
} }
/// Loads a `Command` into the bot /// Loads a `Command` into the bot
pub async fn load_command(&self,c : Command) { pub async fn load_command(&self, c: Command) {
let a = Arc::new(self); let a = Arc::new(self);
let mut cmdlock = a.commands.lock().await; let mut cmdlock = a.commands.lock().await;
cmdlock.push(c); cmdlock.push(c);
} }
pub async fn get_module(&self, module: String) -> Option<Module> {
pub async fn get_module(&self,module:String) -> Option<Module> {
let modlock = self.modules.read().unwrap(); let modlock = self.modules.read().unwrap();
for modl in modlock.iter() { for modl in modlock.iter() {
if modl.get_names().contains(&module) { if modl.get_names().contains(&module) {
@ -296,8 +272,6 @@ impl Bot
} }
None None
} }
pub fn get_prefix(&self) -> String { pub fn get_prefix(&self) -> String {
self.prefix.clone() self.prefix.clone()
@ -306,9 +280,9 @@ impl Bot
pub fn get_admins(&self) -> Vec<String> { pub fn get_admins(&self) -> Vec<String> {
self.admins.clone() self.admins.clone()
} }
/// loads a `Module` and its bot objects /// loads a `Module` and its bot objects
pub async fn load_module(&self,m: Module) { pub async fn load_module(&self, m: Module) {
// dbg!("load module - start",m.get_names().first().unwrap()); // dbg!("load module - start",m.get_names().first().unwrap());
let bot = Arc::new(self); let bot = Arc::new(self);
// let bot_lock = bot.lock().await; // let bot_lock = bot.lock().await;
@ -316,10 +290,10 @@ impl Bot
if m.get_status_by_default() == Status::Disabled { if m.get_status_by_default() == Status::Disabled {
// dbg!("module fund disabled by default"); // dbg!("module fund disabled by default");
// dbg!("inner if"); // dbg!("inner if");
for (_index,chnl) in bot.botchannels.iter().enumerate() { for (_index, chnl) in bot.botchannels.iter().enumerate() {
// dbg!("iter - ",index); // dbg!("iter - ",index);
bot.disable_module(chnl.clone(), bot.disable_module(chnl.clone(), m.get_names().first().unwrap().clone())
m.get_names().first().unwrap().clone()).await .await
} }
} }
// dbg!("aftee disable check"); // dbg!("aftee disable check");
@ -328,11 +302,11 @@ impl Bot
// dbg!(m); // dbg!(m);
// dbg!("loading module ",m.get_names()); // dbg!("loading module ",m.get_names());
botmods.push(m); botmods.push(m);
} }
pub async fn get_channel_module_status(&self,channel:String,module:String) -> Status { pub async fn get_channel_module_status(&self, channel: String, module: String) -> Status {
// dbg!("get channel module status"); // dbg!("get channel module status");
let found_disabled:bool = { let found_disabled: bool = {
// dbg!("try cms read"); // dbg!("try cms read");
let cms_lock = self.channel_module_status.read().unwrap(); let cms_lock = self.channel_module_status.read().unwrap();
// dbg!("cms read lock"); // dbg!("cms read lock");
@ -349,31 +323,31 @@ impl Bot
found found
}; };
let module_loaded:bool = { let module_loaded: bool = {
let mut loaded_yn = false; let mut loaded_yn = false;
for loaded_m in self.modules.read().unwrap().iter() { for loaded_m in self.modules.read().unwrap().iter() {
if loaded_m.get_names().contains(&module) { if loaded_m.get_names().contains(&module) {
loaded_yn = true; loaded_yn = true;
} }
} }
loaded_yn loaded_yn
}; };
if found_disabled { return Status::Disabled;}
else if !module_loaded { return Status::NotLoaded ;}
else { return Status::Enabled; };
if found_disabled {
return Status::Disabled;
} else if !module_loaded {
return Status::NotLoaded;
} else {
return Status::Enabled;
};
} }
pub async fn disable_module(&self,channel:String,module:String){ pub async fn disable_module(&self, channel: String, module: String) {
// dbg!("disable module called",channel.clone(),module.clone()); // dbg!("disable module called",channel.clone(),module.clone());
let found_disabled:bool = { let found_disabled: bool = {
// dbg!("finding disabled mod"); // dbg!("finding disabled mod");
// dbg!("try cms read"); // dbg!("try cms read");
let cms_lock = self.channel_module_status.read().unwrap(); let cms_lock = self.channel_module_status.read().unwrap();
@ -394,62 +368,63 @@ impl Bot
}; };
if !found_disabled { if !found_disabled {
let mut cms_lock = self.channel_module_status.write().unwrap(); let mut cms_lock = self.channel_module_status.write().unwrap();
cms_lock.push((channel,module.clone(),Status::Disabled)); cms_lock.push((channel, module.clone(), Status::Disabled));
drop(cms_lock); drop(cms_lock);
}
}
} }
pub async fn enable_module(&self,channel:String,module:String){ pub async fn enable_module(&self, channel: String, module: String) {
// dbg!("enable module called",channel.clone(),module.clone()); // dbg!("enable module called",channel.clone(),module.clone());
// dbg!("try cms write"); // dbg!("try cms write");
let mut lock = self.channel_module_status.write().unwrap(); let mut lock = self.channel_module_status.write().unwrap();
// dbg!("cms write lock"); // dbg!("cms write lock");
// dbg!(module.clone()); // dbg!(module.clone());
while lock.contains(&(channel.clone(),module.clone(),Status::Disabled)) { while lock.contains(&(channel.clone(), module.clone(), Status::Disabled)) {
let index = lock let index = lock
.iter() .iter()
.position(|x| *x == .position(|x| *x == (channel.clone(), module.clone(), Status::Disabled))
(channel.clone(),module.clone(),Status::Disabled))
.unwrap(); .unwrap();
lock.remove(index); lock.remove(index);
} }
drop(lock); drop(lock);
} }
pub async fn get_channel_guest_badges(&self,chatter:String,channel:String) -> Vec<(Badge,Instant,Duration)> { pub async fn get_channel_guest_badges(
&self,
chatter: String,
channel: String,
) -> Vec<(Badge, Instant, Duration)> {
let bot = Arc::new(self); let bot = Arc::new(self);
let guest_badges_lock = bot.chatter_guest_badges.lock().await; let guest_badges_lock = bot.chatter_guest_badges.lock().await;
let mut badges = vec![]; let mut badges = vec![];
for temp_badge in guest_badges_lock.iter() { for temp_badge in guest_badges_lock.iter() {
if temp_badge.0 == chatter && temp_badge.1 == channel && if temp_badge.0 == chatter
temp_badge.3 + temp_badge.4 > Instant::now() && temp_badge.1 == channel
&& temp_badge.3 + temp_badge.4 > Instant::now()
{ {
badges.push((temp_badge.2.clone(),temp_badge.3,temp_badge.4)); badges.push((temp_badge.2.clone(), temp_badge.3, temp_badge.4));
} }
} }
badges badges
} }
pub async fn issue_new_guest_badge(
pub async fn issue_new_guest_badge(&self,chatter:String,channel:String,badge:Badge,start:Instant,dur:Duration) { &self,
chatter: String,
channel: String,
badge: Badge,
start: Instant,
dur: Duration,
) {
let bot = Arc::new(self); let bot = Arc::new(self);
let mut guest_badges_lock = bot.chatter_guest_badges.lock().await; let mut guest_badges_lock = bot.chatter_guest_badges.lock().await;
guest_badges_lock.push((chatter,channel,badge,start,dur)); guest_badges_lock.push((chatter, channel, badge, start, dur));
} }
pub fn get_message_cache(&self) -> &Mutex<Vec<PrivmsgMessage>> { pub fn get_message_cache(&self) -> &Mutex<Vec<PrivmsgMessage>> {
@ -457,12 +432,16 @@ impl Bot
} }
/// get message cache newest to oldest for a channel /// get message cache newest to oldest for a channel
pub async fn get_message_cache_per_channel(&self,channel:String) -> Vec<PrivmsgMessage> { pub async fn get_message_cache_per_channel(&self, channel: String) -> Vec<PrivmsgMessage> {
let cache = self.message_cache.lock().await; let cache = self.message_cache.lock().await;
let mut rslt = vec![]; let mut rslt = vec![];
for a in cache.iter().rev().filter(|x| { x.channel_login==channel }).into_iter() { for a in cache
.iter()
.rev()
.filter(|x| x.channel_login == channel)
.into_iter()
{
rslt.push(a.clone()); rslt.push(a.clone());
} }
rslt rslt
} }
@ -476,7 +455,7 @@ impl Bot
// } // }
// return false; // return false;
// } // }
// /// Get the quiet status of a channel // /// Get the quiet status of a channel
// pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) { // pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) {
// let mut found = false; // let mut found = false;
@ -491,16 +470,13 @@ impl Bot
// } // }
// } // }
// drop(chnlquiet); // drop(chnlquiet);
// if !found { // if !found {
// // dbg!("set chn quiet > !found channel quiet status"); // // dbg!("set chn quiet > !found channel quiet status");
// let mut chnlquiet = self.channel_quiet_yn.write().unwrap(); // let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
// chnlquiet.push((channel,RwLock::new(quiet_on))); // chnlquiet.push((channel,RwLock::new(quiet_on)));
// drop(chnlquiet); // drop(chnlquiet);
// } // }
// } // }
} }

View file

@ -1,6 +1,5 @@
pub mod listener;
pub mod command; pub mod command;
pub mod listener;
use std::boxed::Box; use std::boxed::Box;
use std::future::Future; use std::future::Future;
@ -11,25 +10,24 @@ use twitch_irc::message::{PrivmsgMessage, ServerMessage};
use super::bot::Bot; use super::bot::Bot;
/// chat badge /// chat badge
#[derive(Clone,PartialEq, Eq,Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub enum Badge { pub enum Badge {
Moderator, Moderator,
Broadcaster, Broadcaster,
Vip Vip,
} }
pub type ExecBody = Box< pub type ExecBody = Box<
dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = Result<String,String>> + Send>> + Send + Sync, dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send>>
+ Send
+ Sync,
>; >;
/// used to store async execution functions. Primarily used for `Command` /// used to store async execution functions. Primarily used for `Command`
/// ///
/// call this to store execution functions in `Commands` /// call this to store execution functions in `Commands`
/// ///
/// # example /// # example
/// ``` /// ```
/// /* 2. Define exec callback */ /// /* 2. Define exec callback */
@ -40,20 +38,20 @@ pub type ExecBody = Box<
/// /* 3. Set Command flags */ /// /* 3. Set Command flags */
/// cmd.set_exec_fn(execution_async(execbody)); /// cmd.set_exec_fn(execution_async(execbody));
/// ``` /// ```
/// ///
pub fn execution_async<T>(f: fn(Arc<Bot>,ServerMessage) -> T) -> ExecBody pub fn execution_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ExecBody
where where
T: Future<Output = Result<String,String>> + Send + 'static, T: Future<Output = Result<String, String>> + Send + 'static,
{ {
Box::new(move |a,b| Box::pin(f(a,b))) Box::new(move |a, b| Box::pin(f(a, b)))
} }
pub type CommandTrigger = Box< pub type CommandTrigger = Box<
dyn Fn(Arc<Bot>,PrivmsgMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, dyn Fn(Arc<Bot>, PrivmsgMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync,
>; >;
/// used to store async trigger condition callback functions. Primarily used for `Command` /// used to store async trigger condition callback functions. Primarily used for `Command`
/// ///
/// # example /// # example
/// ``` /// ```
/// /* 2. Define condition callback */ /// /* 2. Define condition callback */
@ -64,21 +62,20 @@ pub type CommandTrigger = Box<
/// /* 3. Set Command flags */ /// /* 3. Set Command flags */
/// cmd.set_custom_cond_async(command_condition_async(condition01)); /// cmd.set_custom_cond_async(command_condition_async(condition01));
/// ``` /// ```
/// ///
pub fn command_condition_async<T>(f: fn(Arc<Bot>,PrivmsgMessage) -> T) -> CommandTrigger pub fn command_condition_async<T>(f: fn(Arc<Bot>, PrivmsgMessage) -> T) -> CommandTrigger
where where
T: Future<Output = bool> + Send + 'static, T: Future<Output = bool> + Send + 'static,
{ {
Box::new(move |a,b| Box::pin(f(a,b))) Box::new(move |a, b| Box::pin(f(a, b)))
} }
pub type ListenerTrigger = Box< pub type ListenerTrigger = Box<
dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync,
>; >;
/// used to store async trigger condition callback functions. Primarily used for `Listener` /// used to store async trigger condition callback functions. Primarily used for `Listener`
/// ///
/// # example /// # example
/// ``` /// ```
/// /* 2. Define condition callback */ /// /* 2. Define condition callback */
@ -89,30 +86,29 @@ pub type ListenerTrigger = Box<
/// /* 3. Set Command flags */ /// /* 3. Set Command flags */
/// cmd.set_custom_cond_async(listener_condition_async(condition01)); /// cmd.set_custom_cond_async(listener_condition_async(condition01));
/// ``` /// ```
/// ///
pub fn listener_condition_async<T>(f: fn(Arc<Bot>,ServerMessage) -> T) -> ListenerTrigger pub fn listener_condition_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ListenerTrigger
where where
T: Future<Output = bool> + Send + 'static, T: Future<Output = bool> + Send + 'static,
{ {
Box::new(move |a,b| Box::pin(f(a,b))) Box::new(move |a, b| Box::pin(f(a, b)))
} }
/// collection of functions to create built in objects /// collection of functions to create built in objects
pub mod built_in_objects { pub mod built_in_objects {
const TEMP_BADGE_DUR_MIN:u64 = 30; const TEMP_BADGE_DUR_MIN: u64 = 30;
use std::{sync::Arc, time::{Duration, Instant}}; use std::{
sync::Arc,
time::{Duration, Instant},
};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
use super::{execution_async,command::Command,Bot,Badge,super::modules::Status};
use super::{super::modules::Status, command::Command, execution_async, Badge, Bot};
/// create a vector of command build in objects /// create a vector of command build in objects
pub fn create_commands() -> Vec<Command> pub fn create_commands() -> Vec<Command> {
{
let mut cmds = vec![]; let mut cmds = vec![];
cmds.push(create_disable_cmd()); cmds.push(create_disable_cmd());
@ -120,31 +116,45 @@ pub mod built_in_objects {
cmds.push(create_iam_role_cmd()); cmds.push(create_iam_role_cmd());
cmds cmds
} }
fn create_disable_cmd() -> Command { fn create_disable_cmd() -> Command {
/* 1. Create a new blank cmd */ /* 1. Create a new blank cmd */
let mut cmd = Command::new(vec!["disable".to_string()],"".to_string()); let mut cmd = Command::new(vec!["disable".to_string()], "".to_string());
/* 2. Define an async fn callback execution */ /* 2. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let mut action_taken = false; let mut action_taken = false;
for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { for (i, arg) in msg
.message_text
.replace("\u{e0000}", "")
.trim()
.split(" ")
.enumerate()
{
if i > 1 { if i > 1 {
if bot.get_channel_module_status(msg.channel_login.clone(), arg.to_string()).await == Status::Enabled { if bot
.get_channel_module_status(msg.channel_login.clone(), arg.to_string())
.await
== Status::Enabled
{
action_taken = true; action_taken = true;
bot.disable_module(msg.channel_login.clone(), arg.to_string()).await; bot.disable_module(msg.channel_login.clone(), arg.to_string())
.await;
} }
} }
} }
if action_taken { if action_taken {
let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ; let _ = bot
.chat
.lock()
.await
.say_in_reply_to(&msg, String::from("Disabled!"))
.await;
} }
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set and Store the execution body using `execution_async()` */ /* 3. Set and Store the execution body using `execution_async()` */
@ -156,50 +166,61 @@ pub mod built_in_objects {
/* 5. optionally, set min badge*/ /* 5. optionally, set min badge*/
cmd.set_min_badge(Badge::Moderator /* ::Moderator */); cmd.set_min_badge(Badge::Moderator /* ::Moderator */);
cmd cmd
}
}
fn create_enable_cmd() -> Command { fn create_enable_cmd() -> Command {
/* 1. Create a new blank cmd */ /* 1. Create a new blank cmd */
let mut cmd = Command::new(vec!["enable".to_string()],"".to_string()); let mut cmd = Command::new(vec!["enable".to_string()], "".to_string());
/* 2. Define an async fn callback execution */ /* 2. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let mut bot_message = "".to_string();
let mut bot_message="".to_string();
let mut re_enabled = false; let mut re_enabled = false;
for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { for (i, arg) in msg
.message_text
.replace("\u{e0000}", "")
.trim()
.split(" ")
.enumerate()
{
if i > 1 { if i > 1 {
if Status::Disabled
== bot
.get_channel_module_status(
msg.channel_login.clone(),
arg.to_string(),
)
.await
{
bot.enable_module(msg.channel_login.clone(), arg.to_string())
.await;
if Status::Disabled == bot.get_channel_module_status(msg.channel_login.clone(), arg.to_string()).await {
bot.enable_module(msg.channel_login.clone(), arg.to_string()).await;
//bot.get_modules() //bot.get_modules()
if let Some(found_mod) = bot.get_module(arg.to_string()).await { if let Some(found_mod) = bot.get_module(arg.to_string()).await {
bot_message = bot_message.to_string() + found_mod.get_bot_read_description().as_str(); bot_message = bot_message.to_string()
+ found_mod.get_bot_read_description().as_str();
} }
re_enabled = true; re_enabled = true;
} }
} }
} }
if re_enabled { if re_enabled {
if bot_message.len() > 250 {
if bot_message.len() > 250 {
bot_message = bot_message[..250].to_string(); bot_message = bot_message[..250].to_string();
} }
let _ = bot.chat.lock().await.say_in_reply_to(&msg, let _ = bot
format!("Enabled! {}", bot_message) .chat
).await ; .lock()
.await
.say_in_reply_to(&msg, format!("Enabled! {}", bot_message))
.await;
} }
}
} Result::Err("Not Valid message type".to_string())
Result::Err("Not Valid message type".to_string())
} }
/* 3. Set and Store the execution body using `execution_async()` */ /* 3. Set and Store the execution body using `execution_async()` */
@ -211,98 +232,158 @@ pub mod built_in_objects {
/* 5. optionally, set min badge*/ /* 5. optionally, set min badge*/
cmd.set_min_badge(Badge::Moderator); cmd.set_min_badge(Badge::Moderator);
cmd cmd
} }
/// adminonly command that grants a temporary role /// adminonly command that grants a temporary role
fn create_iam_role_cmd() -> Command { fn create_iam_role_cmd() -> Command {
/* 1. Create a new blank cmd */ /* 1. Create a new blank cmd */
let mut cmd = Command::new(vec![ let mut cmd = Command::new(
"I am ".to_string(), vec!["I am ".to_string(), "I'm ".to_string(), "Im a ".to_string()],
"I'm ".to_string(), "".to_string(),
"Im a ".to_string(), );
],"".to_string());
/* 2. Define an async fn callback execution */ /* 2. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { for (i, arg) in msg
.message_text
.replace("\u{e0000}", "")
.trim()
.split(" ")
.enumerate()
{
if i > 1 { if i > 1 {
// bot.disable_module(msg.channel_login.clone(), arg.to_string()).await; // bot.disable_module(msg.channel_login.clone(), arg.to_string()).await;
// #todo // #todo
// if not dont have the badge or have a lower priviledge badge // if not dont have the badge or have a lower priviledge badge
// and they dont have an active guest badge, ths admin can be // and they dont have an active guest badge, ths admin can be
// recognzed wth that badge // recognzed wth that badge
if arg == "mod" || arg == "moderator" { if arg == "mod" || arg == "moderator" {
let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; let curr_temp_badges = bot
.get_channel_guest_badges(
msg.sender.login.clone(),
msg.channel_login.clone(),
)
.await;
let mut found = false; let mut found = false;
for temp_badge in curr_temp_badges { for temp_badge in curr_temp_badges {
if temp_badge.0 == Badge::Moderator { if temp_badge.0 == Badge::Moderator {
found = true; found = true;
} }
} }
if found { if found {
/* do nothing */ /* do nothing */
} else { } else {
bot.issue_new_guest_badge( bot.issue_new_guest_badge(
msg.sender.login.clone(), msg.sender.login.clone(),
msg.channel_login.clone(), msg.channel_login.clone(),
Badge::Moderator, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; Badge::Moderator,
Instant::now(),
Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
)
.await;
let _ = bot.chat.lock().await.say_in_reply_to(&msg, let _ = bot
format!("Temp {:?} issued for {:?} minutes",Badge::Moderator,TEMP_BADGE_DUR_MIN) .chat
).await ; .lock()
.await
.say_in_reply_to(
&msg,
format!(
"Temp {:?} issued for {:?} minutes",
Badge::Moderator,
TEMP_BADGE_DUR_MIN
),
)
.await;
} }
} }
if arg == "vip" { if arg == "vip" {
let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; let curr_temp_badges = bot
.get_channel_guest_badges(
msg.sender.login.clone(),
msg.channel_login.clone(),
)
.await;
let mut found = false; let mut found = false;
for temp_badge in curr_temp_badges { for temp_badge in curr_temp_badges {
if temp_badge.0 == Badge::Vip { if temp_badge.0 == Badge::Vip {
found = true; found = true;
} }
} }
if found { if found {
/* do nothing */ /* do nothing */
} else { } else {
bot.issue_new_guest_badge( bot.issue_new_guest_badge(
msg.sender.login.clone(), msg.sender.login.clone(),
msg.channel_login.clone(), msg.channel_login.clone(),
Badge::Vip, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; Badge::Vip,
Instant::now(),
Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
)
.await;
let _ = bot.chat.lock().await.say_in_reply_to(&msg, let _ = bot
format!("Temp {:?} issued for {:?} minutes for the bot admin",Badge::Vip,TEMP_BADGE_DUR_MIN) .chat
).await ; .lock()
.await
.say_in_reply_to(
&msg,
format!(
"Temp {:?} issued for {:?} minutes for the bot admin",
Badge::Vip,
TEMP_BADGE_DUR_MIN
),
)
.await;
} }
} }
if arg == "broadcaster" || arg == "strimmer" || arg == "streamer" { if arg == "broadcaster" || arg == "strimmer" || arg == "streamer" {
let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; let curr_temp_badges = bot
.get_channel_guest_badges(
msg.sender.login.clone(),
msg.channel_login.clone(),
)
.await;
let mut found = false; let mut found = false;
for temp_badge in curr_temp_badges { for temp_badge in curr_temp_badges {
if temp_badge.0 == Badge::Broadcaster { if temp_badge.0 == Badge::Broadcaster {
found = true; found = true;
} }
} }
if found { if found {
/* do nothing */ /* do nothing */
} else { } else {
bot.issue_new_guest_badge( bot.issue_new_guest_badge(
msg.sender.login.clone(), msg.sender.login.clone(),
msg.channel_login.clone(), msg.channel_login.clone(),
Badge::Broadcaster, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; Badge::Broadcaster,
Instant::now(),
let _ = bot.chat.lock().await.say_in_reply_to(&msg, Duration::from_secs(60 * TEMP_BADGE_DUR_MIN),
format!("Temp {:?} issued for {:?} minutes for the bot admin",Badge::Broadcaster,TEMP_BADGE_DUR_MIN) )
).await ; .await;
let _ = bot
.chat
.lock()
.await
.say_in_reply_to(
&msg,
format!(
"Temp {:?} issued for {:?} minutes for the bot admin",
Badge::Broadcaster,
TEMP_BADGE_DUR_MIN
),
)
.await;
} }
} }
} }
} }
// let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ; // let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ;
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set and Store the execution body using `execution_async()` */ /* 3. Set and Store the execution body using `execution_async()` */
@ -314,8 +395,5 @@ pub mod built_in_objects {
// /* 5. optionally, set min badge*/ // /* 5. optionally, set min badge*/
// cmd.set_min_badge(Badge::Moderator); // cmd.set_min_badge(Badge::Moderator);
cmd cmd
}
} }
}

View file

@ -2,131 +2,124 @@ use std::sync::Arc;
use twitch_irc::message::{PrivmsgMessage, ServerMessage}; use twitch_irc::message::{PrivmsgMessage, ServerMessage};
use super::{command_condition_async, execution_async, Badge, Bot};
use super::{execution_async,Bot,Badge,command_condition_async};
use super::{CommandTrigger, ExecBody}; use super::{CommandTrigger, ExecBody};
/// Bot `Command` that stores trigger condition callback and a execution functon /// Bot `Command` that stores trigger condition callback and a execution functon
/// ///
/// A prefix character or phrase can be defined for the bot to evaluate a trigger condition /// A prefix character or phrase can be defined for the bot to evaluate a trigger condition
/// ///
/// A command or command phrase defines the phrase after the prefix phrase /// A command or command phrase defines the phrase after the prefix phrase
/// ///
/// If no min badge role is provided, Broadcaster is defaulted. All commands require at least a vip role /// If no min badge role is provided, Broadcaster is defaulted. All commands require at least a vip role
/// ///
/// AdminOnly commands can only be ran by admin /// AdminOnly commands can only be ran by admin
/// ///
/// Use `execution_async()` on custom async execution bodies /// Use `execution_async()` on custom async execution bodies
#[derive(Clone)] #[derive(Clone)]
pub struct Command pub struct Command {
{ commands: Vec<String>,
commands : Vec<String>, exec_fn: Arc<ExecBody>,
exec_fn : Arc<ExecBody>, min_badge: Badge,
min_badge : Badge,
/// only admins can run - default : `true` /// only admins can run - default : `true`
admin_only : bool, admin_only: bool,
/// admin role overrides channel badge - default : `false` /// admin role overrides channel badge - default : `false`
admin_override : bool, admin_override: bool,
prefix : String, prefix: String,
custom_cond_fn : fn(Arc<Bot>,PrivmsgMessage) -> bool, custom_cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool,
custom_cond_async : Arc<CommandTrigger>, custom_cond_async: Arc<CommandTrigger>,
} }
impl Command impl Command {
{
/// Creates a new empty `Command` using command `String` and prefix `String` /// Creates a new empty `Command` using command `String` and prefix `String`
/// Pass an empty string prefix if the bot should use the bot default /// Pass an empty string prefix if the bot should use the bot default
/// ///
/// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks
/// if a blank prefix is given, the bot will look for the bot prefix instead /// if a blank prefix is given, the bot will look for the bot prefix instead
/// ///
/// By default, the new command is admin_only /// By default, the new command is admin_only
pub fn new(commands:Vec<String>,prefix:String) -> Command { pub fn new(commands: Vec<String>, prefix: String) -> Command {
async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> {
async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> Result::Ok("success".to_string())
{ Result::Ok("success".to_string()) } }
async fn condition01(_:Arc<Bot>,_:PrivmsgMessage) -> bool { true } async fn condition01(_: Arc<Bot>, _: PrivmsgMessage) -> bool {
true
}
Command { Command {
commands , commands,
prefix , prefix,
exec_fn : Arc::new(execution_async(execbody)), exec_fn: Arc::new(execution_async(execbody)),
min_badge : Badge::Vip, min_badge: Badge::Vip,
admin_only : true, admin_only: true,
admin_override : false , admin_override: false,
custom_cond_fn : |_:Arc<Bot>,_:PrivmsgMessage| true, custom_cond_fn: |_: Arc<Bot>, _: PrivmsgMessage| true,
custom_cond_async : Arc::new(command_condition_async(condition01)), custom_cond_async: Arc::new(command_condition_async(condition01)),
} }
} }
/// set a trigger condition callback that returns true if the command should trigger /// set a trigger condition callback that returns true if the command should trigger
pub fn set_custom_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,PrivmsgMessage) -> bool) { pub fn set_custom_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool) {
self.custom_cond_fn = cond_fn; self.custom_cond_fn = cond_fn;
} }
/// sets the async trigger condition for listener /// sets the async trigger condition for listener
/// ///
/// Same as `set_custom_cond_fn()` , but async define /// Same as `set_custom_cond_fn()` , but async define
/// ///
/// Use`execution_async()` on the async fn when storing /// Use`execution_async()` on the async fn when storing
/// ///
/// Example - /// Example -
/// ```rust /// ```rust
/// /* 1. Create a new blank Listener */ /// /* 1. Create a new blank Listener */
/// let mut cmd = Command::new(); /// let mut cmd = Command::new();
/// ///
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true }
/// ///
/// /* 3. Set and Store the execution body using `execution_async()` */ /// /* 3. Set and Store the execution body using `execution_async()` */
/// cmd.set_custom_cond_async(condition_async(condition01)); /// cmd.set_custom_cond_async(condition_async(condition01));
/// ``` /// ```
/// ///
pub fn set_custom_cond_async(&mut self,condition:CommandTrigger ) { pub fn set_custom_cond_async(&mut self, condition: CommandTrigger) {
self.custom_cond_async = Arc::new(condition); self.custom_cond_async = Arc::new(condition);
} }
/// sets the execution body of the listener for when it triggers /// sets the execution body of the listener for when it triggers
/// ///
/// Use`execution_async()` on the async fn when storing /// Use`execution_async()` on the async fn when storing
/// ///
/// ///
pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { pub fn set_exec_fn(&mut self, exec_fn: ExecBody) {
self.exec_fn = Arc::new(exec_fn); self.exec_fn = Arc::new(exec_fn);
} }
/// checks if the trigger condition is met /// checks if the trigger condition is met
/// specifically if the message is a valid command and min badge roles provided /// specifically if the message is a valid command and min badge roles provided
/// ///
pub async fn command_triggered(&self,bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { pub async fn command_triggered(&self, bot: Arc<Bot>, msg: PrivmsgMessage) -> bool {
fn cmd_called(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
fn cmd_called(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { let mut prefixed_cmd = "".to_string();
let mut prefixed_cmd = "".to_string(); if cmd.prefix == "" {
if cmd.prefix == "" { prefixed_cmd.push_str(&bot.get_prefix());
prefixed_cmd.push_str(&bot.get_prefix()); } else {
} else { prefixed_cmd.push_str(&cmd.prefix);
prefixed_cmd.push_str(&cmd.prefix); }
for cmd_nm in &cmd.commands {
prefixed_cmd.push_str(cmd_nm);
if message.message_text.starts_with(prefixed_cmd.as_str()) {
return true;
} }
for cmd_nm in &cmd.commands { }
prefixed_cmd.push_str(cmd_nm); return false;
if message.message_text.starts_with(prefixed_cmd.as_str()) {
return true;
}
};
return false;
} }
async fn caller_badge_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
async fn caller_badge_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
// senders that are admins skip badge check if the command is adminonly // senders that are admins skip badge check if the command is adminonly
if cmd.admin_only && bot.get_admins().contains(&message.sender.login) { if cmd.admin_only && bot.get_admins().contains(&message.sender.login) {
return true; return true;
} ; };
// adminOnly commands will can only be ran by admins // adminOnly commands will can only be ran by admins
if cmd.admin_only && bot.get_admins().contains(&message.sender.login) { if cmd.admin_only && bot.get_admins().contains(&message.sender.login) {
@ -134,35 +127,41 @@ impl Command
} }
// admin role overrides badge check if enabled // admin role overrides badge check if enabled
if cmd.admin_override && bot.get_admins().contains( &message.sender.login) { return true; } if cmd.admin_override && bot.get_admins().contains(&message.sender.login) {
return true;
}
for badge in message.badges { for badge in message.badges {
match cmd.min_badge { match cmd.min_badge {
Badge::Broadcaster => { Badge::Broadcaster => {
if badge.name == "broadcaster" { return true } if badge.name == "broadcaster" {
else { return false } return true;
}, } else {
Badge::Moderator => { return false;
match badge.name.as_str() {
"moderator" | "broadcaster" => return true,
_ => (),
} }
}
Badge::Moderator => match badge.name.as_str() {
"moderator" | "broadcaster" => return true,
_ => (),
}, },
Badge::Vip => { Badge::Vip => match badge.name.as_str() {
match badge.name.as_str() { "vip" | "moderator" | "broadcaster" => return true,
"vip" | "moderator" | "broadcaster" => return true, _ => (),
_ => (),
}
}, },
} }
} }
for temp_badge in bot.get_channel_guest_badges(message.sender.login, message.channel_login).await { for temp_badge in bot
match (cmd.min_badge.clone(),temp_badge.0) { .get_channel_guest_badges(message.sender.login, message.channel_login)
(Badge::Broadcaster,Badge::Broadcaster) => return true, .await
(Badge::Moderator,Badge::Moderator) | (Badge::Moderator,Badge::Broadcaster) => return true, {
(Badge::Vip,Badge::Vip)|(Badge::Vip,Badge::Moderator)|(Badge::Vip,Badge::Broadcaster) => return true, match (cmd.min_badge.clone(), temp_badge.0) {
(Badge::Broadcaster, Badge::Broadcaster) => return true,
(Badge::Moderator, Badge::Moderator)
| (Badge::Moderator, Badge::Broadcaster) => return true,
(Badge::Vip, Badge::Vip)
| (Badge::Vip, Badge::Moderator)
| (Badge::Vip, Badge::Broadcaster) => return true,
_ => (), _ => (),
} }
} }
@ -170,59 +169,58 @@ impl Command
return false; return false;
} }
/// determines if the command caller can run the command
/// determines if the command caller can run the command
/// based on admin_only flag /// based on admin_only flag
/// ///
/// callers who are admins can run admin_only commands /// callers who are admins can run admin_only commands
/// callers can run non-admin_only commands /// callers can run non-admin_only commands
fn admin_only_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { fn admin_only_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
if (cmd.admin_only && bot.get_admins().contains(&message.sender.login)) || !cmd.admin_only { if (cmd.admin_only && bot.get_admins().contains(&message.sender.login))
|| !cmd.admin_only
{
return true; return true;
} else { } else {
return false; return false;
} }
} }
async fn custom_cond_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { async fn custom_cond_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool {
(cmd.custom_cond_fn)(bot.clone(),message.clone()) && (cmd.custom_cond_async)(bot,message).await (cmd.custom_cond_fn)(bot.clone(), message.clone())
&& (cmd.custom_cond_async)(bot, message).await
} }
// async fn quiet_off_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { // async fn quiet_off_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
// !bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) // !bot.chat.lock().await.get_channel_quiet(message.channel_login.clone())
// || bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) && cmd.commands.contains(&("quiet off".to_string())) // || bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) && cmd.commands.contains(&("quiet off".to_string()))
// } // }
cmd_called(self, bot.clone(), msg.clone())
cmd_called(self, bot.clone(), msg.clone()) && && caller_badge_ok(self, bot.clone(), msg.clone()).await
caller_badge_ok(self, bot.clone(), msg.clone()).await && && admin_only_ok(self, bot.clone(), msg.clone())
admin_only_ok(self, bot.clone(), msg.clone()) && && custom_cond_ok(self, bot.clone(), msg.clone()).await
custom_cond_ok(self, bot.clone(), msg.clone()).await
// && // &&
// quiet_off_ok(self, bot, msg).await // quiet_off_ok(self, bot, msg).await
} }
/// executes the listeners executon body /// executes the listeners executon body
pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> { pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> {
(self.exec_fn)(bot,msg).await (self.exec_fn)(bot, msg).await
} }
/// sets min_badge to run the cmd /// sets min_badge to run the cmd
// pub fn set_min_badge(&mut self,min_badge:String) { // pub fn set_min_badge(&mut self,min_badge:String) {
pub fn set_min_badge(&mut self,min_badge:Badge) { pub fn set_min_badge(&mut self, min_badge: Badge) {
self.min_badge = min_badge self.min_badge = min_badge
} }
/// sets admin_only /// sets admin_only
pub fn set_admin_only(&mut self,admin_only:bool) { pub fn set_admin_only(&mut self, admin_only: bool) {
self.admin_only = admin_only self.admin_only = admin_only
} }
/// sets admin_override . This lets admins bypass /// sets admin_override . This lets admins bypass
/// badge restrictions /// badge restrictions
pub fn set_admin_override(&mut self,admin_override:bool) { pub fn set_admin_override(&mut self, admin_override: bool) {
self.admin_override = admin_override self.admin_override = admin_override
} }
} }

View file

@ -1,124 +1,126 @@
use std::sync::Arc; use std::sync::Arc;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
use crate::Module; use crate::Module;
use super::{execution_async,Bot,listener_condition_async}; use super::{execution_async, listener_condition_async, Bot};
use super::{ExecBody, ListenerTrigger}; use super::{ExecBody, ListenerTrigger};
/// Bot `Listener` that stores trigger condition callback and a execution functon /// Bot `Listener` that stores trigger condition callback and a execution functon
/// ///
/// Use `Listener` functions to define the Trigger Condition & Execution callbacks. /// Use `Listener` functions to define the Trigger Condition & Execution callbacks.
/// When the Trigger callback is `true`, the Execution callback runs in the bot loop /// When the Trigger callback is `true`, the Execution callback runs in the bot loop
/// ///
/// Create a new empty `Listener` with `new()` /// Create a new empty `Listener` with `new()`
/// ///
/// Use the following on the empty listener before loading it into the bot to set the callbacks /// Use the following on the empty listener before loading it into the bot to set the callbacks
/// ///
/// - `set_trigger_cond_fn()` - to define the Trigger condition callback /// - `set_trigger_cond_fn()` - to define the Trigger condition callback
/// ///
/// - `set_exec_fn()` - to define the Execution Callback /// - `set_exec_fn()` - to define the Execution Callback
#[derive(Clone)] #[derive(Clone)]
pub struct Listener pub struct Listener {
{
/// trigger condition /// trigger condition
trigger_cond_fn : fn(Arc<Bot>,ServerMessage) -> bool, trigger_cond_fn: fn(Arc<Bot>, ServerMessage) -> bool,
/// trigger condition for async /// trigger condition for async
trigger_cond_async : Arc<ListenerTrigger> , trigger_cond_async: Arc<ListenerTrigger>,
/// execution body /// execution body
exec_fn : Arc<ExecBody>, exec_fn: Arc<ExecBody>,
parent_module : Arc<Option<Module>>, parent_module: Arc<Option<Module>>,
} }
impl Listener impl Listener {
{ /// Creates a new empty `Listener`
///
/// Creates a new empty `Listener` /// Use `Listener` functions to define the Trigger Condition & Execution callbacks.
/// /// When the Trigger callback is `true`, the Execution callback runs in the bot loop
/// Use `Listener` functions to define the Trigger Condition & Execution callbacks. ///
/// When the Trigger callback is `true`, the Execution callback runs in the bot loop
///
/// Use the following on the empty listener before loading it into the bot to set the callbacks /// Use the following on the empty listener before loading it into the bot to set the callbacks
/// ///
/// - `set_trigger_cond_fn()` - to define the Trigger condition callback /// - `set_trigger_cond_fn()` - to define the Trigger condition callback
/// ///
/// - `set_exec_fn()` - to define the Execution Callback /// - `set_exec_fn()` - to define the Execution Callback
pub fn new() -> Listener { pub fn new() -> Listener {
async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> {
async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } Result::Ok("success".to_string())
async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } }
async fn condition01(_: Arc<Bot>, _: ServerMessage) -> bool {
true
}
Listener { Listener {
trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| true, trigger_cond_fn: |_: Arc<Bot>, _: ServerMessage| true,
trigger_cond_async : Arc::new(listener_condition_async(condition01)), trigger_cond_async: Arc::new(listener_condition_async(condition01)),
exec_fn : Arc::new(execution_async(execbody)), exec_fn: Arc::new(execution_async(execbody)),
parent_module : Arc::new(None), parent_module: Arc::new(None),
} }
} }
/// set a trigger conditin callback that returns true if the listener shoud trigger /// set a trigger conditin callback that returns true if the listener shoud trigger
pub fn set_trigger_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,ServerMessage) -> bool) { pub fn set_trigger_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, ServerMessage) -> bool) {
self.trigger_cond_fn = cond_fn; self.trigger_cond_fn = cond_fn;
} }
/// sets the async trigger condition for listener /// sets the async trigger condition for listener
/// ///
/// Same as `set_trigger_cond_fn()` , but async define /// Same as `set_trigger_cond_fn()` , but async define
/// ///
/// Use`condition_async()` on the async fn when storing /// Use`condition_async()` on the async fn when storing
/// ///
/// Example - /// Example -
/// ```rust /// ```rust
/// /* 1. Create a new blank Listener */ /// /* 1. Create a new blank Listener */
/// let mut listener = Listener::new(); /// let mut listener = Listener::new();
/// ///
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true }
/// ///
/// /* 3. Set and Store the execution body using `execution_async()` */ /// /* 3. Set and Store the execution body using `execution_async()` */
/// listener.set_trigger_cond_async(condition_async(condition01)); /// listener.set_trigger_cond_async(condition_async(condition01));
/// ``` /// ```
/// ///
pub fn set_trigger_cond_async(&mut self,condition:ListenerTrigger ) { pub fn set_trigger_cond_async(&mut self, condition: ListenerTrigger) {
self.trigger_cond_async = Arc::new(condition); self.trigger_cond_async = Arc::new(condition);
} }
/// sets the execution body of the listener for when it triggers /// sets the execution body of the listener for when it triggers
/// ///
/// Use`execution_async()` on the async fn when storing /// Use`execution_async()` on the async fn when storing
/// ///
/// Example - /// Example -
/// ```rust /// ```rust
/// /* 1. Create a new blank Listener */ /// /* 1. Create a new blank Listener */
/// let mut listener = Listener::new(); /// let mut listener = Listener::new();
/// ///
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
/// ///
/// /* 3. Set and Store the execution body using `execution_async()` */ /// /* 3. Set and Store the execution body using `execution_async()` */
/// listener.set_exec_fn(execution_async(execbody)); /// listener.set_exec_fn(execution_async(execbody));
/// ``` /// ```
/// ///
pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { pub fn set_exec_fn(&mut self, exec_fn: ExecBody) {
self.exec_fn = Arc::new(exec_fn); self.exec_fn = Arc::new(exec_fn);
} }
/// checks if the trigger condition is met /// checks if the trigger condition is met
pub async fn cond_triggered(&self,bot:Arc<Bot>,msg:ServerMessage) -> bool { pub async fn cond_triggered(&self, bot: Arc<Bot>, msg: ServerMessage) -> bool {
let list = Arc::new(self.clone()); let list = Arc::new(self.clone());
async fn defined_conditions_ok(list:Arc<Listener>,bot:Arc<Bot>,msg:ServerMessage) -> bool { async fn defined_conditions_ok(
list: Arc<Listener>,
bot: Arc<Bot>,
msg: ServerMessage,
) -> bool {
// let list = Arc::new(self); // let list = Arc::new(self);
(list.trigger_cond_fn)(bot.clone(),msg.clone()) && (list.trigger_cond_async)(bot,msg).await (list.trigger_cond_fn)(bot.clone(), msg.clone())
&& (list.trigger_cond_async)(bot, msg).await
} }
// async fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool { // async fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool {
// if let ServerMessage::Privmsg(msg) = message { // if let ServerMessage::Privmsg(msg) = message {
// if let Some(parent_mod) = &*list.parent_module { // if let Some(parent_mod) = &*list.parent_module {
// return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) || parent_mod.get_names().contains(&"debug".to_string()); // return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) || parent_mod.get_names().contains(&"debug".to_string());
// } // }
@ -128,22 +130,18 @@ impl Listener
// return true; /* quiet is off for non chat msgs */ // return true; /* quiet is off for non chat msgs */
// } // }
defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await
// && // &&
// quiet_off_ok(list, bot, msg).await // quiet_off_ok(list, bot, msg).await
} }
/// executes the listeners executon body /// executes the listeners executon body
pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> { pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> {
(self.exec_fn)(bot, msg).await
(self.exec_fn)(bot,msg).await
} }
/// sets parent module /// sets parent module
pub fn set_parent_module(&mut self,module:Module) { pub fn set_parent_module(&mut self, module: Module) {
self.parent_module = Arc::new(Some(module)); self.parent_module = Arc::new(Some(module));
} }
} }

View file

@ -4,11 +4,7 @@ use crate::Bot;
pub mod quiet; pub mod quiet;
/// used to internally load internal modules /// used to internally load internal modules
pub async fn load_built_in_mods(bot:&Bot){ pub async fn load_built_in_mods(bot: &Bot) {
bot.load_module(quiet::create_module()).await; bot.load_module(quiet::create_module()).await;
} }

View file

@ -4,18 +4,17 @@ use twitch_irc::message::ServerMessage;
use crate::{execution_async, Badge, Bot, Command, Module}; use crate::{execution_async, Badge, Bot, Command, Module};
/// quiet the bot in a channel /// quiet the bot in a channel
/// ///
/// use /// use
/// `quiet on` /// `quiet on`
/// `quiet off` /// `quiet off`
/// ///
/// ///
/// ///
/// Use this function when loading modules into the bot /// Use this function when loading modules into the bot
/// ///
/// For example /// For example
/// ```rust /// ```rust
/// bot.load_module(quiet::create_module()); /// bot.load_module(quiet::create_module());
@ -23,38 +22,33 @@ use crate::{execution_async, Badge, Bot, Command, Module};
/// ///
pub fn create_module() -> Module { pub fn create_module() -> Module {
/* 1. Create a new module */ /* 1. Create a new module */
let mut custom_mod = Module::new( let mut custom_mod = Module::new(vec!["quiet".to_string()], "".to_string());
vec!["quiet".to_string()],
"".to_string());
/* 2. Load the cmd into a new module */ /* 2. Load the cmd into a new module */
custom_mod.load_command(cmd_quiet_on()); custom_mod.load_command(cmd_quiet_on());
custom_mod.load_command(cmd_quiet_off()); custom_mod.load_command(cmd_quiet_off());
custom_mod custom_mod
} }
/// Command definition for quiet command /// Command definition for quiet command
fn cmd_quiet_on() -> Command { fn cmd_quiet_on() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["quiet on".to_string()],"".to_string()); let mut cmd = Command::new(vec!["quiet on".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
// dbg!("quiet on called"); // dbg!("quiet on called");
let chatlock = bot.chat.lock().await; let chatlock = bot.chat.lock().await;
let _=chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await; let _ = chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await;
chatlock.set_channel_quiet(msg.channel_login.clone(), true); chatlock.set_channel_quiet(msg.channel_login.clone(), true);
println!("channel {} set quiet true",msg.channel_login); println!("channel {} set quiet true", msg.channel_login);
return Result::Ok("Success".to_string()); return Result::Ok("Success".to_string());
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */
@ -69,21 +63,21 @@ fn cmd_quiet_on() -> Command {
/// Command definition for quiet command /// Command definition for quiet command
fn cmd_quiet_off() -> Command { fn cmd_quiet_off() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["quiet off".to_string()],"".to_string()); let mut cmd = Command::new(vec!["quiet off".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let chatlock = bot.chat.lock().await; let chatlock = bot.chat.lock().await;
chatlock.set_channel_quiet(msg.channel_login.clone(), false); chatlock.set_channel_quiet(msg.channel_login.clone(), false);
let _=chatlock.say_in_reply_to(&msg, "GoodGirl I'll be good for u chat rar ".to_string()).await; let _ = chatlock
.say_in_reply_to(&msg, "GoodGirl I'll be good for u chat rar ".to_string())
.await;
println!("channel {} set quiet false",msg.channel_login);
println!("channel {} set quiet false", msg.channel_login);
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */

View file

@ -1,34 +1,36 @@
use std::{fmt::Error, ops::Mul, rc::Rc, sync::{Arc, Mutex, RwLock}}; use std::{
fmt::Error,
ops::Mul,
rc::Rc,
sync::{Arc, Mutex, RwLock},
};
use twitch_irc::{login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient}; use twitch_irc::{
login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient,
};
use crate::Bot; use crate::Bot;
/// Bot API to send messages to send messages to chat /// Bot API to send messages to send messages to chat
/// ///
/// Uses TwitchIRCClient say_in_reply_to() but enforces controls like quiet /// Uses TwitchIRCClient say_in_reply_to() but enforces controls like quiet
/// ///
/// ///
pub struct Chat pub struct Chat {
{
/// outbound chat client msg stream /// outbound chat client msg stream
pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>,
/// channel_quiet /// channel_quiet
channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>, channel_quiet_yn: RwLock<Vec<(String, RwLock<bool>)>>,
} }
impl Chat { impl Chat {
pub async fn new(client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>) -> Chat {
Chat {
pub async fn new(client:TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>)
-> Chat {
Chat {
client, client,
// parent_bot : Mutex::new(Bot::new().await) , // parent_bot : Mutex::new(Bot::new().await) ,
channel_quiet_yn : RwLock::new(vec![]), channel_quiet_yn: RwLock::new(vec![]),
} }
} }
// pub fn set_parent_bot(&self,parent_bot_in:Arc<Bot>) // pub fn set_parent_bot(&self,parent_bot_in:Arc<Bot>)
@ -38,23 +40,20 @@ impl Chat {
// } // }
/// helper /// helper
fn ok_to_send(&self,channel_login: String) -> bool { fn ok_to_send(&self, channel_login: String) -> bool {
fn not_quiet_ok(chat: &Chat, channel_login: String) -> bool {
fn not_quiet_ok(chat:&Chat,channel_login:String) -> bool {
// let lock = chat.parent_bot.lock().unwrap(); // let lock = chat.parent_bot.lock().unwrap();
// let a = lock.as_ref(); // let a = lock.as_ref();
// if let Some(bot) = &*lock { // if let Some(bot) = &*lock {
return !chat.get_channel_quiet(channel_login); return !chat.get_channel_quiet(channel_login);
// } // }
// true // true
} }
not_quiet_ok(self, channel_login) not_quiet_ok(self, channel_login)
} }
/// Get the quiet status of a channel /// Get the quiet status of a channel
pub fn get_channel_quiet(&self,channel:String) -> bool { pub fn get_channel_quiet(&self, channel: String) -> bool {
for a in self.channel_quiet_yn.read().unwrap().iter() { for a in self.channel_quiet_yn.read().unwrap().iter() {
if a.0 == channel { if a.0 == channel {
return a.1.read().unwrap().clone(); return a.1.read().unwrap().clone();
@ -62,9 +61,9 @@ impl Chat {
} }
return false; return false;
} }
/// Get the quiet status of a channel /// Get the quiet status of a channel
pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) { pub fn set_channel_quiet(&self, channel: String, quiet_on: bool) {
let mut found = false; let mut found = false;
let chnlquiet = self.channel_quiet_yn.read().unwrap(); let chnlquiet = self.channel_quiet_yn.read().unwrap();
@ -77,22 +76,20 @@ impl Chat {
} }
} }
drop(chnlquiet); drop(chnlquiet);
if !found { if !found {
// dbg!("set chn quiet > !found channel quiet status"); // dbg!("set chn quiet > !found channel quiet status");
let mut chnlquiet = self.channel_quiet_yn.write().unwrap(); let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
chnlquiet.push((channel,RwLock::new(quiet_on))); chnlquiet.push((channel, RwLock::new(quiet_on)));
drop(chnlquiet); drop(chnlquiet);
} }
} }
pub async fn say_in_reply_to(
&self,
pub async fn say_in_reply_to(&self, reply_to: &impl ReplyToMessage,
reply_to: &impl ReplyToMessage, message: String,
message: String ) -> Result<(), ()> {
) -> Result<(),()> {
// reply_to.channel_login() // reply_to.channel_login()
if self.ok_to_send(reply_to.channel_login().to_string()) { if self.ok_to_send(reply_to.channel_login().to_string()) {
match self.client.say_in_reply_to(reply_to, message).await { match self.client.say_in_reply_to(reply_to, message).await {
@ -102,50 +99,42 @@ impl Chat {
} else { } else {
return Err(()); return Err(());
} }
} }
pub async fn say(&self, pub async fn say(&self, channel_login: String, message: String) -> Result<(), ()> {
channel_login: String,
message: String,
) -> Result<(),()> {
if self.ok_to_send(channel_login.to_string()) { if self.ok_to_send(channel_login.to_string()) {
match self.client.say(channel_login, message).await { match self.client.say(channel_login, message).await {
Ok(_) => return Ok(()), Ok(_) => return Ok(()),
Err(_) => return Err(()), Err(_) => return Err(()),
} }
} else { } else {
return Err(()); return Err(());
} }
} }
pub async fn me(&self, pub async fn me(&self, channel_login: String, message: String) -> Result<(), ()> {
channel_login: String,
message: String,
) -> Result<(),()> {
if self.ok_to_send(channel_login.to_string()) { if self.ok_to_send(channel_login.to_string()) {
match self.client.me(channel_login, message).await { match self.client.me(channel_login, message).await {
Ok(_) => return Ok(()), Ok(_) => return Ok(()),
Err(_) => return Err(()), Err(_) => return Err(()),
} }
} else { } else {
return Err(()); return Err(());
} }
} }
pub async fn me_in_reply_to(&self, pub async fn me_in_reply_to(
&self,
reply_to: &impl ReplyToMessage, reply_to: &impl ReplyToMessage,
message: String message: String,
) -> Result<(),()> { ) -> Result<(), ()> {
if self.ok_to_send(reply_to.channel_login().to_string()) { if self.ok_to_send(reply_to.channel_login().to_string()) {
match self.client.me_in_reply_to(reply_to, message).await { match self.client.me_in_reply_to(reply_to, message).await {
Ok(_) => return Ok(()), Ok(_) => return Ok(()),
Err(_) => return Err(()), Err(_) => return Err(()),
}
} else {
return Err(());
}
} }
} else { }
return Err(());
}
}
}

View file

@ -1,11 +1,9 @@
// use std::sync::{Arc, Mutex}; // use std::sync::{Arc, Mutex};
use super::bot_objects::command::Command; use super::bot_objects::command::Command;
use super::bot_objects::listener::Listener; use super::bot_objects::listener::Listener;
#[derive(PartialEq, Eq, Debug, Clone)]
#[derive(PartialEq, Eq,Debug,Clone)]
pub enum Status { pub enum Status {
Disabled, Disabled,
Enabled, Enabled,
@ -13,24 +11,22 @@ pub enum Status {
} }
/// Bot `Module` that groups a set of `bot_objects` /// Bot `Module` that groups a set of `bot_objects`
/// ///
/// Elevated chatters can disable modules by their name or chat alias /// Elevated chatters can disable modules by their name or chat alias
#[derive(Clone)] #[derive(Clone)]
pub struct Module pub struct Module {
{
name: Vec<String>, name: Vec<String>,
// _alias: String, // _alias: String,
bot_read_description : String, bot_read_description: String,
listeners: Vec<Listener>, listeners: Vec<Listener>,
commands: Vec<Command>, commands: Vec<Command>,
// disable module at load for bot channels // disable module at load for bot channels
default_status_per_channel: Status, default_status_per_channel: Status,
} }
impl Module impl Module {
{
/// create a new module /// create a new module
pub fn new(name:Vec<String>,bot_read_description:String) -> Module { pub fn new(name: Vec<String>, bot_read_description: String) -> Module {
Module { Module {
name, name,
// _alias: alias, // _alias: alias,
@ -42,20 +38,20 @@ impl Module
} }
/// Loads a `Listener` into the module /// Loads a `Listener` into the module
pub fn load_listener(&mut self,mut l : Listener) { pub fn load_listener(&mut self, mut l: Listener) {
l.set_parent_module(self.clone()); l.set_parent_module(self.clone());
self.listeners.push(l); self.listeners.push(l);
} }
/// Loads a `Command` into the module /// Loads a `Command` into the module
pub fn load_command(&mut self,c : Command) { pub fn load_command(&mut self, c: Command) {
self.commands.push(c); self.commands.push(c);
} }
pub fn get_listeners(&self) -> Vec<Listener> { pub fn get_listeners(&self) -> Vec<Listener> {
self.listeners.clone() self.listeners.clone()
} }
pub fn get_commands(&self) -> Vec<Command> { pub fn get_commands(&self) -> Vec<Command> {
self.commands.clone() self.commands.clone()
} }
@ -68,13 +64,11 @@ impl Module
self.bot_read_description.clone() self.bot_read_description.clone()
} }
pub fn set_status_by_default(&mut self,status:Status){ pub fn set_status_by_default(&mut self, status: Status) {
self.default_status_per_channel = status; self.default_status_per_channel = status;
} }
pub fn get_status_by_default(&self) -> Status { pub fn get_status_by_default(&self) -> Status {
self.default_status_per_channel.clone() self.default_status_per_channel.clone()
} }
}
}

View file

@ -1,4 +1,4 @@
pub mod debug;
pub mod guest_badge; pub mod guest_badge;
pub mod pyramid; pub mod pyramid;
pub mod debug; // pub mod quiet;
// pub mod quiet;

View file

@ -1,23 +1,20 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{execution_async, modules::Status, Bot, Command, Listener, Module}; use crate::{execution_async, modules::Status, Bot, Command, Listener, Module};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
/// debug module /// debug module
/// ///
/// Commands to enable debugging messages in chat /// Commands to enable debugging messages in chat
/// ///
/// `debug on` to start /// `debug on` to start
/// ///
/// `debug off` to stop /// `debug off` to stop
/// ///
/// ///
/// Use this function when loading modules into the bot /// Use this function when loading modules into the bot
/// ///
/// For example /// For example
/// ```rust /// ```rust
/// bot.load_module(debug::create_module()); /// bot.load_module(debug::create_module());
@ -25,38 +22,42 @@ use twitch_irc::message::ServerMessage;
/// ///
pub fn create_module() -> Module { pub fn create_module() -> Module {
/* 1. Create a new module */ /* 1. Create a new module */
let mut custom_mod = Module::new( let mut custom_mod = Module::new(vec!["debug".to_string()], "".to_string());
vec!["debug".to_string()],
"".to_string());
/* 2. Load the cmd into a new module */ /* 2. Load the cmd into a new module */
custom_mod.load_command(cmd_debug_on()); custom_mod.load_command(cmd_debug_on());
custom_mod.load_command(cmd_debug_off()); custom_mod.load_command(cmd_debug_off());
custom_mod custom_mod
} }
/// Command definition for debug command /// Command definition for debug command
fn cmd_debug_on() -> Command { fn cmd_debug_on() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["debug on".to_string()],"".to_string()); let mut cmd = Command::new(vec!["debug on".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
// dbg!("debug cmd on executed"); // dbg!("debug cmd on executed");
let modulename="debug listener".to_string(); let modulename = "debug listener".to_string();
if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await { if let Status::NotLoaded = bot
.get_channel_module_status(msg.channel_login.clone(), modulename.clone())
.await
{
let module = create_listener_module(modulename.clone()); let module = create_listener_module(modulename.clone());
bot.load_module(module.clone()).await; bot.load_module(module.clone()).await;
} }
let modl = bot.get_module(modulename).await.unwrap(); let modl = bot.get_module(modulename).await.unwrap();
bot.enable_module(msg.channel_login.clone(), modl.get_names().first().unwrap().clone()).await; bot.enable_module(
println!("Debug enabled for channel {}",msg.channel_login); msg.channel_login.clone(),
modl.get_names().first().unwrap().clone(),
)
.await;
println!("Debug enabled for channel {}", msg.channel_login);
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */
@ -71,24 +72,28 @@ fn cmd_debug_on() -> Command {
/// Command definition for debug off command /// Command definition for debug off command
fn cmd_debug_off() -> Command { fn cmd_debug_off() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["debug off".to_string()],"".to_string()); let mut cmd = Command::new(vec!["debug off".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
// dbg!("debug cmd on executed"); // dbg!("debug cmd on executed");
let modulename="debug listener".to_string(); let modulename = "debug listener".to_string();
// if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await { // if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await {
// let module = create_listener_module(modulename.clone()); // let module = create_listener_module(modulename.clone());
// bot.load_module(module.clone()).await; // bot.load_module(module.clone()).await;
// } // }
let modl = bot.get_module(modulename).await.unwrap(); let modl = bot.get_module(modulename).await.unwrap();
bot.disable_module(msg.channel_login.clone(), modl.get_names().first().unwrap().clone()).await; bot.disable_module(
println!("Debug disabled for channel {}",msg.channel_login); msg.channel_login.clone(),
modl.get_names().first().unwrap().clone(),
)
.await;
println!("Debug disabled for channel {}", msg.channel_login);
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */
@ -100,41 +105,34 @@ fn cmd_debug_off() -> Command {
cmd cmd
} }
fn create_listener_module(name:String) -> Module { fn create_listener_module(name: String) -> Module {
let mut custom_mod = Module::new(vec![name], "".to_string());
let mut custom_mod = Module::new( // dbg!("debug listener module created");
vec![name],
"".to_string());
// dbg!("debug listener module created");
custom_mod.load_listener(cmd_debug_listener()); custom_mod.load_listener(cmd_debug_listener());
custom_mod.set_status_by_default(Status::Disabled); custom_mod.set_status_by_default(Status::Disabled);
custom_mod custom_mod
} }
/// Listener for debug /// Listener for debug
fn cmd_debug_listener() -> Listener { fn cmd_debug_listener() -> Listener {
// dbg!("Creating debug listener"); // dbg!("Creating debug listener");
/* 2a. Create a new blank Listener */ /* 2a. Create a new blank Listener */
let mut listener = Listener::new(); let mut listener = Listener::new();
/* 2b. Set a trigger condition function for listener */ /* 2b. Set a trigger condition function for listener */
listener.set_trigger_cond_fn( listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
|_:Arc<Bot>,_:ServerMessage| true
);
/* 2c. Define an async fn callback execution */
async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
if let ServerMessage::Privmsg(msg) = message {
dbg!(msg); /* outputs message to debug */
}
Result::Err("Not Valid message type".to_string())
}
/* 2d. Set and Store the execution body using `execution_async()` */
listener.set_exec_fn(execution_async(execbody));
listener /* 2c. Define an async fn callback execution */
async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message {
dbg!(msg); /* outputs message to debug */
}
Result::Err("Not Valid message type".to_string())
}
/* 2d. Set and Store the execution body using `execution_async()` */
listener.set_exec_fn(execution_async(execbody));
listener
} }

View file

@ -1,91 +1,109 @@
use std::{sync::Arc, time::{Duration, Instant}}; use std::{
sync::Arc,
time::{Duration, Instant},
};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
use crate::{execution_async, Badge, Bot, Command, Module}; use crate::{execution_async, Badge, Bot, Command, Module};
/// guest_badge / guest module /// guest_badge / guest module
/// ///
/// Temporary badges can be issued to chatters. The bot then opens functionality /// Temporary badges can be issued to chatters. The bot then opens functionality
/// to that chatter based on the recognized role /// to that chatter based on the recognized role
/// ///
/// Chatters with real badge roles will be able to share guest /// Chatters with real badge roles will be able to share guest
/// badges based on their role /// badges based on their role
/// ///
/// ///
/// ///
const VIP_GIVEN_DUR_MIN:u64 = 15;
const MOD_GIVEN_DUR_MIN:u64 = 30;
const VIP_GIVEN_DUR_MIN: u64 = 15;
const MOD_GIVEN_DUR_MIN: u64 = 30;
/// Use this function when loading modules into the bot /// Use this function when loading modules into the bot
/// ///
/// For example /// For example
/// ```rust /// ```rust
/// bot.load_module(guest_badge::create_module()); /// bot.load_module(guest_badge::create_module());
/// ``` /// ```
/// ///
pub fn create_module() -> Module { pub fn create_module() -> Module {
let mut custom_mod = Module::new( let mut custom_mod = Module::new(
vec!["guests".to_string()], vec!["guests".to_string()],
"Temp Guest badges can be given by chatters with badges. ".to_string()); "Temp Guest badges can be given by chatters with badges. ".to_string(),
);
custom_mod.load_command(create_cmd_mod()); custom_mod.load_command(create_cmd_mod());
custom_mod.load_command(create_cmd_vip()); custom_mod.load_command(create_cmd_vip());
custom_mod
custom_mod
} }
fn create_cmd_vip() -> Command { fn create_cmd_vip() -> Command {
let mut cmd = Command::new(vec!["vip".to_string()], "".to_string());
let mut cmd = Command::new(vec!["vip".to_string()],"".to_string()); async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let guest_dur_min = { let guest_dur_min = {
let mut result=VIP_GIVEN_DUR_MIN; let mut result = VIP_GIVEN_DUR_MIN;
for badge in msg.clone().badges { for badge in msg.clone().badges {
if badge.name == "vip" { result = VIP_GIVEN_DUR_MIN ; } if badge.name == "vip" {
if badge.name == "moderator" { result = MOD_GIVEN_DUR_MIN ; } result = VIP_GIVEN_DUR_MIN;
}
if badge.name == "moderator" {
result = MOD_GIVEN_DUR_MIN;
}
} }
result result
}; };
let mut badges_issued = false;
let mut badges_issued =false; for (i, arg) in msg
for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { .message_text
.replace("\u{e0000}", "")
.trim()
.split(" ")
.enumerate()
{
if i > 1 { if i > 1 {
let mut already_vip = false; let mut already_vip = false;
for guest_badge in bot
for guest_badge in bot.get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()).await { .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone())
if guest_badge.0 == Badge::Vip { already_vip = true } .await
{
if guest_badge.0 == Badge::Vip {
already_vip = true
}
} }
if !already_vip { if !already_vip {
badges_issued= true; badges_issued = true;
bot.issue_new_guest_badge( bot.issue_new_guest_badge(
arg.trim().to_string(), arg.trim().to_string(),
msg.channel_login.clone(), msg.channel_login.clone(),
Badge::Vip, Instant::now(), Duration::from_secs(60*guest_dur_min)).await; Badge::Vip,
Instant::now(),
Duration::from_secs(60 * guest_dur_min),
)
.await;
} }
} }
} }
if badges_issued { if badges_issued {
let _ = bot
.chat
let _= bot.chat.lock().await.say_in_reply_to( .lock()
&msg.clone(), format!("Guest badges issued for {} min",guest_dur_min)).await; .await
.say_in_reply_to(
&msg.clone(),
format!("Guest badges issued for {} min", guest_dur_min),
)
.await;
return Result::Ok("Success".to_string()); return Result::Ok("Success".to_string());
} }
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
cmd.set_exec_fn(execution_async(execbody)); cmd.set_exec_fn(execution_async(execbody));
@ -94,41 +112,58 @@ fn create_cmd_vip() -> Command {
cmd.set_admin_override(true); cmd.set_admin_override(true);
cmd.set_min_badge(Badge::Vip); cmd.set_min_badge(Badge::Vip);
cmd cmd
} }
fn create_cmd_mod() -> Command { fn create_cmd_mod() -> Command {
let mut cmd = Command::new(vec!["mod".to_string()], "".to_string());
let mut cmd = Command::new(vec!["mod".to_string()],"".to_string()); async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let mut badges_issued = false;
for (i, arg) in msg
let mut badges_issued =false; .message_text
for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { .replace("\u{e0000}", "")
.trim()
.split(" ")
.enumerate()
{
if i > 1 { if i > 1 {
let mut already_mod = false; let mut already_mod = false;
for guest_badge in bot.get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()).await { for guest_badge in bot
if guest_badge.0 == Badge::Moderator { already_mod = true } .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone())
.await
{
if guest_badge.0 == Badge::Moderator {
already_mod = true
}
} }
if !already_mod { if !already_mod {
badges_issued= true; badges_issued = true;
bot.issue_new_guest_badge( bot.issue_new_guest_badge(
arg.trim().to_string(), arg.trim().to_string(),
msg.channel_login.clone(), msg.channel_login.clone(),
Badge::Moderator, Instant::now(), Duration::from_secs(60*MOD_GIVEN_DUR_MIN)).await; Badge::Moderator,
Instant::now(),
Duration::from_secs(60 * MOD_GIVEN_DUR_MIN),
)
.await;
} }
} }
} }
if badges_issued { if badges_issued {
let _= bot.chat.lock().await.say_in_reply_to( let _ = bot
&msg, format!("Guest badges issued for {} min",MOD_GIVEN_DUR_MIN)).await; .chat
.lock()
.await
.say_in_reply_to(
&msg,
format!("Guest badges issued for {} min", MOD_GIVEN_DUR_MIN),
)
.await;
return Result::Ok("Success".to_string()); return Result::Ok("Success".to_string());
} }
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
cmd.set_exec_fn(execution_async(execbody)); cmd.set_exec_fn(execution_async(execbody));
@ -137,6 +172,4 @@ fn create_cmd_mod() -> Command {
cmd.set_admin_override(true); cmd.set_admin_override(true);
cmd.set_min_badge(Badge::Moderator); cmd.set_min_badge(Badge::Moderator);
cmd cmd
}
}

View file

@ -1,169 +1,174 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use twitch_irc::message::{PrivmsgMessage, ServerMessage}; use twitch_irc::message::{PrivmsgMessage, ServerMessage};
// use crate::{execution_async, listener_condition_async, Badge, Bot, Command, Listener, Module}; // use crate::{execution_async, listener_condition_async, Badge, Bot, Command, Listener, Module};
use super::super::botcore::bot_objects::execution_async;
use super::super::botcore::bot_objects::listener_condition_async;
use super::super::botcore::bot_objects::listener::Listener;
use super::super::botcore::modules::Module;
use super::super::botcore::bot::Bot; use super::super::botcore::bot::Bot;
use super::super::botcore::bot_objects::command::Command; use super::super::botcore::bot_objects::command::Command;
use super::super::botcore::bot_objects::execution_async;
use super::super::botcore::bot_objects::listener::Listener;
use super::super::botcore::bot_objects::listener_condition_async;
use super::super::botcore::bot_objects::Badge; use super::super::botcore::bot_objects::Badge;
use super::super::botcore::modules::Module;
/// pyramid module /// pyramid module
/// ///
/// for detecting & handling pyramids /// for detecting & handling pyramids
/// ///
/// - listener - detects pyramid /// - listener - detects pyramid
/// - cmd & listener - interrupts some chatters temporarily /// - cmd & listener - interrupts some chatters temporarily
/// ///
/// ///
use lazy_static::lazy_static; use lazy_static::lazy_static;
/// Use this function when loading modules into the bot /// Use this function when loading modules into the bot
/// ///
/// For example /// For example
/// ```rust /// ```rust
/// bot.load_module(pyramid::create_module()); /// bot.load_module(pyramid::create_module());
/// ``` /// ```
/// ///
pub fn create_module() -> Module { pub fn create_module() -> Module {
let mut custom_mod = Module::new( let mut custom_mod = Module::new(
vec!["pyramid".to_string(), vec!["pyramid".to_string(), "pyramids".to_string()],
"pyramids".to_string()], "o7 I can handle pyramids".to_string(),
"o7 I can handle pyramids".to_string()); );
custom_mod.load_listener(create_pyramid_detector()); custom_mod.load_listener(create_pyramid_detector());
custom_mod custom_mod
} }
fn create_pyramid_detector() -> Listener { fn create_pyramid_detector() -> Listener {
/* 1. Create a new blank Listener */
let mut listener = Listener::new();
/* 1. Create a new blank Listener */ /* 2. Define an async trigger condition callback */
let mut listener = Listener::new(); async fn condition01(bot: Arc<Bot>, message: ServerMessage) -> bool {
if let ServerMessage::Privmsg(msg) = message {
/* 2. Define an async trigger condition callback */ if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await
async fn condition01(bot:Arc<Bot>,message:ServerMessage) -> bool { && get_pyramid_size(msg.channel_login) > 3
if let ServerMessage::Privmsg(msg) = message { {
if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await && get_pyramid_size(msg.channel_login) > 3 { return true;
return true;
}
} }
false
} }
false
}
/* 3. Set a trigger condition function for listener */ /* 3. Set a trigger condition function for listener */
listener.set_trigger_cond_async(listener_condition_async(condition01)); listener.set_trigger_cond_async(listener_condition_async(condition01));
/* 4. Define an async fn callback execution */
/* 4. Define an async fn callback execution */ async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { if let ServerMessage::Privmsg(msg) = message {
if let ServerMessage::Privmsg(msg) = message { dbg!("enter pyramid listener execution - after pyramid complete");
dbg!("enter pyramid listener execution - after pyramid complete"); // if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await {
// if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await {
// let _ = bot.chat.lock().await. // let _ = bot.chat.lock().await.
dbg!("> get start pattern"); dbg!("> get start pattern");
let pattern = get_start_pattern(msg.channel_login.clone()); let pattern = get_start_pattern(msg.channel_login.clone());
let mut outmsg ; let mut outmsg;
/* Prefer emote before pattern in case pattern is command */ /* Prefer emote before pattern in case pattern is command */
if pattern.len() < 50 { if pattern.len() < 50 {
outmsg = format!("Clap {}",pattern); outmsg = format!("Clap {}", pattern);
} else { } else {
outmsg = "Clap".to_string(); outmsg = "Clap".to_string();
}
dbg!(get_pyramid_size(msg.channel_login.clone()));
if get_pyramid_size(msg.channel_login.clone()) < 4 {
outmsg = format!("{} annytfMagniGlass",outmsg);
}
dbg!("> start pattern :",pattern);
dbg!("> say_in_reply_to completed :",outmsg.clone());
let _ = bot.chat.lock().await.say_in_reply_to(&msg, outmsg).await ;
dbg!("> set pyramid started - false");
set_pyramid_started(msg.channel_login.clone(),false);
return Result::Ok("Success".to_string()) ;
// }
} }
Result::Err("Not Valid message type".to_string())
dbg!(get_pyramid_size(msg.channel_login.clone()));
if get_pyramid_size(msg.channel_login.clone()) < 4 {
outmsg = format!("{} annytfMagniGlass", outmsg);
}
dbg!("> start pattern :", pattern);
dbg!("> say_in_reply_to completed :", outmsg.clone());
let _ = bot.chat.lock().await.say_in_reply_to(&msg, outmsg).await;
dbg!("> set pyramid started - false");
set_pyramid_started(msg.channel_login.clone(), false);
return Result::Ok("Success".to_string());
// }
} }
Result::Err("Not Valid message type".to_string())
/* 5. Set and Store the execution body using `execution_async()` */ }
listener.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b))));
listener /* 5. Set and Store the execution body using `execution_async()` */
listener.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b))));
listener
} }
/// detect pyramid based on latest message and channel /// detect pyramid based on latest message and channel
/// ///
/// ///
async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { async fn detect_pyramid_complete_ok(_bot: Arc<Bot>, msg: PrivmsgMessage) -> bool {
dbg!("enter detect_pyramid_complete()"); dbg!("enter detect_pyramid_complete()");
let msgtext = msg.message_text.replace("󠀀","").replace("\u{e0000}","").trim().to_string(); let msgtext = msg
.message_text
.replace("󠀀", "")
.replace("\u{e0000}", "")
.trim()
.to_string();
let msgchannel = msg.channel_login; let msgchannel = msg.channel_login;
let msgchatter = msg.sender.login; let msgchatter = msg.sender.login;
// 1. Check if Pyramid started in chat > and recognize pyramid started // 1. Check if Pyramid started in chat > and recognize pyramid started
if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) { if !is_pyramid_started(msgchannel.clone())
& check_start_pyramid(msgchannel.clone(), msgtext.clone())
{
dbg!("> set pyramid started - true"); dbg!("> set pyramid started - true");
set_pyramid_started(msgchannel.clone(),true); set_pyramid_started(msgchannel.clone(), true);
push_to_compare(msgchannel.clone(),msgchatter.clone(),get_start_pattern(msgchannel.clone())); push_to_compare(
msgchannel.clone(),
msgchatter.clone(),
get_start_pattern(msgchannel.clone()),
);
} }
if is_pyramid_started(msgchannel.clone()) { if is_pyramid_started(msgchannel.clone()) {
push_to_compare(msgchannel.clone(),msgchatter.clone(),msgtext.clone()); push_to_compare(msgchannel.clone(), msgchatter.clone(), msgtext.clone());
} }
// 2a. If Pyramid Not Started, Assume message is a potential start pattern // 2a. If Pyramid Not Started, Assume message is a potential start pattern
if !is_pyramid_started(msgchannel.clone()) { if !is_pyramid_started(msgchannel.clone()) {
set_start_pattern(msgchannel.clone(),msgtext.clone()); set_start_pattern(msgchannel.clone(), msgtext.clone());
} }
// 2b. If Pyramid is Started, and the latest message is the pattern, check for // 2b. If Pyramid is Started, and the latest message is the pattern, check for
// symmetry to determine pyramid // symmetry to determine pyramid
if is_pyramid_started(msgchannel.clone()) && msgtext.clone() == get_start_pattern(msgchannel.clone()) { if is_pyramid_started(msgchannel.clone())
&& msgtext.clone() == get_start_pattern(msgchannel.clone())
{
if symmetry_ok(msgchannel.clone()) { if symmetry_ok(msgchannel.clone()) {
return true; return true;
} else { } else {
dbg!("> set pyramid started - false"); dbg!("> set pyramid started - false");
set_pyramid_started(msgchannel,false); set_pyramid_started(msgchannel, false);
return false ; return false;
} }
} }
// 2c. if Pyramid is strted but latest message does not ontain pattern // 2c. if Pyramid is strted but latest message does not ontain pattern
if is_pyramid_started(msgchannel.clone()) && !msgtext.clone().contains( get_start_pattern(msgchannel.clone()).as_str()) { if is_pyramid_started(msgchannel.clone())
&& !msgtext
.clone()
.contains(get_start_pattern(msgchannel.clone()).as_str())
{
dbg!("> set pyramid started - false"); dbg!("> set pyramid started - false");
set_pyramid_started(msgchannel,false); set_pyramid_started(msgchannel, false);
return false ; return false;
} else { } else {
return false; return false;
}; };
} }
lazy_static! {
lazy_static!{
/// Message Compare stack per channel (channel:String,msgstack:Vec<(chatter:String,message:String)>) /// Message Compare stack per channel (channel:String,msgstack:Vec<(chatter:String,message:String)>)
pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>> = Mutex::new(vec![]); pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>> = Mutex::new(vec![]);
#[derive(Debug)] #[derive(Debug)]
@ -173,35 +178,34 @@ lazy_static!{
pub static ref START_PATTERNS_PER_CHNL: Mutex<Vec<(String,Mutex<String>)>> = Mutex::new(vec![]); pub static ref START_PATTERNS_PER_CHNL: Mutex<Vec<(String,Mutex<String>)>> = Mutex::new(vec![]);
/// Pyramid sze per channel (channel:String,started:bool) /// Pyramid sze per channel (channel:String,started:bool)
pub static ref PYRAMID_SIZE_PER_CHNL: Mutex<Vec<(String,Mutex<i32>)>> = Mutex::new(vec![]); pub static ref PYRAMID_SIZE_PER_CHNL: Mutex<Vec<(String,Mutex<i32>)>> = Mutex::new(vec![]);
/// temp message stack checker /// temp message stack checker
pub static ref TEMP_MSG_STACK: Mutex<Vec<String>> = Mutex::new(vec![]); pub static ref TEMP_MSG_STACK: Mutex<Vec<String>> = Mutex::new(vec![]);
/// interruptor targets - (channel:String,chatters:Vec<String>>) /// interruptor targets - (channel:String,chatters:Vec<String>>)
pub static ref INTERRUPT_TRG_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<String>>)>> = Mutex::new(vec![]); pub static ref INTERRUPT_TRG_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<String>>)>> = Mutex::new(vec![]);
} }
fn read_top_of_compare(channel:String) -> Option<(String,String)> { fn read_top_of_compare(channel: String) -> Option<(String, String)> {
let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
for rec in comp_perchnl.iter() { for rec in comp_perchnl.iter() {
if rec.0 == channel { if rec.0 == channel {
let msg_stack = rec.1.lock().unwrap(); let msg_stack = rec.1.lock().unwrap();
return msg_stack.last().cloned(); return msg_stack.last().cloned();
} }
} }
None None
} }
fn pop_top_of_compare(channel:String) -> Option<(String,String)> { fn pop_top_of_compare(channel: String) -> Option<(String, String)> {
let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
for rec in comp_perchnl.iter() { for rec in comp_perchnl.iter() {
if rec.0 == channel { if rec.0 == channel {
let mut msg_stack = rec.1.lock().unwrap(); let mut msg_stack = rec.1.lock().unwrap();
let popped = msg_stack.pop(); let popped = msg_stack.pop();
return popped; return popped;
} }
@ -209,7 +213,7 @@ fn pop_top_of_compare(channel:String) -> Option<(String,String)> {
None None
} }
fn set_pyramid_started(channel:String,started:bool) { fn set_pyramid_started(channel: String, started: bool) {
let mut start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap(); let mut start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap();
let mut found = false; let mut found = false;
for rec in start_perchnl.iter() { for rec in start_perchnl.iter() {
@ -217,14 +221,14 @@ fn set_pyramid_started(channel:String,started:bool) {
found = true; found = true;
let mut rec_started = rec.1.lock().unwrap(); let mut rec_started = rec.1.lock().unwrap();
*rec_started = started; *rec_started = started;
} }
} }
if !found { if !found {
start_perchnl.push((channel,Mutex::new(started))); start_perchnl.push((channel, Mutex::new(started)));
} }
} }
fn is_pyramid_started(channel:String) -> bool { fn is_pyramid_started(channel: String) -> bool {
let start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap(); let start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap();
for rec in start_perchnl.iter() { for rec in start_perchnl.iter() {
if rec.0 == channel { if rec.0 == channel {
@ -235,42 +239,37 @@ fn is_pyramid_started(channel:String) -> bool {
false false
} }
fn set_start_pattern(channel:String,pattern:String) { fn set_start_pattern(channel: String, pattern: String) {
let mut start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap(); let mut start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap();
let mut found = false; let mut found = false;
for rec in start_patterns.iter() { for rec in start_patterns.iter() {
if rec.0 == channel { if rec.0 == channel {
found = true; found = true;
let mut patternlock = rec.1.lock().unwrap(); let mut patternlock = rec.1.lock().unwrap();
*patternlock = pattern.clone(); *patternlock = pattern.clone();
} }
}
}
if !found { if !found {
start_patterns.push((channel.clone(),Mutex::new(pattern.clone()))); start_patterns.push((channel.clone(), Mutex::new(pattern.clone())));
} }
} }
fn get_start_pattern(channel: String) -> String {
fn get_start_pattern(channel:String) -> String {
let start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap(); let start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap();
for rec in start_patterns.iter() { for rec in start_patterns.iter() {
if rec.0 == channel { if rec.0 == channel {
let patternlock = rec.1.lock().unwrap(); let patternlock = rec.1.lock().unwrap();
return patternlock.clone(); return patternlock.clone();
} }
} }
return "".to_string(); return "".to_string();
} }
/// pushes message to compare stack /// pushes message to compare stack
fn push_to_compare(channel:String,chatter:String,message:String) { fn push_to_compare(channel: String, chatter: String, message: String) {
let mut comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); let mut comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
let mut found = false; let mut found = false;
@ -278,20 +277,23 @@ fn push_to_compare(channel:String,chatter:String,message:String) {
if rec.0 == channel { if rec.0 == channel {
found = true; found = true;
let mut msg_stack = rec.1.lock().unwrap(); let mut msg_stack = rec.1.lock().unwrap();
msg_stack.push((chatter.clone(),message.clone())); msg_stack.push((chatter.clone(), message.clone()));
// dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last()); // dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last());
} }
} }
if !found { if !found {
comp_perchnl.push((channel,Mutex::new(vec![(chatter,message)]))); comp_perchnl.push((channel, Mutex::new(vec![(chatter, message)])));
} }
} }
/// checks latest and next latest messages for potential start /// checks latest and next latest messages for potential start
fn check_start_pyramid(channel:String,msgtext: String) -> bool { fn check_start_pyramid(channel: String, msgtext: String) -> bool {
msgtext == format!("{} {}",get_start_pattern(channel.clone()),get_start_pattern(channel.clone())) msgtext
== format!(
"{} {}",
get_start_pattern(channel.clone()),
get_start_pattern(channel.clone())
)
// msgtext == format!("{} {} {}", // msgtext == format!("{} {} {}",
// get_start_pattern(channel.clone()), // get_start_pattern(channel.clone()),
// get_start_pattern(channel.clone()), // get_start_pattern(channel.clone()),
@ -299,60 +301,80 @@ fn check_start_pyramid(channel:String,msgtext: String) -> bool {
// ) // )
} }
/// pops the compare stack to determine symmetry /// pops the compare stack to determine symmetry
fn symmetry_ok(channel:String) -> bool { fn symmetry_ok(channel: String) -> bool {
let mut temp_stack = TEMP_MSG_STACK.lock().unwrap(); let mut temp_stack = TEMP_MSG_STACK.lock().unwrap();
let mut checking_started = false; let mut checking_started = false;
if !(read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone())) { if !(read_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1
== get_start_pattern(channel.clone()))
{
return false; return false;
} }
let mut pyramid_size = 0; let mut pyramid_size = 0;
loop { loop {
if !checking_started
if !checking_started && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone()) { && read_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1
== get_start_pattern(channel.clone())
{
checking_started = true; checking_started = true;
} }
if temp_stack.last().is_none() || read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() > temp_stack.last().unwrap_or(&"".to_string()).len() { if temp_stack.last().is_none()
temp_stack.push(pop_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1); || read_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1
.len()
> temp_stack.last().unwrap_or(&"".to_string()).len()
{
temp_stack.push(
pop_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1,
);
pyramid_size += 1; pyramid_size += 1;
} else if temp_stack.last().is_some()
} else if temp_stack.last().is_some() && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() < temp_stack.last().unwrap_or(&"".to_string()).len() { && read_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1
.len()
< temp_stack.last().unwrap_or(&"".to_string()).len()
{
temp_stack.pop(); temp_stack.pop();
if temp_stack.last().unwrap_or(&"".to_string()).clone() == read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 { if temp_stack.last().unwrap_or(&"".to_string()).clone()
== read_top_of_compare(channel.clone())
.unwrap_or(("".to_string(), "".to_string()))
.1
{
temp_stack.pop(); temp_stack.pop();
continue; continue;
} else { } else {
set_pyramid_size(channel.clone(), 0); set_pyramid_size(channel.clone(), 0);
temp_stack.clear(); temp_stack.clear();
return false; return false;
} }
} else {
} else {
set_pyramid_size(channel.clone(), 0); set_pyramid_size(channel.clone(), 0);
return false; return false;
} }
if checking_started && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone()) { if checking_started
&& read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone())
{
/* leave pyramid size set for exection */ /* leave pyramid size set for exection */
set_pyramid_size(channel.clone(), pyramid_size*2-1); set_pyramid_size(channel.clone(), pyramid_size * 2 - 1);
temp_stack.clear(); temp_stack.clear();
return true; return true;
} }
} }
} }
fn set_pyramid_size(channel: String, size: i32) {
fn set_pyramid_size(channel:String,size:i32) {
let mut size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap(); let mut size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
let mut found = false; let mut found = false;
for rec in size_perchnl.iter() { for rec in size_perchnl.iter() {
@ -360,14 +382,14 @@ fn set_pyramid_size(channel:String,size:i32) {
found = true; found = true;
let mut rec_started = rec.1.lock().unwrap(); let mut rec_started = rec.1.lock().unwrap();
*rec_started = size; *rec_started = size;
} }
} }
if !found { if !found {
size_perchnl.push((channel,Mutex::new(size))); size_perchnl.push((channel, Mutex::new(size)));
} }
} }
fn get_pyramid_size(channel:String) -> i32 { fn get_pyramid_size(channel: String) -> i32 {
let size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap(); let size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
for rec in size_perchnl.iter() { for rec in size_perchnl.iter() {
if rec.0 == channel { if rec.0 == channel {
@ -379,88 +401,85 @@ fn get_pyramid_size(channel:String) -> i32 {
} }
/// #todo /// #todo
/// ///
/// pyramid interruptor /// pyramid interruptor
/// ///
/// pick chatters that will be interrupted if they solo build /// pick chatters that will be interrupted if they solo build
/// ///
/// takes in arguments as chatters /// takes in arguments as chatters
/// ///
/// chatters are then interrupted for a random duration under 15m /// chatters are then interrupted for a random duration under 15m
/// ///
/// if a duration is given, take that duration eg 15m , 25m /// if a duration is given, take that duration eg 15m , 25m
/// ///
/// ///
fn _create_interruptor_cmd() -> Command { fn _create_interruptor_cmd() -> Command {
let mut cmd = Command::new(vec![ let mut cmd = Command::new(
"no pyramid".to_string(), vec!["no pyramid".to_string(), "no pyramids".to_string()],
"no pyramids".to_string() "".to_string(),
], );
"".to_string());
/* 2. Define an async fn callback execution */ /* 2. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("test success")).await; let _ = bot
return Result::Ok("Success".to_string()) ; .chat
} .lock()
Result::Err("Not Valid message type".to_string()) .await
.say_in_reply_to(&msg, String::from("test success"))
.await;
return Result::Ok("Success".to_string());
} }
Result::Err("Not Valid message type".to_string())
}
/* 3. Set and Store the execution body using `execution_async()` */ /* 3. Set and Store the execution body using `execution_async()` */
cmd.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b)))); cmd.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b))));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */
cmd.set_admin_only(false); cmd.set_admin_only(false);
/* 5. optionally, set min badge*/
cmd.set_min_badge(Badge::Moderator);
/* 5. optionally, set min badge*/
cmd.set_min_badge(Badge::Moderator);
cmd cmd
} }
/// #todo /// #todo
fn _create_interruptor_module(channel:String) -> Module { fn _create_interruptor_module(channel: String) -> Module {
/* 1. Create a new module */ /* 1. Create a new module */
let modname = format!("interruptor {}",channel); let modname = format!("interruptor {}", channel);
let mut custom_mod = Module::new( let mut custom_mod = Module::new(vec![modname], "".to_string());
vec![modname],
"".to_string());
/* 2. Load the cmd into a new module */ /* 2. Load the cmd into a new module */
custom_mod.load_listener(_create_interruptor_listener()); custom_mod.load_listener(_create_interruptor_listener());
custom_mod custom_mod
} }
/// #todo /// #todo
fn _create_interruptor_listener() -> Listener { fn _create_interruptor_listener() -> Listener {
/* 2a. Create a new blank Listener */ /* 2a. Create a new blank Listener */
let mut listener = Listener::new(); let mut listener = Listener::new();
/* 2b. Set a trigger condition function for listener */ /* 2b. Set a trigger condition function for listener */
listener.set_trigger_cond_fn( listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
|_:Arc<Bot>,_:ServerMessage| true
);
/* 2c. Define an async fn callback execution */ /* 2c. Define an async fn callback execution */
async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
dbg!(message); /* outputs message to debug */ dbg!(message); /* outputs message to debug */
Result::Ok("Success".to_string()) Result::Ok("Success".to_string())
} }
/* 2d. Set and Store the execution body using `execution_async()` */ /* 2d. Set and Store the execution body using `execution_async()` */
listener.set_exec_fn(execution_async(execbody)); listener.set_exec_fn(execution_async(execbody));
listener listener
} }
/// #todo /// #todo
/// ///
/// Returns Some(chatter) if the pyramid in progress is being built by a solo /// Returns Some(chatter) if the pyramid in progress is being built by a solo
fn _solo_building(_channel:String) -> Option<String> { fn _solo_building(_channel: String) -> Option<String> {
None None
} }

View file

@ -1,32 +1,32 @@
//! `forcebot_core` library for `forcebot-rs-v2` Twitch chat bot //! `forcebot_core` library for `forcebot-rs-v2` Twitch chat bot
//! //!
//! Customize by adding additional bot objects //! Customize by adding additional bot objects
//! //!
//! # New Bot //! # New Bot
//! //!
//! Uses Env defined variables to create and run the bot //! Uses Env defined variables to create and run the bot
//! //!
//! ```rust //! ```rust
//! use forcebot_core::Bot; //! use forcebot_core::Bot;
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn main() { //! pub async fn main() {
//! //!
//! /* 1. Create the bot using env */ //! /* 1. Create the bot using env */
//! let bot = Bot::new(); //! let bot = Bot::new();
//! //!
//! /* 2. Run the bot */ //! /* 2. Run the bot */
//! bot.run().await; //! bot.run().await;
//! //!
//! } //! }
//! //!
//! ``` //! ```
//! //!
//! //!
//! # Customize with Modules //! # Customize with Modules
//! //!
//! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands //! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands
//! //!
//! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot //! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
//! //!
//! ```rust //! ```rust
@ -48,16 +48,16 @@
//! } //! }
//! ``` //! ```
//! //!
//! //!
//! # Create your own Custom Modules //! # Create your own Custom Modules
//! //!
//! Create a custom `Module` by : //! Create a custom `Module` by :
//! //!
//! 1. Defining Functions that create the Custom Bot Objects (eg `Command`) //! 1. Defining Functions that create the Custom Bot Objects (eg `Command`)
//! //!
//! 2. Define a function that creates a `Module` with the Custom Bot Objects loaded //! 2. Define a function that creates a `Module` with the Custom Bot Objects loaded
//! //!
//! //!
//! ```rust //! ```rust
//! use forcebot_core::Bot; //! use forcebot_core::Bot;
//! //!
@ -86,7 +86,7 @@
//! pub fn new() -> Module { //! pub fn new() -> Module {
//! /* 1. Create a new module */ //! /* 1. Create a new module */
//! let mut custom_mod = Module::new( //! let mut custom_mod = Module::new(
//! vec!["test".to_string()], //! vec!["test".to_string()],
//! "".to_string()); //! "".to_string());
//! //!
//! /* 2. Load the cmd into a new module */ //! /* 2. Load the cmd into a new module */
@ -96,7 +96,7 @@
//! //!
//! } //! }
//! //!
//! /// Command definition //! /// Command definition
//! pub fn cmd_test() -> Command { //! pub fn cmd_test() -> Command {
//! /* 1. Create a new cmd */ //! /* 1. Create a new cmd */
//! let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); //! let mut cmd = Command::new(vec!["test".to_string()],"".to_string());
@ -107,7 +107,7 @@
//! let _= bot.client.say_in_reply_to( //! let _= bot.client.say_in_reply_to(
//! &msg, "test return".to_string()).await; //! &msg, "test return".to_string()).await;
//! } //! }
//! Result::Err("Not Valid message type".to_string()) //! Result::Err("Not Valid message type".to_string())
//! } //! }
//! //!
//! /* 3. Set Command flags */ //! /* 3. Set Command flags */
@ -119,99 +119,99 @@
//! } //! }
//! } //! }
//! //!
//! //!
//! ``` //! ```
//! //!
//! # Simple Debug Listener //! # Simple Debug Listener
//! Bot with a simple listener that listens for all messages and prints in output //! Bot with a simple listener that listens for all messages and prints in output
//! //!
//! ```rust //! ```rust
//! use std::sync::Arc; //! use std::sync::Arc;
//! //!
//! use forcebot_core::{execution_async, Bot, Listener}; //! use forcebot_core::{execution_async, Bot, Listener};
//! use twitch_irc::message::ServerMessage; //! use twitch_irc::message::ServerMessage;
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn main() { //! pub async fn main() {
//! //!
//! /* 1. Create the bot using env */ //! /* 1. Create the bot using env */
//! let mut bot = Bot::new(); //! let mut bot = Bot::new();
//! //!
//! /* 2a. Create a new blank Listener */ //! /* 2a. Create a new blank Listener */
//! let mut listener = Listener::new(); //! let mut listener = Listener::new();
//! //!
//! /* 2b. Set a trigger condition function for listener */ //! /* 2b. Set a trigger condition function for listener */
//! listener.set_trigger_cond_fn( //! listener.set_trigger_cond_fn(
//! |_:Arc<Bot>,_:ServerMessage| true //! |_:Arc<Bot>,_:ServerMessage| true
//! ); //! );
//! //!
//! /* 2c. Define an async fn callback execution */ //! /* 2c. Define an async fn callback execution */
//! async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { //! async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
//! dbg!(message); /* outputs message to debug */ //! dbg!(message); /* outputs message to debug */
//! Result::Ok("Success".to_string()) //! Result::Ok("Success".to_string())
//! } //! }
//! //!
//! /* 2d. Set and Store the execution body using `execution_async()` */ //! /* 2d. Set and Store the execution body using `execution_async()` */
//! listener.set_exec_fn(execution_async(execbody)); //! listener.set_exec_fn(execution_async(execbody));
//! //!
//! /* 3. Load the listener into the bot */ //! /* 3. Load the listener into the bot */
//! bot.load_listener(listener); //! bot.load_listener(listener);
//! //!
//! /* 4. Run the bot */ //! /* 4. Run the bot */
//! bot.run().await; //! bot.run().await;
//! //!
//! } //! }
//! //!
//! ``` //! ```
//! //!
//! # Moderator Reactor //! # Moderator Reactor
//! //!
//! ``` //! ```
//! //!
//! use std::sync::Arc; //! use std::sync::Arc;
//! //!
//! use forcebot_core::Bot; //! use forcebot_core::Bot;
//! use forcebot_core::execution_async; //! use forcebot_core::execution_async;
//! use forcebot_core::Listener; //! use forcebot_core::Listener;
//! use twitch_irc::message::ServerMessage; //! use twitch_irc::message::ServerMessage;
//! //!
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn main() { //! pub async fn main() {
//! //!
//! /* Create the bot using env */ //! /* Create the bot using env */
//! let mut bot = Bot::new(); //! let mut bot = Bot::new();
//! //!
//! /* 1. Create a new blank Listener */ //! /* 1. Create a new blank Listener */
//! let mut listener = Listener::new(); //! let mut listener = Listener::new();
//! //!
//! /* 2. Set a trigger condition function for listener */ //! /* 2. Set a trigger condition function for listener */
//! //!
//! listener.set_trigger_cond_fn( //! listener.set_trigger_cond_fn(
//! |_:Arc<Bot>,message:ServerMessage| //! |_:Arc<Bot>,message:ServerMessage|
//! if let ServerMessage::Privmsg(msg) = message { //! if let ServerMessage::Privmsg(msg) = message {
//! for badge in msg.badges { //! for badge in msg.badges {
//! if matches!(badge, x if x.name == "moderator") { //! if matches!(badge, x if x.name == "moderator") {
//! // dbg!("moderator found"); //! // dbg!("moderator found");
//! return true; //! return true;
//! } //! }
//! } //! }
//! false //! false
//! } else { false } //! } else { false }
//! ); //! );
//! //!
//! /* 3. Define an async fn callback execution */ //! /* 3. Define an async fn callback execution */
//! async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { //! async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
//! if let ServerMessage::Privmsg(msg) = message { //! if let ServerMessage::Privmsg(msg) = message {
//! let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ; //! let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
//! return Result::Ok("Success".to_string()) ; //! return Result::Ok("Success".to_string()) ;
//! } //! }
//! Result::Err("Not Valid message type".to_string()) //! Result::Err("Not Valid message type".to_string())
//! } //! }
//! //!
//! /* 4. Set and Store the execution body using `execution_async()` */ //! /* 4. Set and Store the execution body using `execution_async()` */
//! listener.set_exec_fn(execution_async(execbody)); //! listener.set_exec_fn(execution_async(execbody));
//! //!
//! /* 5. Load the listener into the bot */ //! /* 5. Load the listener into the bot */
//! bot.load_listener(listener); //! bot.load_listener(listener);
//! //!
@ -220,17 +220,15 @@
//! //!
//! } //! }
pub mod botcore; pub mod botcore;
pub mod custom_mods; pub mod custom_mods;
pub use botcore::bot::Bot; pub use botcore::bot::Bot;
pub use botcore::bot_objects::execution_async;
pub use botcore::bot_objects::command_condition_async; pub use botcore::bot_objects::command_condition_async;
pub use botcore::bot_objects::listener_condition_async; pub use botcore::bot_objects::execution_async;
pub use botcore::bot_objects::listener::Listener; pub use botcore::bot_objects::listener::Listener;
pub use botcore::bot_objects::listener_condition_async;
// pub use crate::botcore::bot_objects::command::Command; // pub use crate::botcore::bot_objects::command::Command;
pub use botcore::bot_objects::command::Command; pub use botcore::bot_objects::command::Command;
pub use botcore::modules::Module;
pub use botcore::bot_objects::Badge; pub use botcore::bot_objects::Badge;
pub use botcore::modules; pub use botcore::modules;
pub use botcore::modules::Module;

View file

@ -1,27 +1,25 @@
//! Simple bot with a custom listeners that listens for moderators and respond to the moderator //! Simple bot with a custom listeners that listens for moderators and respond to the moderator
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use std::sync::Arc; use std::sync::Arc;
use forcebot_core::Bot;
use forcebot_core::execution_async; use forcebot_core::execution_async;
use forcebot_core::Bot;
use forcebot_core::Listener; use forcebot_core::Listener;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* Create the bot using env */ /* Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
@ -30,26 +28,32 @@ pub async fn main() {
/* 2. Set a trigger condition function for listener */ /* 2. Set a trigger condition function for listener */
listener.set_trigger_cond_fn( listener.set_trigger_cond_fn(|_: Arc<Bot>, message: ServerMessage| {
|_:Arc<Bot>,message:ServerMessage| if let ServerMessage::Privmsg(msg) = message {
if let ServerMessage::Privmsg(msg) = message { for badge in msg.badges {
for badge in msg.badges { if matches!(badge, x if x.name == "moderator") {
if matches!(badge, x if x.name == "moderator") { // dbg!("moderator found");
// dbg!("moderator found"); return true;
return true; }
} }
} false
false } else {
} else { false } false
); }
});
/* 3. Define an async fn callback execution */ /* 3. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _ = bot.chat.lock().await.say_in_reply_to(&msg, "pepeKneel".to_string()).await ; let _ = bot
return Result::Ok("Success".to_string()) ; .chat
.lock()
.await
.say_in_reply_to(&msg, "pepeKneel".to_string())
.await;
return Result::Ok("Success".to_string());
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 4. Set and Store the execution body using `execution_async()` */ /* 4. Set and Store the execution body using `execution_async()` */
@ -60,5 +64,4 @@ pub async fn main() {
/* Run the bot */ /* Run the bot */
bot.run().await; bot.run().await;
} }

View file

@ -1,12 +1,12 @@
//! Example simple Binary crate that creates & runs bot based on `.env` //! Example simple Binary crate that creates & runs bot based on `.env`
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
@ -14,11 +14,9 @@ use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* 1. Create the bot using env */ /* 1. Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
/* 2. Run the bot */ /* 2. Run the bot */
bot.run().await; bot.run().await;
} }

View file

@ -1,43 +1,46 @@
//! Bot with custom example commands that responds to caller if allowed //! Bot with custom example commands that responds to caller if allowed
//! //!
//! Commands that are passed a blank prefix will use the bot prefix //! Commands that are passed a blank prefix will use the bot prefix
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use std::sync::Arc; use std::sync::Arc;
use forcebot_core::execution_async;
use forcebot_core::Badge; use forcebot_core::Badge;
use forcebot_core::Bot; use forcebot_core::Bot;
use forcebot_core::execution_async;
use forcebot_core::Command; use forcebot_core::Command;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* Create the bot using env */ /* Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
/* 1. Create a new blank cmd */ /* 1. Create a new blank cmd */
let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
/* 2. Define an async fn callback execution */ /* 2. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("test success")).await; let _ = bot
return Result::Ok("Success".to_string()) ; .chat
.lock()
.await
.say_in_reply_to(&msg, String::from("test success"))
.await;
return Result::Ok("Success".to_string());
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set and Store the execution body using `execution_async()` */ /* 3. Set and Store the execution body using `execution_async()` */
@ -54,5 +57,4 @@ pub async fn main() {
/* Run the bot */ /* Run the bot */
bot.run().await; bot.run().await;
} }

View file

@ -1,12 +1,12 @@
//! Example simple Binary crate that creates & runs bot based on `.env` //! Example simple Binary crate that creates & runs bot based on `.env`
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
@ -17,7 +17,6 @@ use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* 1. Create the bot using env */ /* 1. Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
@ -25,14 +24,12 @@ pub async fn main() {
let mut listener = Listener::new(); let mut listener = Listener::new();
/* 2b. Set a trigger condition function for listener */ /* 2b. Set a trigger condition function for listener */
listener.set_trigger_cond_fn( listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true);
|_:Arc<Bot>,_:ServerMessage| true
);
/* 2c. Define an async fn callback execution */ /* 2c. Define an async fn callback execution */
async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
dbg!(message); /* outputs message to debug */ dbg!(message); /* outputs message to debug */
Result::Ok("Success".to_string()) Result::Ok("Success".to_string())
} }
/* 2d. Set and Store the execution body using `execution_async()` */ /* 2d. Set and Store the execution body using `execution_async()` */
@ -43,5 +40,4 @@ pub async fn main() {
/* 4. Run the bot */ /* 4. Run the bot */
bot.run().await; bot.run().await;
} }

View file

@ -1,19 +1,19 @@
//! Simple Module with a Command //! Simple Module with a Command
//! //!
//! Adding objects through packages provides controls , //! Adding objects through packages provides controls ,
//! such as moderators, and brodcasters can disable or enable mods //! such as moderators, and brodcasters can disable or enable mods
//! //!
//! Here, moderators or above can enable or disable the `test` //! Here, moderators or above can enable or disable the `test`
//! module with the command `<prefix> disable test` //! module with the command `<prefix> disable test`
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
//! - login_name //! - login_name
//! - access_token //! - access_token
//! - bot_channels //! - bot_channels
//! - prefix //! - prefix
//! - bot_admins //! - bot_admins
//! //!
//! Bot access tokens be generated here - //! Bot access tokens be generated here -
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
@ -21,7 +21,6 @@ use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
/* Create the bot using env */ /* Create the bot using env */
let bot = Bot::new().await; let bot = Bot::new().await;
@ -30,43 +29,41 @@ pub async fn main() {
/* Run the bot */ /* Run the bot */
bot.run().await; bot.run().await;
} }
pub mod custom_mod { pub mod custom_mod {
use std::sync::Arc; use std::sync::Arc;
use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use forcebot_core::{execution_async, Badge, Bot, Command, Module};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
/// Module definition with a loaded command /// Module definition with a loaded command
pub fn new() -> Module { pub fn new() -> Module {
/* 1. Create a new module */ /* 1. Create a new module */
let mut custom_mod = Module::new( let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string());
vec!["test".to_string()],
"".to_string());
/* 2. Load the cmd into a new module */ /* 2. Load the cmd into a new module */
custom_mod.load_command(cmd_test()); custom_mod.load_command(cmd_test());
custom_mod custom_mod
} }
/// Command definition /// Command definition
pub fn cmd_test() -> Command { pub fn cmd_test() -> Command {
/* 1. Create a new cmd */ /* 1. Create a new cmd */
let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); let mut cmd = Command::new(vec!["test".to_string()], "".to_string());
/* 2. Define exec callback */ /* 2. Define exec callback */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> {
if let ServerMessage::Privmsg(msg) = message { if let ServerMessage::Privmsg(msg) = message {
let _= bot.chat.lock().await.say_in_reply_to( let _ = bot
&msg, "test return".to_string()).await; .chat
.lock()
.await
.say_in_reply_to(&msg, "test return".to_string())
.await;
} }
Result::Err("Not Valid message type".to_string()) Result::Err("Not Valid message type".to_string())
} }
/* 3. Set Command flags */ /* 3. Set Command flags */
@ -76,4 +73,4 @@ pub mod custom_mod {
cmd cmd
} }
} }