First (barely) working async version

[TEC], wtf if this. It's all nigh upon unreadable and is in a terrible
code style
parent c6ab8e0f
Pipeline #297 failed with stages
......@@ -11,7 +11,7 @@ pub struct LDAPUser {
pub fn ldap_search(username: &str) -> Option<LDAPUser> {
let settings = LdapConnSettings::new().set_no_tls_verify(true);
let ldap =
let mut ldap =
LdapConn::with_settings(settings, &CONFIG.bind_address).expect("Unable to connect to LDAP");
ldap.simple_bind(
"cn=ucc-discord-bot,cn=Users,dc=ad,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au",
......@@ -31,7 +31,7 @@ pub fn ldap_search(username: &str) -> Option<LDAPUser> {
.success()
.expect("LDAP search error");
if rs.is_empty() {
return None
return None;
}
let result = SearchEntry::construct(rs[0].clone()).attrs;
Some(LDAPUser {
......@@ -44,9 +44,9 @@ pub fn ldap_search(username: &str) -> Option<LDAPUser> {
.expect("LDAP failed to get 'displayName' field")
.join(""),
when_created: "".to_string(), // result
// .get("whenCreated")
// .expect("LDAP failed to get 'whenCreated' field")
// .join(""),
// .get("whenCreated")
// .expect("LDAP failed to get 'whenCreated' field")
// .join(""),
login_shell: result
.get("loginShell")
.expect("LDAP failed to get 'loginShell' field")
......
use crate::config::{ReactRoleMap, CONFIG};
use crate::util::{get_react_from_string, get_string_from_react};
use rayon::prelude::*;
use serenity::{
client::Context,
model::{channel::Message, channel::Reaction, id::RoleId, id::UserId},
......@@ -198,21 +197,17 @@ async fn get_all_role_reaction_message(ctx: &Context) -> Vec<(Message, &'static
let channels = ctx.http.get_channels(*guild.id.as_u64()).await.unwrap();
info!(" Find role-react message: channels determined");
let http = ctx.http.clone();
channels
.par_iter()
.flat_map(|channel| {
// since we don't know which channels the messages are in, we check every combination
// of message and channel and ignore the bad matches using .ok() and .filter_map()
let h = http.clone(); // thread-local copy
CONFIG
.react_role_messages
.par_iter()
.filter_map(move |rrm| async {
h.get_message(*channel.id.as_u64(), *rrm.message.as_u64())
.await
.ok()
.map(|m| (m, &rrm.mapping))
})
})
.collect()
let mut v = Vec::new();
for channel in channels {
for reaction in CONFIG.react_role_messages.iter() {
if let Some(m) = http
.get_message(*channel.id.as_u64(), *reaction.message.as_u64())
.await
.ok()
{
v.push((m, &reaction.mapping))
}
}
}
v
}
......@@ -6,7 +6,7 @@ use serenity::{
utils::MessageBuilder,
};
use rand::seq::SliceRandom;
// use rand::seq::SliceRandom;
use crate::config::CONFIG;
use crate::ldap;
......@@ -35,9 +35,8 @@ impl EventHandler for Handler {
send_message!(
msg.channel_id,
&ctx.http,
MENTION_RESPONSES
.choose(&mut rand::thread_rng())
.expect("We couldn't get any sass")
MENTION_RESPONSES[0] //.choose(&mut rand::random())
//.expect("We couldn't get any sass")
);
}
return;
......@@ -136,16 +135,12 @@ impl EventHandler for Handler {
async fn reaction_add(&self, ctx: Context, add_reaction: channel::Reaction) {
match add_reaction.message(&ctx.http).await {
Ok(message) => match get_message_type(&message) {
MessageType::RoleReactMessage if add_reaction.user_id.unwrap() != CONFIG.bot_id => {
add_role_by_reaction(&ctx, message, add_reaction);
return;
MessageType::RoleReactMessage if add_reaction.user_id == Some(CONFIG.bot_id) => {
add_role_by_reaction(&ctx, message, add_reaction).await
}
_ if message.author.id != CONFIG.bot_id
|| add_reaction.user_id.unwrap() == CONFIG.bot_id =>
{
return
}
MessageType::Motion => voting::reaction_add(ctx, add_reaction).await,
|| add_reaction.user_id == Some(CONFIG.bot_id) => {}
MessageType::Motion => voting::reaction_add(&ctx, add_reaction).await,
MessageType::LogReact => {
let react_user = add_reaction.user(&ctx).await.unwrap();
let react_as_string = get_string_from_react(&add_reaction.emoji);
......@@ -186,28 +181,24 @@ impl EventHandler for Handler {
MessageType::RoleReactMessage
if removed_reaction.user_id.unwrap() != CONFIG.bot_id =>
{
remove_role_by_reaction(&ctx, message, removed_reaction);
return;
remove_role_by_reaction(&ctx, message, removed_reaction).await
}
_ if message.author.id != CONFIG.bot_id
|| removed_reaction.user_id.unwrap() == CONFIG.bot_id =>
{
return
}
MessageType::Motion => voting::reaction_remove(ctx, removed_reaction).await,
|| removed_reaction.user_id.unwrap() == CONFIG.bot_id => {}
MessageType::Motion => voting::reaction_remove(&ctx, removed_reaction).await,
_ => {}
},
Err(why) => error!("Failed to get react message {:?}", why),
}
}
fn guild_member_addition(
async fn guild_member_addition(
&self,
ctx: Context,
_guild_id: serenity::model::id::GuildId,
the_new_member: Member,
) {
user_management::new_member(&ctx, the_new_member);
user_management::new_member(&ctx, the_new_member).await
}
// Set a handler to be called on the `ready` event. This is called when a
......@@ -216,13 +207,13 @@ impl EventHandler for Handler {
// private channels, and more.
//
// In this case, just print what the current user's username is.
fn ready(&self, ctx: Context, ready: Ready) {
async fn ready(&self, ctx: Context, ready: Ready) {
info!("{} is connected!", ready.user.name);
sync_all_role_reactions(&ctx);
sync_all_role_reactions(&ctx).await
}
fn resume(&self, ctx: Context, _: serenity::model::event::ResumedEvent) {
sync_all_role_reactions(&ctx);
async fn resume(&self, ctx: Context, _: serenity::model::event::ResumedEvent) {
sync_all_role_reactions(&ctx).await
}
}
......
......@@ -17,7 +17,7 @@ lazy_static! {
}
fn text_encrypt(plaintext: &str) -> String {
base64::encode(CIPHER.encrypt_vec(plaintext.as_bytes()))
base64::encode(CIPHER.clone().encrypt_vec(plaintext.as_bytes()))
}
fn text_decrypt(ciphertext: &str) -> Option<String> {
......@@ -25,7 +25,7 @@ fn text_decrypt(ciphertext: &str) -> Option<String> {
warn!("Unable to decode base64 text");
return None
});
guard!(let Ok(decrypted_vec) = CIPHER.decrypt_vec(&cipher_vec) else {
guard!(let Ok(decrypted_vec) = CIPHER.clone().decrypt_vec(&cipher_vec) else {
warn!("Text decryption failed");
return None
});
......
......@@ -290,7 +290,7 @@ impl Commands {
let user = match ctx.http.get_user(member.discord_id as _).await {
Ok(u) => u,
Err(e) => {
error!("Couldn't find matching Discord ID for username!");
error!("Couldn't find matching Discord ID for username! {:?}", e);
return;
}
};
......@@ -492,8 +492,7 @@ impl Commands {
pub async fn clear_info(ctx: Context, msg: Message, field: &str) {
if field.trim().is_empty() {
// just show the help page from set_info
Commands::set_info(ctx, msg, "");
return;
return Commands::set_info(ctx, msg, "").await;
}
match field {
"bio" => database::set_member_bio(&msg.author.id.0, None),
......
......@@ -5,7 +5,7 @@ use serenity::{
};
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Mutex;
use tokio::sync::Mutex;
use crate::config::CONFIG;
use crate::util::get_string_from_react;
......@@ -15,8 +15,7 @@ impl Commands {
pub async fn move_something(ctx: Context, msg: Message, content: &str) {
let motion = content;
if !motion.is_empty() {
create_motion(&ctx, &msg, motion);
return;
return create_motion(&ctx, &msg, motion).await;
}
send_message!(
msg.channel_id,
......@@ -34,8 +33,7 @@ impl Commands {
pub async fn poll(ctx: Context, msg: Message, content: &str) {
let topic = content;
if !topic.is_empty() {
create_poll(&ctx, &msg, topic);
return;
return create_poll(&ctx, &msg, topic).await;
}
send_message!(
msg.channel_id,
......@@ -167,45 +165,42 @@ lazy_static! {
}
async fn get_cached_motion(ctx: &Context, msg: &Message) -> MotionInfo {
let mut cached_motions = MOTIONS_CACHE.lock().unwrap();
let mut cached_motions = MOTIONS_CACHE.lock().await;
if !cached_motions.contains_key(&msg.id) {
info!("Initialising representation of motion {:?}", msg.id);
let for_votes = msg
.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.for_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap();
let against_votes = msg
.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.against_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap();
let abstain_votes = msg
.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.abstain_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap();
let this_motion = MotionInfo {
votes: {
let mut m = HashMap::new();
m.insert(
CONFIG.for_vote.to_string(),
msg.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.for_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap(),
);
m.insert(
CONFIG.against_vote.to_string(),
msg.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.against_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap(),
);
m.insert(
CONFIG.abstain_vote.to_string(),
msg.reaction_users(
ctx,
EmojiIdentifier::from_str(&CONFIG.abstain_vote).unwrap(),
Some(100),
None,
)
.await
.unwrap(),
);
m.insert(CONFIG.for_vote.to_string(), for_votes);
m.insert(CONFIG.against_vote.to_string(), against_votes);
m.insert(CONFIG.abstain_vote.to_string(), abstain_votes);
m
},
};
......@@ -213,34 +208,15 @@ async fn get_cached_motion(ctx: &Context, msg: &Message) -> MotionInfo {
}
(*cached_motions.get(&msg.id).unwrap()).clone()
}
fn set_cached_motion(id: serenity::model::id::MessageId, motion_info: MotionInfo) {
if let Some(motion) = MOTIONS_CACHE.lock().unwrap().get_mut(&id) {
async fn set_cached_motion(id: serenity::model::id::MessageId, motion_info: MotionInfo) {
if let Some(motion) = MOTIONS_CACHE.lock().await.get_mut(&id) {
*motion = motion_info;
return;
}
warn!("{}", "Couldn't find motion in cache to set");
}
macro_rules! tiebreaker {
($ctx: expr, $vote: expr, $motion_info: expr) => {
if $motion_info
.votes
.get($vote)
.unwrap()
.iter()
.any(|u| async {
u.has_role($ctx, CONFIG.server_id, CONFIG.tiebreaker_role)
.await
.unwrap()
})
{
0.25
} else {
0.0
}
};
}
async fn update_motion(
ctx: &Context,
msg: &mut Message,
......@@ -250,15 +226,33 @@ async fn update_motion(
) {
let motion_info: MotionInfo = get_cached_motion(ctx, msg).await;
async fn tiebreaker(ctx: &Context, motion: &MotionInfo, vote_type: &str) -> f32 {
if let Some(votes) = motion.votes.get(vote_type) {
for voter in votes {
match voter
.has_role(ctx, CONFIG.server_id, CONFIG.tiebreaker_role)
.await
{
Ok(true) => return 0.25,
_ => continue,
}
}
0.0
} else {
warn!("Couldn't find \"{}\" vote for {:?}", vote_type, motion);
0.0
}
}
let for_votes = motion_info.votes.get(&CONFIG.for_vote).unwrap().len() as isize - 1;
let against_votes = motion_info.votes.get(&CONFIG.against_vote).unwrap().len() as isize - 1;
let abstain_votes = motion_info.votes.get(&CONFIG.abstain_vote).unwrap().len() as isize - 1;
let for_strength = for_votes as f32 + tiebreaker!(ctx, &CONFIG.for_vote, motion_info);
let for_strength = for_votes as f32 + tiebreaker(ctx, &motion_info, &CONFIG.for_vote).await;
let against_strength =
against_votes as f32 + tiebreaker!(ctx, &CONFIG.against_vote, motion_info);
against_votes as f32 + tiebreaker(ctx, &motion_info, &CONFIG.against_vote).await;
let abstain_strength =
abstain_votes as f32 + tiebreaker!(ctx, &CONFIG.abstain_vote, motion_info);
abstain_votes as f32 + tiebreaker(ctx, &motion_info, &CONFIG.abstain_vote).await;
let old_embed = msg.embeds[0].clone();
let topic = old_embed.clone().title.unwrap();
......@@ -271,10 +265,13 @@ async fn update_motion(
topic
);
let update_status = |e: &mut serenity::builder::CreateEmbed,
status: &str,
last_status_full: String,
topic: &str| async {
fn update_status(
ctx: &Context,
e: &mut serenity::builder::CreateEmbed,
status: &str,
last_status_full: String,
topic: &str,
) {
let last_status = last_status_full.lines().next().expect("No previous status");
if last_status == status {
e.field("Status", last_status_full, true);
......@@ -291,9 +288,15 @@ async fn update_motion(
message.push(" is now ");
message.push_bold(status);
message.push_italic(format!(" (was {})", last_status));
send_message!(CONFIG.announcement_channel, &ctx.http, message.build());
let ctx = ctx.clone();
tokio::spawn(async move {
CONFIG
.announcement_channel
.say(ctx.http, message.build())
.await
});
}
};
}
if let Err(why) = msg
.edit(ctx, |m| {
......@@ -319,14 +322,14 @@ async fn update_motion(
.value;
if for_strength > (CONFIG.vote_pool_size as f32 / 2.0) {
e.colour(serenity::utils::Colour::TEAL);
update_status(e, "Passed", last_status_full, &topic);
update_status(ctx, e, "Passed", last_status_full, &topic);
} else if against_strength + abstain_strength > (CONFIG.vote_pool_size as f32 / 2.0)
{
e.colour(serenity::utils::Colour::RED);
update_status(e, "Failed", last_status_full, &topic);
update_status(ctx, e, "Failed", last_status_full, &topic);
} else {
e.colour(serenity::utils::Colour::GOLD);
update_status(e, "Under Consideration", last_status_full, &topic);
update_status(ctx, e, "Under Consideration", last_status_full, &topic);
}
e.field(
format!(
......@@ -354,7 +357,7 @@ async fn update_motion(
}
}
pub async fn reaction_add(ctx: Context, add_reaction: channel::Reaction) {
pub async fn reaction_add(ctx: &Context, add_reaction: channel::Reaction) {
let react_as_string = get_string_from_react(&add_reaction.emoji);
match add_reaction.message(&ctx.http).await {
Ok(mut message) => {
......@@ -407,8 +410,8 @@ pub async fn reaction_add(ctx: Context, add_reaction: channel::Reaction) {
vote.retain(|u| u.id != user.id);
vote.push(user.clone());
}
set_cached_motion(message.id, motion_info);
update_motion(&ctx, &mut message, &user, "add", add_reaction);
set_cached_motion(message.id, motion_info).await;
update_motion(&ctx, &mut message, &user, "add", add_reaction).await
}
Ok(false) => {
if ![
......@@ -434,7 +437,7 @@ pub async fn reaction_add(ctx: Context, add_reaction: channel::Reaction) {
}
}
pub async fn reaction_remove(ctx: Context, removed_reaction: channel::Reaction) {
pub async fn reaction_remove(ctx: &Context, removed_reaction: channel::Reaction) {
match removed_reaction.message(&ctx.http).await {
Ok(mut message) => {
if let Ok(user) = removed_reaction.user(&ctx).await {
......@@ -445,8 +448,8 @@ pub async fn reaction_remove(ctx: Context, removed_reaction: channel::Reaction)
{
vote.retain(|u| u.id != user.id);
}
set_cached_motion(message.id, motion_info);
update_motion(&ctx, &mut message, &user, "remove", removed_reaction);
set_cached_motion(message.id, motion_info).await;
update_motion(&ctx, &mut message, &user, "remove", removed_reaction).await;
}
}
Err(why) => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment