feat: script test command
This commit is contained in:
parent
e739c443ac
commit
f3eb1dc188
3 changed files with 158 additions and 8 deletions
|
|
@ -1,7 +1,12 @@
|
||||||
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use serenity::all::{
|
use serenity::all::{
|
||||||
CommandInteraction, CommandOptionType, Context, CreateCommand, CreateCommandOption,
|
CommandInteraction, CommandOptionType, CommandType, Context, CreateCommand,
|
||||||
CreateInputText, CreateLabel, CreateModal, CreateModalComponent, CreateTextDisplay,
|
CreateCommandOption, CreateComponent, CreateContainer, CreateContainerComponent,
|
||||||
InputTextStyle, Permissions,
|
CreateInputText, CreateInteractionResponseMessage, CreateLabel, CreateModal,
|
||||||
|
CreateModalComponent, CreateTextDisplay, InputTextStyle, MessageFlags, Permissions,
|
||||||
|
ResolvedTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::handler::{Handler, get_guild};
|
use crate::handler::{Handler, get_guild};
|
||||||
|
|
@ -17,6 +22,13 @@ pub fn config_command() -> CreateCommand<'static> {
|
||||||
.default_member_permissions(Permissions::ADMINISTRATOR)
|
.default_member_permissions(Permissions::ADMINISTRATOR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn script_test_command() -> CreateCommand<'static> {
|
||||||
|
CreateCommand::new("test_script")
|
||||||
|
.name_localized("ko", "스크립트 테스트")
|
||||||
|
.kind(CommandType::Message)
|
||||||
|
.default_member_permissions(Permissions::ADMINISTRATOR)
|
||||||
|
}
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
pub async fn process_starboard_command(
|
pub async fn process_starboard_command(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -27,6 +39,26 @@ impl Handler {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !interaction
|
||||||
|
.member
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|x| x.permissions)
|
||||||
|
.map(|x| x.contains(Permissions::ADMINISTRATOR))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
interaction
|
||||||
|
.create_response(
|
||||||
|
&ctx.http,
|
||||||
|
serenity::all::CreateInteractionResponse::Message(
|
||||||
|
CreateInteractionResponseMessage::new()
|
||||||
|
.content("관리자 권한이 필요합니다")
|
||||||
|
.ephemeral(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
// if let CommandType interaction.data.kind {}
|
// if let CommandType interaction.data.kind {}
|
||||||
|
|
||||||
for option in interaction.data.options() {
|
for option in interaction.data.options() {
|
||||||
|
|
@ -72,4 +104,102 @@ if reactions["⭐"] >= 3 {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn process_script_test_command(
|
||||||
|
&self,
|
||||||
|
ctx: &Context,
|
||||||
|
interaction: &CommandInteraction,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let Some(guild_id) = interaction.guild_id else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if !interaction
|
||||||
|
.member
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|x| x.permissions)
|
||||||
|
.map(|x| x.contains(Permissions::ADMINISTRATOR))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
interaction
|
||||||
|
.create_response(
|
||||||
|
&ctx.http,
|
||||||
|
serenity::all::CreateInteractionResponse::Message(
|
||||||
|
CreateInteractionResponseMessage::new()
|
||||||
|
.content("관리자 권한이 필요합니다")
|
||||||
|
.ephemeral(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = interaction.data.target();
|
||||||
|
|
||||||
|
let target_message = target
|
||||||
|
.and_then(|x| match x {
|
||||||
|
ResolvedTarget::Message(msg) => Some(msg),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow!("no target message"))?;
|
||||||
|
|
||||||
|
let script = get_guild(&self.db, guild_id)
|
||||||
|
.await?
|
||||||
|
.and_then(|x| x.script)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
|
||||||
|
let channel = interaction
|
||||||
|
.channel
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| anyhow!("no channel data"))?;
|
||||||
|
|
||||||
|
let channel = ctx.http.get_channel(channel.id()).await?;
|
||||||
|
|
||||||
|
debug!("selected message: {target_message:?}");
|
||||||
|
|
||||||
|
let reactions: HashMap<String, i64> = target_message
|
||||||
|
.reactions
|
||||||
|
.iter()
|
||||||
|
.map(|x| (x.reaction_type.to_string(), x.count as i64))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let (result, buffer) = paringboard::script::check(
|
||||||
|
&script,
|
||||||
|
reactions,
|
||||||
|
interaction.channel_id.to_string(),
|
||||||
|
channel
|
||||||
|
.guild()
|
||||||
|
.and_then(|x| x.parent_id)
|
||||||
|
.map(|x| x.to_string()),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|err| (None, format!("run failed: {err:?}")));
|
||||||
|
|
||||||
|
interaction
|
||||||
|
.create_response(
|
||||||
|
&ctx.http,
|
||||||
|
serenity::all::CreateInteractionResponse::Message(
|
||||||
|
CreateInteractionResponseMessage::new()
|
||||||
|
.flags(MessageFlags::IS_COMPONENTS_V2)
|
||||||
|
.components(vec![
|
||||||
|
CreateComponent::Container(
|
||||||
|
// result text
|
||||||
|
CreateContainer::new(vec![CreateContainerComponent::TextDisplay(
|
||||||
|
CreateTextDisplay::new(format!(
|
||||||
|
"## Result \n```rs\n{result:?}\n```"
|
||||||
|
)),
|
||||||
|
)]),
|
||||||
|
),
|
||||||
|
CreateComponent::Container(CreateContainer::new(vec![
|
||||||
|
CreateContainerComponent::TextDisplay(CreateTextDisplay::new(
|
||||||
|
format!("## Console Output \n```rs\n{}\n```", &buffer),
|
||||||
|
)),
|
||||||
|
])),
|
||||||
|
])
|
||||||
|
.ephemeral(true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,10 @@ impl EventHandler for Handler {
|
||||||
|
|
||||||
if let Err(e) = context
|
if let Err(e) = context
|
||||||
.http
|
.http
|
||||||
.create_global_commands(&vec![commands::config_command()])
|
.create_global_commands(&vec![
|
||||||
|
commands::config_command(),
|
||||||
|
commands::script_test_command(),
|
||||||
|
])
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
error!("Failed to register config command: {e:?}");
|
error!("Failed to register config command: {e:?}");
|
||||||
|
|
@ -108,6 +111,11 @@ impl Handler {
|
||||||
if command.data.name == "starboard" {
|
if command.data.name == "starboard" {
|
||||||
self.process_starboard_command(ctx, command).await?;
|
self.process_starboard_command(ctx, command).await?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if command.data.name == "test_script" {
|
||||||
|
self.process_script_test_command(ctx, command).await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,6 +172,7 @@ impl Handler {
|
||||||
.and_then(|x| x.parent_id)
|
.and_then(|x| x.parent_id)
|
||||||
.map(|x| x.to_string()),
|
.map(|x| x.to_string()),
|
||||||
)
|
)
|
||||||
|
.map(|x| x.0)
|
||||||
.inspect_err(|res| {
|
.inspect_err(|res| {
|
||||||
error!("check failed: {res:?}");
|
error!("check failed: {res:?}");
|
||||||
})?
|
})?
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use rhai::{Dynamic, Engine, Map, Scope};
|
use rhai::{Dynamic, Engine, Map, Scope};
|
||||||
|
|
@ -17,9 +20,10 @@ pub fn check(
|
||||||
reactions: HashMap<String, i64>,
|
reactions: HashMap<String, i64>,
|
||||||
channel: String,
|
channel: String,
|
||||||
category: Option<String>,
|
category: Option<String>,
|
||||||
) -> anyhow::Result<Option<ReactionResult>> {
|
) -> anyhow::Result<(Option<ReactionResult>, String)> {
|
||||||
debug!("script: {script}");
|
debug!("script: {script}");
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
let buffer = Arc::new(RwLock::new(String::new()));
|
||||||
engine.set_max_operations(1000);
|
engine.set_max_operations(1000);
|
||||||
engine.register_type::<ReactionResult>();
|
engine.register_type::<ReactionResult>();
|
||||||
engine.register_fn("result", |webhook_url: String, count: i64, icon: String| {
|
engine.register_fn("result", |webhook_url: String, count: i64, icon: String| {
|
||||||
|
|
@ -30,6 +34,8 @@ pub fn check(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let logger = buffer.clone();
|
||||||
|
|
||||||
engine
|
engine
|
||||||
.disable_symbol("for")
|
.disable_symbol("for")
|
||||||
.disable_symbol("while")
|
.disable_symbol("while")
|
||||||
|
|
@ -37,7 +43,10 @@ pub fn check(
|
||||||
.set_max_expr_depths(50, 5)
|
.set_max_expr_depths(50, 5)
|
||||||
.set_max_string_size(60)
|
.set_max_string_size(60)
|
||||||
.set_max_map_size(512)
|
.set_max_map_size(512)
|
||||||
.set_max_array_size(512);
|
.set_max_array_size(512)
|
||||||
|
.on_print(move |line| {
|
||||||
|
logger.write().unwrap().push_str(line);
|
||||||
|
});
|
||||||
|
|
||||||
let mut emotes_input = Map::new();
|
let mut emotes_input = Map::new();
|
||||||
for (emoji, count) in reactions {
|
for (emoji, count) in reactions {
|
||||||
|
|
@ -57,6 +66,8 @@ pub fn check(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
debug!("current scope: {scope:?}");
|
||||||
|
|
||||||
let result: Dynamic = engine
|
let result: Dynamic = engine
|
||||||
.eval_with_scope(&mut scope, script)
|
.eval_with_scope(&mut scope, script)
|
||||||
.map_err(|e| anyhow!("{e:?}"))?;
|
.map_err(|e| anyhow!("{e:?}"))?;
|
||||||
|
|
@ -73,5 +84,5 @@ pub fn check(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(result);
|
return Ok((result, buffer.read().unwrap().to_string()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue