enh pyramid + chat module
This commit is contained in:
parent
5faf982485
commit
8eaa56dd0c
19 changed files with 455 additions and 176 deletions
forcebot_core
moderator_reactor/src
readme.mdsimple_command_bot/src
simple_module_example/src
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||
default-run = "fun_bot"
|
||||
|
||||
[dependencies]
|
||||
# async-recursion = "1.1.1" /* has issues when used */
|
||||
dotenv = "0.15.0"
|
||||
lazy_static = "1.5.0"
|
||||
tokio = { version = "1.33.0", features = ["full"] }
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
|
||||
//! - More Info - <https://dev.twitch.tv/docs/authentication>
|
||||
|
||||
// use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot};
|
||||
use forcebot_core::{custom_mods::{debug, guest_badge, pyramid, quiet}, Bot};
|
||||
use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot};
|
||||
|
||||
|
||||
|
||||
|
@ -31,12 +30,10 @@ pub async fn main() {
|
|||
|
||||
/* 1. Load the module into the bot */
|
||||
bot.load_module(funbot_objs::create_module()).await;
|
||||
|
||||
/* 2. Load Custom Modules */
|
||||
bot.load_module(guest_badge::create_module()).await;
|
||||
bot.load_module(pyramid::create_module()).await;
|
||||
bot.load_module(debug::create_module()).await;
|
||||
bot.load_module(quiet::create_module()).await;
|
||||
|
||||
|
||||
/* 3. Run the bot */
|
||||
bot.run().await;
|
||||
|
@ -69,7 +66,7 @@ pub mod funbot_objs {
|
|||
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.chat.lock().await.say_in_reply_to(
|
||||
&msg, "annytfYandere he's mine".to_string()).await;
|
||||
return Result::Ok("Success".to_string());
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
//! Example simple Binary crate that creates & runs bot based on `.env`
|
||||
//! Be sure the followig is defined in `.env`
|
||||
//! - login_name
|
||||
//! - access_token
|
||||
//! - bot_channels
|
||||
//! - prefix
|
||||
//! - bot_admins
|
||||
//!
|
||||
//! Bot access tokens be generated here -
|
||||
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
|
||||
//! - More Info - <https://dev.twitch.tv/docs/authentication>
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_core::{execution_async, Bot, Listener};
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 2a. Create a new blank Listener */
|
||||
let mut listener = Listener::new();
|
||||
|
||||
/* 2b. Set a trigger condition function for listener */
|
||||
listener.set_trigger_cond_fn(
|
||||
|_:Arc<Bot>,_:ServerMessage| true
|
||||
);
|
||||
|
||||
/* 2c. Define an async fn callback execution */
|
||||
async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
dbg!(message); /* outputs message to debug */
|
||||
Result::Ok("Success".to_string())
|
||||
}
|
||||
|
||||
/* 2d. Set and Store the execution body using `async_box()` */
|
||||
listener.set_exec_fn(execution_async(execbody));
|
||||
|
||||
/* 3. Load the listener into the bot */
|
||||
bot.load_listener(listener).await;
|
||||
|
||||
/* 4. Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
|
@ -63,7 +63,7 @@ pub mod custom_mod {
|
|||
/* 2. Define exec callback */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.chat.lock().await.say_in_reply_to(
|
||||
&msg, "test return".to_string()).await;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pub mod bot;
|
||||
pub mod bot_objects;
|
||||
pub mod modules;
|
||||
pub mod modules;
|
||||
pub mod built_in_mods;
|
||||
pub mod chat;
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
|
||||
// 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 std::{env, sync::{Arc, RwLock}, time::{Duration, Instant}};
|
||||
|
||||
// use crate::{Badge, Command, Listener, Module};
|
||||
use super::bot_objects::command::Command;
|
||||
use super::{bot_objects::command::Command, built_in_mods, chat::Chat};
|
||||
|
||||
use crate::botcore::bot_objects::Badge;
|
||||
use crate::botcore::{bot_objects::Badge, chat};
|
||||
use crate::botcore::bot_objects::listener::Listener;
|
||||
use super::super::botcore::modules::Module;
|
||||
// use super::
|
||||
|
@ -25,6 +26,8 @@ pub struct Bot
|
|||
incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>,
|
||||
/// outbound chat client msg stream
|
||||
pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>,
|
||||
/// *preferred* bot enforced outbound chat client msg stream
|
||||
pub chat : Mutex<Chat>,
|
||||
/// joined channels
|
||||
botchannels: Vec<String>,
|
||||
/// admin chatters
|
||||
|
@ -41,8 +44,8 @@ pub struct Bot
|
|||
chatter_guest_badges: Mutex<Vec<(String,String,Badge,Instant,Duration)>>,
|
||||
/// Message cache
|
||||
message_cache: Mutex<Vec<PrivmsgMessage>>,
|
||||
/// channel_quiet
|
||||
channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>,
|
||||
// /// channel_quiet
|
||||
// channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>,
|
||||
|
||||
}
|
||||
|
||||
|
@ -57,7 +60,8 @@ impl Bot
|
|||
/// - bot_channels
|
||||
/// - prefix
|
||||
/// - bot_admins
|
||||
pub async fn new() -> Bot {
|
||||
// #[async_recursion]
|
||||
pub async fn new() -> Arc<Bot> {
|
||||
|
||||
|
||||
|
||||
|
@ -82,7 +86,10 @@ impl Bot
|
|||
/// Creates a new `Bot` using bot information
|
||||
///
|
||||
/// Bot will join `botchannels` argument
|
||||
pub async fn new_from(bot_login_name:String,oauth_token:String,prefix:String,botchannels:Vec<String>) -> Bot {
|
||||
pub async fn new_from(bot_login_name:String,
|
||||
oauth_token:String,
|
||||
prefix:String,
|
||||
botchannels:Vec<String>) -> Arc<Bot> {
|
||||
|
||||
dotenv().ok();
|
||||
let bot_login_name = bot_login_name;
|
||||
|
@ -111,7 +118,8 @@ impl Bot
|
|||
let bot = Bot {
|
||||
prefix,
|
||||
incoming_msgs : Mutex::new(incoming_messages),
|
||||
client,
|
||||
client : client.clone(),
|
||||
chat : Mutex::new(Chat::new(client).await),
|
||||
botchannels : botchannels_all,
|
||||
listeners : Mutex::new(vec![]),
|
||||
commands : Mutex::new(vec![]),
|
||||
|
@ -120,31 +128,61 @@ impl Bot
|
|||
channel_module_status: RwLock::new(vec![]),
|
||||
chatter_guest_badges: 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 {
|
||||
// let mut bot1 = bot;
|
||||
|
||||
// bot1.chat = Some(Chat::new(client, bot1));
|
||||
|
||||
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;
|
||||
|
||||
bot
|
||||
|
||||
}
|
||||
|
||||
let bot = load_modules(bot).await;
|
||||
|
||||
|
||||
let bot = Arc::new(bot);
|
||||
|
||||
// let lock = bot.chat.lock().await;
|
||||
|
||||
// *lock = Some(Chat::new(chat, bot.clone()));
|
||||
|
||||
// let cht = Chat::new(chat).await;
|
||||
|
||||
// bot.chat.lock()
|
||||
|
||||
// lock.set_parent_bot(bot.clone());
|
||||
|
||||
println!("Joined - {:?}",bot.botchannels);
|
||||
|
||||
|
||||
bot.clone()
|
||||
}
|
||||
|
||||
/// Runs the bot
|
||||
pub async fn run(self) {
|
||||
pub async fn run(self:Arc<Self>) {
|
||||
|
||||
for chnl in &self.botchannels {
|
||||
self.client.join(chnl.to_owned()).unwrap();
|
||||
}
|
||||
|
||||
let bot = Arc::new(self);
|
||||
// let bot = Arc::new(self);
|
||||
let bot = self;
|
||||
|
||||
let join_handle = tokio::spawn(async move {
|
||||
|
||||
let a = bot.clone();
|
||||
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()) ;
|
||||
|
||||
let bot_listener_lock = bot.listeners.lock().await;
|
||||
for listener in bot_listener_lock.iter() {
|
||||
|
@ -429,39 +467,39 @@ impl Bot
|
|||
rslt
|
||||
}
|
||||
|
||||
/// Get the quiet status of a channel
|
||||
pub fn get_channel_quiet(&self,channel:String) -> bool {
|
||||
for a in self.channel_quiet_yn.read().unwrap().iter() {
|
||||
if a.0 == channel {
|
||||
return a.1.read().unwrap().clone();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// /// Get the quiet status of a channel
|
||||
// pub fn get_channel_quiet(&self,channel:String) -> bool {
|
||||
// for a in self.channel_quiet_yn.read().unwrap().iter() {
|
||||
// if a.0 == channel {
|
||||
// return a.1.read().unwrap().clone();
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/// Get the quiet status of a channel
|
||||
pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) {
|
||||
let mut found = false;
|
||||
// /// Get the quiet status of a channel
|
||||
// pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) {
|
||||
// let mut found = false;
|
||||
|
||||
let chnlquiet = self.channel_quiet_yn.read().unwrap();
|
||||
for rec in chnlquiet.iter() {
|
||||
if rec.0 == channel {
|
||||
found = true;
|
||||
let mut status = rec.1.write().unwrap();
|
||||
*status = quiet_on;
|
||||
drop(status);
|
||||
}
|
||||
}
|
||||
drop(chnlquiet);
|
||||
// let chnlquiet = self.channel_quiet_yn.read().unwrap();
|
||||
// for rec in chnlquiet.iter() {
|
||||
// if rec.0 == channel {
|
||||
// found = true;
|
||||
// let mut status = rec.1.write().unwrap();
|
||||
// *status = quiet_on;
|
||||
// drop(status);
|
||||
// }
|
||||
// }
|
||||
// drop(chnlquiet);
|
||||
|
||||
if !found {
|
||||
// dbg!("set chn quiet > !found channel quiet status");
|
||||
let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
|
||||
chnlquiet.push((channel,RwLock::new(quiet_on)));
|
||||
drop(chnlquiet);
|
||||
}
|
||||
// if !found {
|
||||
// // dbg!("set chn quiet > !found channel quiet status");
|
||||
// let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
|
||||
// chnlquiet.push((channel,RwLock::new(quiet_on)));
|
||||
// drop(chnlquiet);
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ pub enum Badge {
|
|||
}
|
||||
|
||||
|
||||
|
||||
pub type ExecBody = Box<
|
||||
dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = Result<String,String>> + Send>> + Send + Sync,
|
||||
>;
|
||||
|
@ -107,14 +108,6 @@ pub mod built_in_objects {
|
|||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
use super::{execution_async,command::Command,Bot,Badge,super::modules::Status};
|
||||
|
||||
// use super::execution_async;
|
||||
// use super::command::Command;
|
||||
// use super::Bot;
|
||||
// use super::Badge;
|
||||
// use super::super::modules::Status;
|
||||
// ::{execution_async, modules::Status, Badge, Bot, Command};
|
||||
|
||||
|
||||
|
||||
/// create a vector of command build in objects
|
||||
|
@ -148,7 +141,7 @@ pub mod built_in_objects {
|
|||
}
|
||||
}
|
||||
if action_taken {
|
||||
let _ = bot.client.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())
|
||||
|
@ -199,7 +192,7 @@ pub mod built_in_objects {
|
|||
bot_message = bot_message[..250].to_string();
|
||||
}
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg,
|
||||
let _ = bot.chat.lock().await.say_in_reply_to(&msg,
|
||||
format!("Enabled! {}", bot_message)
|
||||
).await ;
|
||||
|
||||
|
@ -257,7 +250,7 @@ pub mod built_in_objects {
|
|||
msg.channel_login.clone(),
|
||||
Badge::Moderator, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await;
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg,
|
||||
let _ = bot.chat.lock().await.say_in_reply_to(&msg,
|
||||
format!("Temp {:?} issued for {:?} minutes",Badge::Moderator,TEMP_BADGE_DUR_MIN)
|
||||
).await ;
|
||||
}
|
||||
|
@ -279,8 +272,8 @@ pub mod built_in_objects {
|
|||
msg.channel_login.clone(),
|
||||
Badge::Vip, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await;
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg,
|
||||
format!("Temp {:?} issued for {:?} minutes",Badge::Vip,TEMP_BADGE_DUR_MIN)
|
||||
let _ = bot.chat.lock().await.say_in_reply_to(&msg,
|
||||
format!("Temp {:?} issued for {:?} minutes for the bot admin",Badge::Vip,TEMP_BADGE_DUR_MIN)
|
||||
).await ;
|
||||
}
|
||||
}
|
||||
|
@ -300,14 +293,14 @@ pub mod built_in_objects {
|
|||
msg.channel_login.clone(),
|
||||
Badge::Broadcaster, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await;
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg,
|
||||
format!("Temp {:?} issued for {:?} minutes",Badge::Broadcaster,TEMP_BADGE_DUR_MIN)
|
||||
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.client.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())
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
use twitch_irc::message::{PrivmsgMessage, ServerMessage};
|
||||
|
||||
// use crate::{botcore::bot::Bot, command_condition_async, execution_async, Badge};
|
||||
|
||||
use super::{execution_async,Bot,Badge,command_condition_async};
|
||||
|
||||
|
||||
|
@ -188,17 +188,18 @@ impl Command
|
|||
(cmd.custom_cond_fn)(bot.clone(),message.clone()) && (cmd.custom_cond_async)(bot,message).await
|
||||
}
|
||||
|
||||
fn quiet_off_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
|
||||
!bot.get_channel_quiet(message.channel_login.clone())
|
||||
|| bot.get_channel_quiet(message.channel_login.clone()) && cmd.commands.contains(&("quiet off".to_string()))
|
||||
}
|
||||
// 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()) && cmd.commands.contains(&("quiet off".to_string()))
|
||||
// }
|
||||
|
||||
|
||||
cmd_called(self, bot.clone(), msg.clone()) &&
|
||||
caller_badge_ok(self, bot.clone(), msg.clone()).await &&
|
||||
admin_only_ok(self, bot.clone(), msg.clone()) &&
|
||||
custom_cond_ok(self, bot.clone(), msg.clone()).await &&
|
||||
quiet_off_ok(self, bot, msg)
|
||||
custom_cond_ok(self, bot.clone(), msg.clone()).await
|
||||
// &&
|
||||
// quiet_off_ok(self, bot, msg).await
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
// use tokio::sync::Mutex;
|
||||
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
use crate::Module;
|
||||
|
@ -116,20 +116,21 @@ impl Listener
|
|||
(list.trigger_cond_fn)(bot.clone(),msg.clone()) && (list.trigger_cond_async)(bot,msg).await
|
||||
}
|
||||
|
||||
fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
// async fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
// if let ServerMessage::Privmsg(msg) = message {
|
||||
|
||||
if let Some(parent_mod) = &*list.parent_module {
|
||||
return !bot.get_channel_quiet(msg.channel_login) || parent_mod.get_names().contains(&"debug".to_string());
|
||||
}
|
||||
// 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.get_channel_quiet(msg.channel_login) ;
|
||||
}
|
||||
return true; /* quiet is off for non chat msgs */
|
||||
}
|
||||
// return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) ;
|
||||
// }
|
||||
// return true; /* quiet is off for non chat msgs */
|
||||
// }
|
||||
|
||||
defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await &&
|
||||
quiet_off_ok(list, bot, msg)
|
||||
defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await
|
||||
// &&
|
||||
// quiet_off_ok(list, bot, msg).await
|
||||
}
|
||||
|
||||
/// executes the listeners executon body
|
||||
|
|
14
forcebot_core/src/botcore/built_in_mods.rs
Normal file
14
forcebot_core/src/botcore/built_in_mods.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// use std::sync::Arc;
|
||||
|
||||
use crate::Bot;
|
||||
|
||||
pub mod quiet;
|
||||
|
||||
|
||||
/// used to internally load internal modules
|
||||
pub async fn load_built_in_mods(bot:&Bot){
|
||||
|
||||
bot.load_module(quiet::create_module()).await;
|
||||
|
||||
}
|
||||
|
|
@ -44,8 +44,15 @@ fn cmd_quiet_on() -> Command {
|
|||
if let ServerMessage::Privmsg(msg) = message {
|
||||
|
||||
// dbg!("quiet on called");
|
||||
bot.set_channel_quiet(msg.channel_login.clone(), true);
|
||||
|
||||
let chatlock = bot.chat.lock().await;
|
||||
let _=chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await;
|
||||
|
||||
chatlock.set_channel_quiet(msg.channel_login.clone(), true);
|
||||
println!("channel {} set quiet true",msg.channel_login);
|
||||
|
||||
|
||||
return Result::Ok("Success".to_string());
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
@ -68,7 +75,12 @@ fn cmd_quiet_off() -> Command {
|
|||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
|
||||
bot.set_channel_quiet(msg.channel_login.clone(), false);
|
||||
let chatlock = bot.chat.lock().await;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
println!("channel {} set quiet false",msg.channel_login);
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
151
forcebot_core/src/botcore/chat.rs
Normal file
151
forcebot_core/src/botcore/chat.rs
Normal file
|
@ -0,0 +1,151 @@
|
|||
use std::{fmt::Error, ops::Mul, rc::Rc, sync::{Arc, Mutex, RwLock}};
|
||||
|
||||
use twitch_irc::{login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient};
|
||||
|
||||
use crate::Bot;
|
||||
|
||||
/// Bot API to send messages to send messages to chat
|
||||
///
|
||||
/// Uses TwitchIRCClient say_in_reply_to() but enforces controls like quiet
|
||||
///
|
||||
///
|
||||
|
||||
pub struct Chat
|
||||
{
|
||||
/// outbound chat client msg stream
|
||||
pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>,
|
||||
/// channel_quiet
|
||||
channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>,
|
||||
|
||||
}
|
||||
|
||||
impl Chat {
|
||||
|
||||
|
||||
pub async fn new(client:TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>)
|
||||
-> Chat {
|
||||
Chat {
|
||||
client,
|
||||
// parent_bot : Mutex::new(Bot::new().await) ,
|
||||
channel_quiet_yn : RwLock::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn set_parent_bot(&self,parent_bot_in:Arc<Bot>)
|
||||
// {
|
||||
// let mut lock = self.parent_bot.lock().unwrap();
|
||||
// *lock = parent_bot_in;
|
||||
// }
|
||||
|
||||
/// helper
|
||||
fn ok_to_send(&self,channel_login: String) -> bool {
|
||||
|
||||
fn not_quiet_ok(chat:&Chat,channel_login:String) -> bool {
|
||||
// let lock = chat.parent_bot.lock().unwrap();
|
||||
// let a = lock.as_ref();
|
||||
// if let Some(bot) = &*lock {
|
||||
return !chat.get_channel_quiet(channel_login);
|
||||
// }
|
||||
// true
|
||||
}
|
||||
not_quiet_ok(self, channel_login)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Get the quiet status of a channel
|
||||
pub fn get_channel_quiet(&self,channel:String) -> bool {
|
||||
for a in self.channel_quiet_yn.read().unwrap().iter() {
|
||||
if a.0 == channel {
|
||||
return a.1.read().unwrap().clone();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Get the quiet status of a channel
|
||||
pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) {
|
||||
let mut found = false;
|
||||
|
||||
let chnlquiet = self.channel_quiet_yn.read().unwrap();
|
||||
for rec in chnlquiet.iter() {
|
||||
if rec.0 == channel {
|
||||
found = true;
|
||||
let mut status = rec.1.write().unwrap();
|
||||
*status = quiet_on;
|
||||
drop(status);
|
||||
}
|
||||
}
|
||||
drop(chnlquiet);
|
||||
|
||||
if !found {
|
||||
// dbg!("set chn quiet > !found channel quiet status");
|
||||
let mut chnlquiet = self.channel_quiet_yn.write().unwrap();
|
||||
chnlquiet.push((channel,RwLock::new(quiet_on)));
|
||||
drop(chnlquiet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub async fn say_in_reply_to(&self,
|
||||
reply_to: &impl ReplyToMessage,
|
||||
message: String
|
||||
) -> Result<(),()> {
|
||||
// reply_to.channel_login()
|
||||
if self.ok_to_send(reply_to.channel_login().to_string()) {
|
||||
match self.client.say_in_reply_to(reply_to, message).await {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn say(&self,
|
||||
channel_login: String,
|
||||
message: String,
|
||||
) -> Result<(),()> {
|
||||
if self.ok_to_send(channel_login.to_string()) {
|
||||
match self.client.say(channel_login, message).await {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn me(&self,
|
||||
channel_login: String,
|
||||
message: String,
|
||||
) -> Result<(),()> {
|
||||
if self.ok_to_send(channel_login.to_string()) {
|
||||
match self.client.me(channel_login, message).await {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn me_in_reply_to(&self,
|
||||
reply_to: &impl ReplyToMessage,
|
||||
message: String
|
||||
) -> Result<(),()> {
|
||||
if self.ok_to_send(reply_to.channel_login().to_string()) {
|
||||
match self.client.me_in_reply_to(reply_to, message).await {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
pub mod guest_badge;
|
||||
pub mod pyramid;
|
||||
pub mod debug;
|
||||
pub mod quiet;
|
||||
// pub mod quiet;
|
|
@ -79,7 +79,7 @@ fn create_cmd_vip() -> Command {
|
|||
if badges_issued {
|
||||
|
||||
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.chat.lock().await.say_in_reply_to(
|
||||
&msg.clone(), format!("Guest badges issued for {} min",guest_dur_min)).await;
|
||||
return Result::Ok("Success".to_string());
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ fn create_cmd_mod() -> Command {
|
|||
}
|
||||
}
|
||||
if badges_issued {
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.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());
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ fn create_pyramid_detector() -> Listener {
|
|||
/* 2. Define an async trigger condition callback */
|
||||
async fn condition01(bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await {
|
||||
if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await && get_pyramid_size(msg.channel_login) > 3 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -65,11 +65,33 @@ fn create_pyramid_detector() -> Listener {
|
|||
/* 4. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
dbg!("enter pyramid listener execution - after pyramid complete");
|
||||
// if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await {
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg, "Clap".to_string()).await ;
|
||||
// let _ = bot.chat.lock().await.
|
||||
dbg!("> get start pattern");
|
||||
let pattern = get_start_pattern(msg.channel_login.clone());
|
||||
let mut outmsg ;
|
||||
|
||||
set_pyramid_started(msg.channel_login,false);
|
||||
/* Prefer emote before pattern in case pattern is command */
|
||||
if pattern.len() < 50 {
|
||||
outmsg = format!("Clap {}",pattern);
|
||||
} else {
|
||||
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()) ;
|
||||
// }
|
||||
|
@ -84,17 +106,22 @@ fn create_pyramid_detector() -> Listener {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/// detect pyramid based on latest message and channel
|
||||
///
|
||||
///
|
||||
async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool {
|
||||
dbg!("enter detect_pyramid_complete()");
|
||||
|
||||
let msgtext = msg.message_text.replace("\u{e0000}","").trim().to_string();
|
||||
let msgtext = msg.message_text.replace("","").replace("\u{e0000}","").trim().to_string();
|
||||
let msgchannel = msg.channel_login;
|
||||
let msgchatter = msg.sender.login;
|
||||
|
||||
// 1. Check if Pyramid started in chat > and recognize pyramid started
|
||||
if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) {
|
||||
dbg!("> set pyramid started - true");
|
||||
set_pyramid_started(msgchannel.clone(),true);
|
||||
push_to_compare(msgchannel.clone(),msgchatter.clone(),get_start_pattern(msgchannel.clone()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -109,15 +136,29 @@ async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool {
|
|||
|
||||
// 2b. If Pyramid is Started, and the latest message is the pattern, check for
|
||||
// symmetry to determine pyramid
|
||||
|
||||
if is_pyramid_started(msgchannel.clone()) && msgtext.clone() == get_start_pattern(msgchannel.clone()) {
|
||||
if symmetry_ok(msgchannel.clone()) {
|
||||
return true;
|
||||
} else {
|
||||
dbg!("> set pyramid started - false");
|
||||
set_pyramid_started(msgchannel,false);
|
||||
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
|
||||
dbg!("> set pyramid started - false");
|
||||
set_pyramid_started(msgchannel,false);
|
||||
|
||||
return false ;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -130,6 +171,8 @@ lazy_static!{
|
|||
pub static ref PYRAMID_STARTED_PER_CHNL: Mutex<Vec<(String,Mutex<bool>)>> = Mutex::new(vec![]);
|
||||
/// Start patterns per channel (channel:String,pattern:String)
|
||||
pub static ref START_PATTERNS_PER_CHNL: Mutex<Vec<(String,Mutex<String>)>> = Mutex::new(vec![]);
|
||||
/// Pyramid sze per channel (channel:String,started:bool)
|
||||
pub static ref PYRAMID_SIZE_PER_CHNL: Mutex<Vec<(String,Mutex<i32>)>> = Mutex::new(vec![]);
|
||||
/// temp message stack checker
|
||||
pub static ref TEMP_MSG_STACK: Mutex<Vec<String>> = Mutex::new(vec![]);
|
||||
|
||||
|
@ -249,6 +292,11 @@ fn push_to_compare(channel:String,chatter:String,message:String) {
|
|||
/// checks latest and next latest messages for potential start
|
||||
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()),
|
||||
// get_start_pattern(channel.clone())
|
||||
// )
|
||||
}
|
||||
|
||||
|
||||
|
@ -259,13 +307,17 @@ fn symmetry_ok(channel:String) -> bool {
|
|||
if !(read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut pyramid_size = 0;
|
||||
loop {
|
||||
|
||||
if !checking_started && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone()) {
|
||||
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() {
|
||||
temp_stack.push(pop_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1);
|
||||
pyramid_size += 1;
|
||||
|
||||
} 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() {
|
||||
|
||||
|
@ -276,13 +328,20 @@ fn symmetry_ok(channel:String) -> bool {
|
|||
continue;
|
||||
} else {
|
||||
|
||||
set_pyramid_size(channel.clone(), 0);
|
||||
temp_stack.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
} else { return false; }
|
||||
} else {
|
||||
set_pyramid_size(channel.clone(), 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if checking_started && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone()) {
|
||||
|
||||
/* leave pyramid size set for exection */
|
||||
set_pyramid_size(channel.clone(), pyramid_size*2-1);
|
||||
temp_stack.clear();
|
||||
return true;
|
||||
}
|
||||
|
@ -293,6 +352,32 @@ fn symmetry_ok(channel:String) -> bool {
|
|||
}
|
||||
|
||||
|
||||
fn set_pyramid_size(channel:String,size:i32) {
|
||||
let mut size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
|
||||
let mut found = false;
|
||||
for rec in size_perchnl.iter() {
|
||||
if rec.0 == channel {
|
||||
found = true;
|
||||
let mut rec_started = rec.1.lock().unwrap();
|
||||
*rec_started = size;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
size_perchnl.push((channel,Mutex::new(size)));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pyramid_size(channel:String) -> i32 {
|
||||
let size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap();
|
||||
for rec in size_perchnl.iter() {
|
||||
if rec.0 == channel {
|
||||
let rec_started = rec.1.lock().unwrap();
|
||||
return *rec_started;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// #todo
|
||||
///
|
||||
/// pyramid interruptor
|
||||
|
@ -316,7 +401,7 @@ fn _create_interruptor_cmd() -> Command {
|
|||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
|
||||
let _ = bot.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())
|
||||
|
|
|
@ -46,7 +46,7 @@ pub async fn main() {
|
|||
/* 3. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
|
||||
let _ = bot.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())
|
||||
|
|
89
readme.md
89
readme.md
|
@ -27,23 +27,41 @@ cargo run -p forcebot_core
|
|||
|
||||
# Features
|
||||
|
||||
- Quick Start to use full feature set bot
|
||||
- Moderators & Broadcasters can `disable` or `enable` `Modules` of bot functionality through chat `Commands`
|
||||
- Full Feature Set `forcebot_core` bot has the following modules loaded
|
||||
- `debug` - outputs to console messages from the channel where it was enabled. Toggle debug with the Commands `debug on` or `debug off`
|
||||
- `guest_badge` - Temporary badges can be issued to chatters
|
||||
- `besty` - Tomfoolery
|
||||
- `pyramid` - for detecting & handling pyramids
|
||||
## Built In Chat Commands
|
||||
|
||||
- `quiet on` / `quiet off` - Moderators & Broadcasters can quiet the bot
|
||||
|
||||
- `enable $module$` / `disable $module$` - Moderators & Broadcasters can enable or disable `Modules` of bot functionality through chat `Commands`
|
||||
|
||||
|
||||
## Custom Modules can be coded to load additional functionality
|
||||
|
||||
Developers an create Modules that add more bot functionality
|
||||
|
||||
The main `forcebot_core` Binary crate includes the following Custom `Modules`
|
||||
|
||||
- `debug` - outputs to console messages from the channel where it was enabled. Toggle debug with the Commands `debug on` or `debug off`
|
||||
- `guest_badge` - Temporary badges can be issued to chatters
|
||||
- `besty` - Tomfoolery
|
||||
- `pyramid` - for detecting & handling pyramids
|
||||
|
||||
|
||||
## `forcebot_core` Bot Library
|
||||
|
||||
- `forcebot_core` library API provides Custom package developers a way to add functionality by adding `Modules` that contain Bot Objects like `Commands` and `Listeners`
|
||||
- `Listeners` and `Commands` listen for a defined callback trigger condition and run an defined execution callback
|
||||
- `Commands` are similar to `Listeners` with refined trigger conditions including using bot `prefix` with the `Command` , triggers based on `Badge` , and more
|
||||
- Workspace for package developers to independently code their own `Modules`
|
||||
- Workspace comes with binary crates with working or example bots that use `forcebot_core` library
|
||||
- `moderator_reactor` - bot kneels to all moderator messages
|
||||
- `simple_module_example` - bot has a `test` `Module` with a `test` `Command` .Moderators & Broadcasters can manage the `Module` in chat with `enable` / `disable` `Commands`
|
||||
- `new_empty_bot` - while empty, has `disable` and `enable` chat `Commands` . This is an example of the bot without any loaded modules
|
||||
- `simple_command_bot` - bot responds to a `test` `Command`. As the command was not loaded through a `Module`, `disable` & `enable` commands don't work on the `test` command. This could be a Global `Command`
|
||||
- `simple_debug_listener` - bot outputs all twitch `ServerMessages` received to terminal
|
||||
|
||||
## Workspaces
|
||||
|
||||
|
||||
Workspace comes with binary crates with working or example bots that use `forcebot_core` library
|
||||
- `moderator_reactor` - bot kneels to all moderator messages
|
||||
- `simple_module_example` - bot has a `test` `Module` with a `test` `Command` . Moderators & Broadcasters can manage the `Module` in chat with `enable` / `disable` `Commands`
|
||||
- `new_empty_bot` - while empty, has `disable` and `enable` chat `Commands` . This is an example of the bot without any loaded modules
|
||||
- `simple_command_bot` - bot responds to a `test` `Command`. As the command was not loaded through a `Module`, `disable` & `enable` commands don't work on the `test` command. This could be a Global `Command`
|
||||
- `simple_debug_listener` - bot outputs all twitch `ServerMessages` received to terminal
|
||||
|
||||
|
||||
|
||||
|
@ -150,7 +168,7 @@ use forcebot_core::Bot;
|
|||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let bot = Bot::new();
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 2. Run the bot */
|
||||
bot.run().await;
|
||||
|
@ -165,18 +183,24 @@ A `Module` is a group of bot objects (eg `Command`) that elevated users can mana
|
|||
Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
|
||||
|
||||
```rust
|
||||
use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot};
|
||||
use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot};
|
||||
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
/* Create the bot using env */
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 1. Load the module into the bot */
|
||||
bot.load_module(funbot_objs::create_module()).await;
|
||||
|
||||
/* 2. Load Custom Modules */
|
||||
bot.load_module(guest_badge::create_module()).await;
|
||||
bot.load_module(pyramid::create_module()).await;
|
||||
bot.load_module(debug::create_module()).await;
|
||||
|
||||
|
||||
/* 3. Run the bot */
|
||||
bot.run().await;
|
||||
|
@ -195,13 +219,14 @@ Create a custom `Module` by :
|
|||
|
||||
|
||||
```rust
|
||||
|
||||
use forcebot_core::Bot;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* load the Module */
|
||||
bot.load_module(custom_mod::new()).await;
|
||||
|
@ -211,6 +236,7 @@ pub async fn main() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
pub mod custom_mod {
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -240,7 +266,7 @@ pub mod custom_mod {
|
|||
/* 2. Define exec callback */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.chat.lock().await.say_in_reply_to(
|
||||
&msg, "test return".to_string()).await;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
|
@ -249,7 +275,7 @@ pub mod custom_mod {
|
|||
/* 3. Set Command flags */
|
||||
cmd.set_exec_fn(execution_async(execbody));
|
||||
cmd.set_admin_only(false);
|
||||
cmd.set_min_badge(Badge::Moderator);
|
||||
cmd.set_min_badge(Badge::Vip);
|
||||
|
||||
cmd
|
||||
}
|
||||
|
@ -260,6 +286,7 @@ pub mod custom_mod {
|
|||
Bot with a simple listener that listens for all messages and prints in output
|
||||
|
||||
```rust
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_core::{execution_async, Bot, Listener};
|
||||
|
@ -269,7 +296,7 @@ use twitch_irc::message::ServerMessage;
|
|||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 2a. Create a new blank Listener */
|
||||
let mut listener = Listener::new();
|
||||
|
@ -289,12 +316,13 @@ pub async fn main() {
|
|||
listener.set_exec_fn(execution_async(execbody));
|
||||
|
||||
/* 3. Load the listener into the bot */
|
||||
bot.load_listener(listener);
|
||||
bot.load_listener(listener).await;
|
||||
|
||||
/* 4. Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Moderator Reactor
|
||||
|
@ -302,6 +330,7 @@ pub async fn main() {
|
|||
Example listener listens for a moderator badge and reply in chat
|
||||
|
||||
```rust
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_core::Bot;
|
||||
|
@ -314,7 +343,7 @@ use twitch_irc::message::ServerMessage;
|
|||
pub async fn main() {
|
||||
|
||||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 1. Create a new blank Listener */
|
||||
let mut listener = Listener::new();
|
||||
|
@ -324,7 +353,6 @@ pub async fn main() {
|
|||
listener.set_trigger_cond_fn(
|
||||
|_:Arc<Bot>,message:ServerMessage|
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
|
||||
for badge in msg.badges {
|
||||
if matches!(badge, x if x.name == "moderator") {
|
||||
// dbg!("moderator found");
|
||||
|
@ -338,7 +366,7 @@ pub async fn main() {
|
|||
/* 3. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
|
||||
let _ = bot.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())
|
||||
|
@ -348,12 +376,13 @@ pub async fn main() {
|
|||
listener.set_exec_fn(execution_async(execbody));
|
||||
|
||||
/* 5. Load the listener into the bot */
|
||||
bot.load_listener(listener);
|
||||
bot.load_listener(listener).await;
|
||||
|
||||
/* Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Simple Test Command
|
||||
|
@ -367,11 +396,12 @@ use forcebot_core::execution_async;
|
|||
use forcebot_core::Command;
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
let bot = Bot::new().await;
|
||||
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new(vec!["test".to_string()],"".to_string());
|
||||
|
@ -379,7 +409,7 @@ pub async fn main() {
|
|||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
|
||||
let _ = bot.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())
|
||||
|
@ -395,12 +425,13 @@ pub async fn main() {
|
|||
cmd.set_min_badge(Badge::Moderator);
|
||||
|
||||
/* 6. Load the cmd into the bot */
|
||||
bot.load_command(cmd);
|
||||
bot.load_command(cmd).await;
|
||||
|
||||
/* Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Crate Rust API Documentation
|
||||
|
|
|
@ -34,7 +34,7 @@ pub async fn main() {
|
|||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
|
||||
let _ = bot.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())
|
||||
|
|
|
@ -63,7 +63,7 @@ pub mod custom_mod {
|
|||
/* 2. Define exec callback */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _= bot.client.say_in_reply_to(
|
||||
let _= bot.chat.lock().await.say_in_reply_to(
|
||||
&msg, "test return".to_string()).await;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue