aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-01-19 22:31:41 -0600
committerNathan Ringo <nathan@remexre.com>2024-01-19 22:31:41 -0600
commite9ce0f5ca752f044716c17384bd7ef2486d74805 (patch)
treee848073b6e939884bcc607f7182446311122d41e /src
parentd9e3caab5ed77eff9263c416b457f110b1f29ace (diff)
Fix interactions with button responses.
Diffstat (limited to 'src')
-rw-r--r--src/commands/discocaml.rs125
-rw-r--r--src/commands/mod.rs22
2 files changed, 66 insertions, 81 deletions
diff --git a/src/commands/discocaml.rs b/src/commands/discocaml.rs
index 2c34c81..ed00185 100644
--- a/src/commands/discocaml.rs
+++ b/src/commands/discocaml.rs
@@ -6,8 +6,8 @@ use serde_json::de::Deserializer;
use serenity::{
all::{
CommandDataOptionValue, CommandInteraction, CommandOptionType, CommandType,
- ComponentInteraction, ComponentInteractionDataKind, InteractionId,
- InteractionResponseFlags, Member, RoleId,
+ ComponentInteraction, ComponentInteractionDataKind, InteractionResponseFlags, Member,
+ RoleId,
},
builder::{
CreateAttachment, CreateButton, CreateCommand, CreateCommandOption, CreateEmbed,
@@ -89,16 +89,15 @@ pub struct DiscocamlResponseExpr {
}
impl DiscocamlResponseExpr {
- async fn save(&self, db: &SqlitePool, id: InteractionId) -> Result<()> {
- let interaction_id = i64::from(id);
- sqlx::query!(
- "INSERT INTO discocaml_exprs (interaction_id, expr) VALUES (?, ?)",
- interaction_id,
+ async fn save(&self, db: &SqlitePool) -> Result<i64> {
+ let out = sqlx::query!(
+ "INSERT INTO discocaml_exprs (expr) VALUES (?) RETURNING rowid",
self.expr
)
- .execute(db)
- .await?;
- Ok(())
+ .fetch_one(db)
+ .await
+ .context("failed to save expression to database")?;
+ Ok(out.rowid)
}
}
@@ -174,7 +173,6 @@ async fn respond_with_error<E: std::error::Error, F: Future<Output = Result<(),
async fn respond_with<E, F>(
db: &SqlitePool,
- interaction_id: InteractionId,
res: DiscocamlResponse,
send: impl FnOnce(CreateInteractionResponse) -> F,
) -> Result<()>
@@ -185,17 +183,16 @@ where
match res {
DiscocamlResponse::Expr(expr) => {
// Insert the output expression in the database.
- if let Err(err) = expr
- .save(db, interaction_id)
- .await
- .context("failed to save expression to database")
- {
- respond_with_error(&err, send).await;
- return Err(err);
- }
+ let rowid = match expr.save(db).await {
+ Ok(rowid) => rowid,
+ Err(err) => {
+ respond_with_error(&err, send).await;
+ return Err(err);
+ }
+ };
// Respond with the expression and the buttons.
- let res = expr_response_message(&expr);
+ let res = expr_response_message(&expr, rowid);
send(CreateInteractionResponse::Message(res)).await?;
Ok(())
}
@@ -293,7 +290,10 @@ async fn run_dot(dot: &str) -> Result<BString> {
Ok(BString::new(output.stdout))
}
-fn expr_response_message(expr: &DiscocamlResponseExpr) -> CreateInteractionResponseMessage {
+fn expr_response_message(
+ expr: &DiscocamlResponseExpr,
+ rowid: i64,
+) -> CreateInteractionResponseMessage {
let mut msg = String::new();
if let Some(note) = &expr.note {
msg.push_str(note);
@@ -306,24 +306,24 @@ fn expr_response_message(expr: &DiscocamlResponseExpr) -> CreateInteractionRespo
CreateInteractionResponseMessage::new()
.content(msg)
- .button(CreateButton::new("draw-tree").label("Draw Tree"))
+ .button(CreateButton::new(format!("discocaml-draw-tree/{}", rowid)).label("Draw Tree"))
.button(
- CreateButton::new("step-cbv")
+ CreateButton::new(format!("discocaml-step-cbv/{}", rowid))
.label("Step (CBV)")
.disabled(!expr.has_redex),
)
.button(
- CreateButton::new("step-cbn")
+ CreateButton::new(format!("discocaml-step-cbn/{}", rowid))
.label("Step (CBN)")
.disabled(!expr.has_redex),
)
.button(
- CreateButton::new("run-cbv")
+ CreateButton::new(format!("discocaml-run-cbv/{}", rowid))
.label("Run (CBV)")
.disabled(!expr.has_redex),
)
.button(
- CreateButton::new("run-cbn")
+ CreateButton::new(format!("discocaml-run-cbn/{}", rowid))
.label("Run (CBN)")
.disabled(!expr.has_redex),
)
@@ -375,10 +375,7 @@ pub async fn handle_command(
};
// Respond with the resulting expression.
- respond_with(db, command.id, res, |res| {
- command.create_response(&ctx, res)
- })
- .await
+ respond_with(db, res, |res| command.create_response(&ctx, res)).await
}
pub async fn handle_button(
@@ -393,43 +390,42 @@ pub async fn handle_button(
return Err(err.context("permissions check failed"));
}
- // Find the interaction ID from the message it was in response to.
- let interaction_id = if let Some(interaction) = &component.message.interaction {
- i64::from(interaction.id)
- } else {
- let err = anyhow!(
- "button was pressed in response to an unknown message {:?}",
- component.message.id
- );
- respond_with_error(&err, |res| component.create_response(&ctx, res)).await;
- return Err(err);
- };
-
- // Fetch the expression it was in response to.
- let result = sqlx::query!(
- "SELECT expr FROM discocaml_exprs WHERE interaction_id = ?",
- interaction_id,
- )
- .fetch_one(db)
- .await
- .context("failed to load expression from database");
- let expr = match result {
- Ok(expr) => expr.expr,
- Err(err) => {
+ // Come up with a command for discocaml based on which button was clicked.
+ let (command, id) = match &component.data.kind {
+ ComponentInteractionDataKind::Button => {
+ let custom_id = &component.data.custom_id;
+ if let Some(id_str) = custom_id.strip_prefix("discocaml-draw-tree/") {
+ (DiscocamlCommand::DrawTree, id_str)
+ } else if let Some(id_str) = custom_id.strip_prefix("discocaml-step-cbv/") {
+ (DiscocamlCommand::StepCBV, id_str)
+ } else if let Some(id_str) = custom_id.strip_prefix("discocaml-step-cbn/") {
+ (DiscocamlCommand::StepCBN, id_str)
+ } else if let Some(id_str) = custom_id.strip_prefix("discocaml-run-cbv/") {
+ (DiscocamlCommand::RunCBV, id_str)
+ } else if let Some(id_str) = custom_id.strip_prefix("discocaml-run-cbn/") {
+ (DiscocamlCommand::RunCBN, id_str)
+ } else {
+ let err = anyhow!("unknown component {:?}", component.data);
+ respond_with_error(&err, |res| component.create_response(&ctx, res)).await;
+ return Err(err);
+ }
+ }
+ _ => {
+ let err = anyhow!("unknown component {:?}", component.data);
respond_with_error(&err, |res| component.create_response(&ctx, res)).await;
return Err(err);
}
};
- // Come up with a command for discocaml based on which button it was.
- let command = match (&component.data.kind, &component.data.custom_id as &str) {
- (ComponentInteractionDataKind::Button, "draw-tree") => DiscocamlCommand::DrawTree,
- (ComponentInteractionDataKind::Button, "step-cbv") => DiscocamlCommand::StepCBV,
- (ComponentInteractionDataKind::Button, "step-cbn") => DiscocamlCommand::StepCBN,
- (ComponentInteractionDataKind::Button, "run-cbv") => DiscocamlCommand::RunCBV,
- (ComponentInteractionDataKind::Button, "run-cbn") => DiscocamlCommand::RunCBN,
- _ => {
- let err = anyhow!("unknown component {:?}", component.data);
+ // Parse the ID, and fetch the corresponding expr.
+ let id: i64 = id.parse().context("failed to parse id")?;
+ let result = sqlx::query!("SELECT expr FROM discocaml_exprs WHERE rowid = ?", id)
+ .fetch_one(db)
+ .await
+ .context("failed to load expression from database");
+ let expr = match result {
+ Ok(expr) => expr.expr,
+ Err(err) => {
respond_with_error(&err, |res| component.create_response(&ctx, res)).await;
return Err(err);
}
@@ -446,8 +442,5 @@ pub async fn handle_button(
};
// Respond.
- respond_with(db, component.id, res, |res| {
- component.create_response(&ctx, res)
- })
- .await
+ respond_with(db, res, |res| component.create_response(&ctx, res)).await
}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index d793c95..f51a3e2 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -39,21 +39,13 @@ pub async fn handle_interaction(
}
},
Interaction::Component(component) => {
- match component
- .message
- .interaction
- .as_ref()
- .map(|i| &i.name as &str)
- {
- Some("discocaml") => {
- discocaml::handle_button(ctx, &config.discocaml, db, component)
- .await
- .context("failed to handle discocaml command")
- }
- _ => {
- log::warn!("unexpected interaction: {:#?}", interaction);
- Ok(())
- }
+ if component.data.custom_id.starts_with("discocaml-") {
+ discocaml::handle_button(ctx, &config.discocaml, db, component)
+ .await
+ .context("failed to handle discocaml command")
+ } else {
+ log::warn!("unexpected interaction: {:#?}", interaction);
+ Ok(())
}
}