use warp::{ Filter, Reply, filters::BoxedFilter, http::Uri, }; use crate::app::{ State, config::{CommandExecutor, Command, Cooldowns}, web::{ CustomRejection, template::commands::{CommandsTemplate, AddCommandTemplate}, }, }; use std::{ collections::HashMap, convert::Infallible, sync::Arc, }; pub fn commands_routes(state: Arc) -> BoxedFilter<(impl Reply, )> { warp::get() .and( commands_get(Arc::clone(&state)) .or(commands_add_get()) ) .or(warp::post().and( commands_add_post(Arc::clone(&state)) .or(commands_delete_post(Arc::clone(&state))) )) .boxed() } fn commands_get(state: Arc) -> BoxedFilter<(impl Reply, )> { warp::path("commands") .and(warp::path::end()) .and_then(move || { let state = Arc::clone(&state); async move { Result::::Ok(CommandsTemplate { commands: state.config.read().await.commands.clone(), }) } }) .boxed() } fn commands_add_get() -> BoxedFilter<(impl Reply, )> { warp::path("commands") .and(warp::path("add")) .and(warp::path::end()) .map(|| AddCommandTemplate) .boxed() } fn commands_add_post(state: Arc) -> BoxedFilter<(impl Reply, )> { warp::path("commands") .and(warp::path("add")) .and(warp::path::end()) .and(warp::body::content_length_limit(1024 * 5)) .and(warp::body::form()) .and_then(move |mut form: HashMap| { let state = Arc::clone(&state); async move { let form_get = try { let name = form.remove("name")?; let aliases = form.remove("aliases")?; let kind = form.remove("type")?; let script = form.remove("executor_data")?; (name, aliases, kind, script) }; let (name, aliases, kind, script) = match form_get { Some(x) => x, None => return Err(warp::reject::custom(CustomRejection::InvalidForm)), }; let executor = match &*kind { "Text" => CommandExecutor::Text(script), "Rhai" => CommandExecutor::Rhai(script), _ => return Err(warp::reject::custom(CustomRejection::InvalidForm)), }; let command = Command { name, executor, aliases: aliases.split("\n").map(|x| x.trim().to_string()).filter(|x| !x.is_empty()).collect(), cooldowns: Cooldowns::default(), }; state.config.write().await.commands.push(command); Ok(warp::redirect(Uri::from_static("/commands"))) } }) .boxed() } fn commands_delete_post(state: Arc) -> BoxedFilter<(impl Reply, )> { warp::path("commands") .and(warp::path("delete")) .and(warp::path::end()) .and(warp::body::content_length_limit(1024 * 5)) .and(warp::body::form()) .and_then(move |mut form: HashMap| { let state = Arc::clone(&state); async move { let name = match form.remove("name") { Some(n) => n, None => return Err(warp::reject::custom(CustomRejection::InvalidForm)), }; state.config.write().await.commands.drain_filter(|command| command.name == name); Ok(warp::redirect(Uri::from_static("/commands"))) } }) .boxed() }