Allow up to 50 commands per message.

If the amount of commands in a single message is greater, the bot will
now return an error. Includes slight refactoring of command execution
code to make use of streams for async iter-like mapping of the command
list.

Fixes #24.
This commit is contained in:
projectmoon 2021-02-02 21:41:16 +00:00
parent 3faca6a2df
commit 7512ca0694
3 changed files with 33 additions and 17 deletions

View File

@ -6,9 +6,9 @@ use crate::error::BotError;
use crate::matrix; use crate::matrix;
use crate::state::DiceBotState; use crate::state::DiceBotState;
use dirs; use dirs;
use futures::stream::{self, StreamExt};
use log::info; use log::info;
use matrix_sdk::{self, identifiers::RoomId, Client, ClientConfig, JoinedRoom, SyncSettings}; use matrix_sdk::{self, identifiers::RoomId, Client, ClientConfig, JoinedRoom, SyncSettings};
//use matrix_sdk_common_macros::async_trait;
use std::clone::Clone; use std::clone::Clone;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -16,6 +16,10 @@ use url::Url;
pub mod event_handlers; pub mod event_handlers;
/// How many commands can be in one message. If the amount is higher
/// than this, we reject execution.
const MAX_COMMANDS_PER_MESSAGE: usize = 50;
/// The DiceBot struct represents an active dice bot. The bot is not /// The DiceBot struct represents an active dice bot. The bot is not
/// connected to Matrix until its run() function is called. /// connected to Matrix until its run() function is called.
pub struct DiceBot { pub struct DiceBot {
@ -153,25 +157,34 @@ impl DiceBot {
} }
async fn execute_commands(&self, room: &JoinedRoom, sender_username: &str, msg_body: &str) { async fn execute_commands(&self, room: &JoinedRoom, sender_username: &str, msg_body: &str) {
let room_name = room.display_name().await.ok().unwrap_or_default(); let room_name: &str = &room.display_name().await.ok().unwrap_or_default();
let room_id = room.room_id().clone(); let room_id = room.room_id().clone();
let mut results: Vec<(&str, CommandResult)> = Vec::with_capacity(msg_body.lines().count()); let commands: Vec<&str> = msg_body
.lines()
.filter(|line| line.starts_with("!"))
.collect();
let commands = msg_body.trim().lines().filter(|line| line.starts_with("!")); //Up to 50 commands allowed, otherwise we send back an error.
let results: Vec<(&str, CommandResult)> = if commands.len() < MAX_COMMANDS_PER_MESSAGE {
for command in commands { stream::iter(commands)
.then(|command| async move {
let ctx = Context { let ctx = Context {
db: self.db.clone(), db: self.db.clone(),
matrix_client: &self.client, matrix_client: &self.client,
room: RoomContext::new_with_name(&room, &room_name), room: RoomContext::new_with_name(&room, room_name),
username: &sender_username, username: &sender_username,
message_body: &command, message_body: &command,
}; };
let cmd_result = execute_command(&ctx).await; let cmd_result = execute_command(&ctx).await;
results.push((&command, cmd_result)); (command, cmd_result)
} })
.collect()
.await
} else {
vec![("", Err(ExecutionError(BotError::MessageTooLarge)))]
};
if results.len() >= 1 { if results.len() >= 1 {
if results.len() == 1 { if results.len() == 1 {

View File

@ -46,7 +46,7 @@ impl Execution {
/// provides formatting for successfully executed commands. /// provides formatting for successfully executed commands.
#[derive(Error, Debug)] #[derive(Error, Debug)]
#[error("{0}")] #[error("{0}")]
pub struct ExecutionError(#[from] BotError); pub struct ExecutionError(#[from] pub BotError);
impl From<crate::db::errors::DataError> for ExecutionError { impl From<crate::db::errors::DataError> for ExecutionError {
fn from(error: crate::db::errors::DataError) -> Self { fn from(error: crate::db::errors::DataError) -> Self {

View File

@ -69,6 +69,9 @@ pub enum BotError {
#[error("database error")] #[error("database error")]
DatabaseErrror(#[from] sled::Error), DatabaseErrror(#[from] sled::Error),
#[error("too many commands or message was too large")]
MessageTooLarge,
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]