diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/discocaml.rs | 125 | ||||
-rw-r--r-- | src/commands/mod.rs | 22 |
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(()) } } |