Merge pull request 'writelock_issue' (#45) from issue-chat-say-id-write-lock into parent-botaction-to-child-fn
All checks were successful
ci/woodpecker/pr/cargo-checks Pipeline was successful

Reviewed-on: #45
This commit is contained in:
modulatingforce 2024-03-24 23:44:24 -04:00
commit 35db264b9e
5 changed files with 432 additions and 26 deletions

View file

@ -6,7 +6,7 @@ use tokio::sync::RwLock;
use crate::core::botinstance::BotInstance;
use super::botmodules::{BotAction, BotModule};
use super::{botmodules::{BotAction, BotModule}, identity::ChatBadge};
pub type BotAR = Arc<RwLock<BotInstance>>;
@ -41,6 +41,26 @@ impl ExecBodyParams {
parent_module
}
pub fn get_sender(&self) -> String {
self.msg.sender.name.clone()
}
pub fn get_sender_chatbadge(&self) -> Option<ChatBadge> {
let mut requestor_badge_mut: Option<ChatBadge> = None;
for b in &self.msg.badges {
if b.name == "moderator" {
requestor_badge_mut = Some(ChatBadge::Mod);
} else if b.name == "broadcaster" {
requestor_badge_mut = Some(ChatBadge::Broadcaster);
}
}
let requestor_badge = requestor_badge_mut;
requestor_badge
}
}

View file

@ -390,6 +390,12 @@ impl BotInstance {
Some(msg),
);
botlog::trace(
"ACQUIRING WRITE LOCK : ID",
Some("BotInstance > listener_main_prvmsg()".to_string()),
Some(msg),
);
const OF_CMD_CHANNEL:Channel = Channel(String::new());
@ -431,6 +437,11 @@ impl BotInstance {
return;
};
botlog::trace(
"ACQUIRING WRITE LOCK : ID",
Some("BotInstance > listener_main_prvmsg()".to_string()),
Some(msg),
);
let eval = {

View file

@ -846,6 +846,12 @@ impl ModulesManager {
return ChangeResult::Failed("Module doesn't exist".to_string());
}
botlog::trace(
"ACQUIRING WRITE LOCK : ID",
Some("ModulesManager > Exec_enable".to_string()),
None,
);
let mut idlock = id.write().await;
@ -1028,6 +1034,13 @@ impl ModulesManager {
return ChangeResult::Failed("Module doesn't exist".to_string());
}
botlog::trace(
"ACQUIRING WRITE LOCK : ID",
Some("ModulesManager > Exec_disable".to_string()),
None,
);
let mut idlock = id.write().await;

View file

@ -12,6 +12,7 @@ use casual_logger::Log;
use rand::Rng;
use crate::core::identity::Permissible;
use crate::core::ratelimiter;
use crate::core::ratelimiter::RateLimiter;
@ -23,6 +24,7 @@ use tokio::time::{sleep, Duration};
use super::bot_actions::ExecBodyParams;
use super::botmodules::BotModule;
use super::identity;
use async_recursion::async_recursion;
@ -34,7 +36,7 @@ pub struct Chat {
}
#[derive(Clone)]
#[derive(Clone,Debug)]
enum BotMsgType<'a> {
SayInReplyTo(&'a PrivmsgMessage,String),
Say(String,String),
@ -62,6 +64,9 @@ impl Chat {
// async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
/*
formats message before sending to TwitchIRC
@ -71,6 +76,13 @@ impl Chat {
*/
botlog::trace(
format!("send_bot_msg params : {:?}",msginput).as_str(),
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
let (channel_login,mut outmsg) = match msginput.clone() {
BotMsgType::SayInReplyTo(msg, outmsg) => {
(msg.channel_login.clone(),outmsg)
@ -80,19 +92,75 @@ impl Chat {
},
};
if self.client.get_channel_status(channel_login.clone()).await == (false,false) {
// in the case where the provided channel isn't something we're known to be connected to
botlog::trace(
"BEFORE parent_module call",
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
let parent_module = params.get_parent_module().await;
// let parent_module = parent_module.clone();
let params_clone = params.clone();
let botclone = Arc::clone(&params_clone.bot);
let botlock = botclone.read().await;
let modmgr = Arc::clone(&botlock.botmodules);
let modstatus = (*modmgr).modstatus(
parent_module.clone().expect("ERROR - Expected a module"),
Channel(channel_login.clone())
).await;
// botlog::trace(
// "BEFORE GET_CHANNEL_STATUS",
// Some("chat.rs > send_botmsg ".to_string()),
// Some(&params.msg),
// );
// let rslt = self.client.get_channel_status(channel_login.clone()).await == (false,false);
// botlog::trace(
// format!("GET_CHANNEL_STATUS result = {:?}",rslt).as_str(),
// Some("chat.rs > send_botmsg ".to_string()),
// Some(&params.msg),
// );
// Log::flush();
// if rslt {
// // in the case where the provided channel isn't something we're known to be connected to
// botlog::warn(
// &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
// Some("Chat > send_botmsg".to_string()),
// None,
// );
// return ;
// }
if !params.bot.read().await.bot_channels.contains(&Channel(channel_login.clone())) {
botlog::warn(
&format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
Some("Chat > send_botmsg".to_string()),
None,
);
self.say_in_reply_to(
&params.msg,
"uuh Bot can't send to a channel it isn't joined".to_string(),
params.clone()
).await;
return ;
}
/*
[ ] !! => 03.24 - Somewhere around here, we should be validating module for target channel
[x] !! => 03.24 - Somewhere around here, we should be validating module for target channel
*/
@ -103,28 +171,47 @@ impl Chat {
*/
let parent_module = params.get_parent_module().await;
// let parent_module = parent_module.clone();
let botlock = params.bot.read().await;
let modmgr = Arc::clone(&botlock.botmodules);
let modstatus = (*modmgr).modstatus(
parent_module.clone().expect("ERROR - Expected a module"),
Channel(channel_login.clone())
).await;
// match modstatus {
// super::botmodules::StatusType::Enabled(_) => (),
// super::botmodules::StatusType::Disabled(_) => (),
// }
botlog::trace(
format!("BEFORE modstatus check : modstatus = {:?}",modstatus).as_str(),
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
match modstatus {
super::botmodules::StatusType::Enabled(_) => (),
super::botmodules::StatusType::Disabled(_) => (),
}
if let super::botmodules::StatusType::Disabled(lvl) = modstatus {
// Note : At this point, chat was called in a channel where the parent module IS enabled
// - this type of validation is done outside of Chat()
// This though takes into account scenarios where we are targetting a different channel
botlog::trace(
"BEFORE msginput check",
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
Log::flush();
if let BotMsgType::SayInReplyTo(a, _) = msginput {
botlog::trace(
"BEFORE potential Async recursion",
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.clone().msg),
);
Log::flush();
self.say_in_reply_to(
a,
format!("uuh {:?} is disabled on {} : {:?}",
@ -135,6 +222,37 @@ impl Chat {
params.clone()
).await;
// let chat_clone = self.clone();
// // tokio::spawn( async move {
// // // for _ in 0..5 {
// // // println!(">> Innterroutine triggered!");
// // // sleep(Duration::from_secs_f64(5.0)).await;
// // // }
// // chat_clone.say_in_reply_to(
// // a,
// // format!("uuh {:?} is disabled on {} : {:?}",
// // parent_module.clone().unwrap(),
// // channel_login.clone(),
// // lvl
// // ),
// // params.clone()
// // ).await;
// // }
// // );
botlog::trace(
"AFTER potential Async recursion",
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
Log::flush();
}
@ -143,6 +261,205 @@ impl Chat {
}
/*
[ ] !! => 03.24 - Would be nice if around here , validate the user has at least some special roles in target channel
- NOTE : If these need to be refined, they can be by the custom module developer at the parent calling function of say()
- This just prevents Chat from being triggered in a channel where the sending chatter does not have any special roles
*/
/*
Use
pub async fn getspecialuserroles(
&self,
chattername: String,
channel: Option<Channel>,
) -> Vec<UserRole> {
*/
// let params_clone = params.clone();
let botclone = Arc::clone(&params.bot);
let botlock = botclone.read().await;
let id = botlock.get_identity();
let id = Arc::clone(&id);
let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
let user_roles = idlock.getspecialuserroles(
params.get_sender(),
Some(Channel(channel_login.clone()))
).await;
// [ ] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
// - Otherwise if not (checked here) , this will not run
// - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want
if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone())))
|| user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone())))
|| user_roles.contains(&identity::UserRole::Broadcaster))
{
self.say_in_reply_to(
&params.msg,
format!("uuh You do not have the right roles to send to {}",
channel_login.clone(),
),
params.clone()
).await;
return;
}
/*
Use the following
pub async fn can_user_run(
&mut self,
usr: String,
channelname: Channel,
chat_badge: Option<ChatBadge>,
cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
) -> (Permissible, ChangeResult) {
*/
/*
botlog::trace(
"BEFORE Permissibility checks",
Some("chat.rs > send_botmsg ".to_string()),
Some(&params.msg),
);
Log::flush();
const OF_CMD_CHANNEL:Channel = Channel(String::new());
let permissability = Permissible::Allow;
{
// let id = botlock.get_identity();
// let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
let channel_login_clone = channel_login.clone();
let spawnhandle = tokio::spawn(
async move {
let botclone = Arc::clone(&params_clone.bot);
let botlock = botclone.read().await;
let id = botlock.get_identity();
// botlog::trace(
// "ACQUIRING WRITE LOCK : ID",
// Some("Chat > send_botmsg".to_string()),
// Some(&params.msg),
// );
// {
// let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
// }
// botlog::trace(
// "ACQUIRED WRITE LOCK : ID",
// Some("Chat > send_botmsg".to_string()),
// Some(&params.msg),
// );
// let (permissability, _) = idlock
// .can_user_run(
// params.get_sender(),
// Channel(channel_login_clone),
// params.get_sender_chatbadge(),
// vec![
// //identity::UserRole::BotAdmin,
// identity::UserRole::Mod(OF_CMD_CHANNEL),
// identity::UserRole::SupMod(OF_CMD_CHANNEL),
// identity::UserRole::Broadcaster,
// ]
// ).await;
// permissability
}
);
if let Ok(permissibility) = spawnhandle.await {
botlog::trace(
format!("permisibility check : {:?}",permissability).as_str(),
Some("chat.rs > send_botmsg ".to_string()),
None
);
}
}
// let permissability = {
// let id = botlock.get_identity();
// let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
// let (permissability, _) = idlock
// .can_user_run(
// params.get_sender(),
// Channel(channel_login.clone()),
// params.get_sender_chatbadge(),
// vec![
// //identity::UserRole::BotAdmin,
// identity::UserRole::Mod(OF_CMD_CHANNEL),
// identity::UserRole::SupMod(OF_CMD_CHANNEL),
// identity::UserRole::Broadcaster,
// ]
// ).await;
// permissability
// };
// match permissability {
// Permissible::Allow => (),
// Permissible::Block => (),
// }
botlog::trace(
format!("permisibility check : {:?}",permissability).as_str(),
Some("chat.rs > send_botmsg ".to_string()),
None,
);
Log::flush();
if let Permissible::Block = permissability {
if let BotMsgType::SayInReplyTo(a, _) = msginput {
// self.say_in_reply_to(
// a,
// format!("uuh you don't have special privileges in {}",
// channel_login.clone()
// ),
// params.clone()
// ).await;
}
return
}
*/
let rl = Arc::clone(&self.ratelimiters);
let mut rllock = rl.lock().await;
@ -222,6 +539,57 @@ impl Chat {
#[async_recursion]
pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
// let params_clone = params.clone();
// let botclone = Arc::clone(&params_clone.bot);
// let botlock = botclone.read().await;
// let id = botlock.get_identity();
// let id = Arc::clone(&id);
// // botlog::trace(
// // "ACQUIRING WRITE LOCK : ID",
// // Some("Chat > send_botmsg".to_string()),
// // Some(&params.msg),
// // );
// // Log::flush();
// botlog::trace(
// "ACQUIRING READ LOCK : ID",
// Some("Chat > send_botmsg".to_string()),
// Some(&params.msg),
// );
// Log::flush();
// // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
// let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
// let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await;
// botlog::trace(
// format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(),
// Some("Chat > send_botmsg".to_string()),
// Some(&params.msg),
// );
// Log::flush();
// // botlog::trace(
// // "ACQUIRED WRITE LOCK : ID",
// // Some("Chat > send_botmsg".to_string()),
// // Some(&params.msg),
// // );
// // Log::flush();
// botlog::trace(
// "ACQUIRED READ LOCK : ID",
// Some("Chat > send_botmsg".to_string()),
// Some(&params.msg),
// );
// Log::flush();
self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;
}

View file

@ -57,8 +57,11 @@ pub async fn init(mgr: Arc<ModulesManager>) {
// 2. Add the BotAction to ModulesManager
botc1.add_to_modmgr(Arc::clone(&mgr)).await;
// If enabling by defauling at instance level
mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await;
// [ ] #TODO - FOR SOME REASON, IF DISABLED BY DEFAULT, IT OVERFLOWS at RUNGTIME
}
@ -79,15 +82,6 @@ async fn sayout(params : ExecBodyParams) {
[x] Get the parent module
*/
// let params_clone = Arc::clone(&params.parent_act);
// let actlock = params_clone.read().await;
// let act = &(*actlock);
// let parent_module = match act {
// BotAction::C(c) => Some(&(*c).module),
// BotAction::L(l) => Some(&(*l).module),
// _ => None,
// };
let parent_module = params.get_parent_module().await;