2021-05-21 14:26:58 +00:00
|
|
|
use crate::context::Context;
|
|
|
|
use crate::db::{Rooms, Variables};
|
|
|
|
use crate::error::{BotError, DiceRollingError};
|
2020-11-30 19:53:26 +00:00
|
|
|
use crate::matrix;
|
|
|
|
use crate::models::RoomInfo;
|
2021-05-21 14:44:03 +00:00
|
|
|
use crate::parser::dice::{Amount, Element};
|
2021-05-21 14:26:58 +00:00
|
|
|
use futures::stream::{self, StreamExt, TryStreamExt};
|
2021-01-29 22:35:07 +00:00
|
|
|
use matrix_sdk::{self, identifiers::RoomId, Client};
|
2021-05-21 14:26:58 +00:00
|
|
|
use std::slice;
|
2020-11-30 19:53:26 +00:00
|
|
|
|
|
|
|
/// Record the information about a room, including users in it.
|
|
|
|
pub async fn record_room_information(
|
|
|
|
client: &Client,
|
2021-05-15 23:45:26 +00:00
|
|
|
db: &crate::db::sqlite::Database,
|
2021-01-29 22:35:07 +00:00
|
|
|
room_id: &RoomId,
|
|
|
|
room_display_name: &str,
|
2020-11-30 19:53:26 +00:00
|
|
|
our_username: &str,
|
2021-05-16 21:39:19 +00:00
|
|
|
) -> Result<(), BotError> {
|
|
|
|
//Clear out any old room info first.
|
|
|
|
db.clear_info(room_id.as_str()).await?;
|
|
|
|
|
2021-01-29 22:35:07 +00:00
|
|
|
let room_id_str = room_id.as_str();
|
2021-05-16 21:39:19 +00:00
|
|
|
let usernames = matrix::get_users_in_room(&client, &room_id).await?;
|
2020-11-30 19:53:26 +00:00
|
|
|
|
|
|
|
let info = RoomInfo {
|
|
|
|
room_id: room_id_str.to_owned(),
|
2021-01-29 22:35:07 +00:00
|
|
|
room_name: room_display_name.to_owned(),
|
2020-11-30 19:53:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO this and the username adding should be one whole
|
|
|
|
// transaction in the db.
|
2021-05-15 23:45:26 +00:00
|
|
|
db.insert_room_info(&info).await?;
|
2020-11-30 19:53:26 +00:00
|
|
|
|
2021-05-15 23:45:26 +00:00
|
|
|
let filtered_usernames = usernames
|
2020-11-30 19:53:26 +00:00
|
|
|
.into_iter()
|
2021-05-15 23:45:26 +00:00
|
|
|
.filter(|username| username != our_username);
|
|
|
|
|
|
|
|
// Async collect into vec of results, then use into_iter of result
|
|
|
|
// to go to from Result<Vec<()>> to just Result<()>. Easier than
|
|
|
|
// attempting to async-collect our way to a single Result<()>.
|
|
|
|
stream::iter(filtered_usernames)
|
2021-05-16 21:39:19 +00:00
|
|
|
.then(|username| async move {
|
|
|
|
db.add_user_to_room(&username, &room_id_str)
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.into())
|
|
|
|
})
|
|
|
|
.collect::<Vec<Result<(), BotError>>>()
|
2021-05-15 23:45:26 +00:00
|
|
|
.await
|
|
|
|
.into_iter()
|
|
|
|
.collect()
|
2020-11-30 19:53:26 +00:00
|
|
|
}
|
2021-05-21 14:26:58 +00:00
|
|
|
|
|
|
|
/// Calculate the amount of dice to roll by consulting the database
|
|
|
|
/// and replacing variables with corresponding the amount. Errors out
|
|
|
|
/// if it cannot find a variable defined, or if the database errors.
|
|
|
|
pub async fn calculate_single_die_amount(
|
|
|
|
amount: &Amount,
|
|
|
|
ctx: &Context<'_>,
|
|
|
|
) -> Result<i32, BotError> {
|
|
|
|
calculate_dice_amount(slice::from_ref(amount), ctx).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Calculate the amount of dice to roll by consulting the database
|
|
|
|
/// and replacing variables with corresponding amounts. Errors out if
|
|
|
|
/// it cannot find a variable defined, or if the database errors.
|
|
|
|
pub async fn calculate_dice_amount(amounts: &[Amount], ctx: &Context<'_>) -> Result<i32, BotError> {
|
|
|
|
let stream = stream::iter(amounts);
|
|
|
|
let variables = &ctx
|
|
|
|
.db
|
|
|
|
.get_user_variables(&ctx.username, ctx.room_id().as_str())
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
use DiceRollingError::VariableNotFound;
|
|
|
|
let dice_amount: i32 = stream
|
|
|
|
.then(|amount| async move {
|
|
|
|
match &amount.element {
|
|
|
|
Element::Number(num_dice) => Ok(num_dice * amount.operator.mult()),
|
|
|
|
Element::Variable(variable) => variables
|
|
|
|
.get(variable)
|
|
|
|
.ok_or_else(|| VariableNotFound(variable.clone()))
|
|
|
|
.map(|i| *i),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.try_fold(0, |total, num_dice| async move { Ok(total + num_dice) })
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(dice_amount)
|
|
|
|
}
|