catch panic from admin commands
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
0627b46f40
commit
61f2a3c68b
3 changed files with 36 additions and 12 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -613,6 +613,7 @@ dependencies = [
|
||||||
"conduit_api",
|
"conduit_api",
|
||||||
"conduit_core",
|
"conduit_core",
|
||||||
"conduit_service",
|
"conduit_service",
|
||||||
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"ruma",
|
"ruma",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -30,6 +30,7 @@ clap.workspace = true
|
||||||
conduit-api.workspace = true
|
conduit-api.workspace = true
|
||||||
conduit-core.workspace = true
|
conduit-core.workspace = true
|
||||||
conduit-service.workspace = true
|
conduit-service.workspace = true
|
||||||
|
futures-util.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
ruma.workspace = true
|
ruma.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
use std::time::Instant;
|
use std::{panic::AssertUnwindSafe, time::Instant};
|
||||||
|
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use conduit::trace;
|
use conduit::{error, trace, Error};
|
||||||
use ruma::events::{
|
use futures_util::future::FutureExt;
|
||||||
relation::InReplyTo,
|
use ruma::{
|
||||||
room::message::{Relation::Reply, RoomMessageEventContent},
|
events::{
|
||||||
|
relation::InReplyTo,
|
||||||
|
room::message::{Relation::Reply, RoomMessageEventContent},
|
||||||
|
},
|
||||||
|
OwnedEventId,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern crate conduit_service as service;
|
extern crate conduit_service as service;
|
||||||
|
@ -69,21 +73,39 @@ pub(crate) fn complete(line: &str) -> String { complete_admin_command(AdminComma
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, name = "admin")]
|
#[tracing::instrument(skip_all, name = "admin")]
|
||||||
async fn handle_command(command: Command) -> CommandResult {
|
async fn handle_command(command: Command) -> CommandResult {
|
||||||
let Some(mut content) = process_admin_message(command.command).await else {
|
AssertUnwindSafe(process_command(&command))
|
||||||
return Ok(None);
|
.catch_unwind()
|
||||||
};
|
.await
|
||||||
|
.map_err(Error::from_panic)
|
||||||
|
.or_else(|error| handle_panic(&error, command))
|
||||||
|
}
|
||||||
|
|
||||||
content.relates_to = command.reply_id.map(|event_id| Reply {
|
async fn process_command(command: &Command) -> CommandOutput {
|
||||||
|
process_admin_message(&command.command)
|
||||||
|
.await
|
||||||
|
.and_then(|content| reply(content, command.reply_id.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_panic(error: &Error, command: Command) -> CommandResult {
|
||||||
|
let link = "Please submit a [bug report](https://github.com/girlbossceo/conduwuit/issues/new). 🥺";
|
||||||
|
let msg = format!("Panic occurred while processing command:\n```\n{error:#?}\n```\n{link}");
|
||||||
|
let content = RoomMessageEventContent::notice_markdown(msg);
|
||||||
|
error!("Panic while processing command: {error:?}");
|
||||||
|
Ok(reply(content, command.reply_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reply(mut content: RoomMessageEventContent, reply_id: Option<OwnedEventId>) -> Option<RoomMessageEventContent> {
|
||||||
|
content.relates_to = reply_id.map(|event_id| Reply {
|
||||||
in_reply_to: InReplyTo {
|
in_reply_to: InReplyTo {
|
||||||
event_id,
|
event_id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Some(content))
|
Some(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and process a message from the admin room
|
// Parse and process a message from the admin room
|
||||||
async fn process_admin_message(msg: String) -> CommandOutput {
|
async fn process_admin_message(msg: &str) -> CommandOutput {
|
||||||
let mut lines = msg.lines().filter(|l| !l.trim().is_empty());
|
let mut lines = msg.lines().filter(|l| !l.trim().is_empty());
|
||||||
let command = lines.next().expect("each string has at least one line");
|
let command = lines.next().expect("each string has at least one line");
|
||||||
let body = lines.collect::<Vec<_>>();
|
let body = lines.collect::<Vec<_>>();
|
||||||
|
@ -103,7 +125,7 @@ async fn process_admin_message(msg: String) -> CommandOutput {
|
||||||
match result {
|
match result {
|
||||||
Ok(reply) => Some(reply),
|
Ok(reply) => Some(reply),
|
||||||
Err(error) => Some(RoomMessageEventContent::notice_markdown(format!(
|
Err(error) => Some(RoomMessageEventContent::notice_markdown(format!(
|
||||||
"Encountered an error while handling the command:\n```\n{error}\n```"
|
"Encountered an error while handling the command:\n```\n{error:#?}\n```"
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue