feat: add webhook notification system with Settings UI (REMOTE-03)
Webhook module with HTTP delivery, HMAC-SHA256 signing, and event filtering. RPC handlers for get-config, configure, and test endpoints. Settings page gains webhook configuration section with URL, secret, event toggles, and test button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ mod system;
|
||||
mod update;
|
||||
mod vpn;
|
||||
mod wallet;
|
||||
mod webhooks;
|
||||
|
||||
use crate::auth::AuthManager;
|
||||
use crate::config::Config;
|
||||
@@ -490,6 +491,11 @@ impl RpcHandler {
|
||||
self.handle_security_list_expiring(&p).await
|
||||
}
|
||||
|
||||
// Webhooks
|
||||
"webhook.get-config" => self.handle_webhook_get_config().await,
|
||||
"webhook.configure" => self.handle_webhook_configure(params).await,
|
||||
"webhook.test" => self.handle_webhook_test().await,
|
||||
|
||||
_ => {
|
||||
Err(anyhow::anyhow!("Unknown method: {}", rpc_req.method))
|
||||
}
|
||||
|
||||
83
core/archipelago/src/api/rpc/webhooks.rs
Normal file
83
core/archipelago/src/api/rpc/webhooks.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use super::RpcHandler;
|
||||
use crate::webhooks;
|
||||
use anyhow::Result;
|
||||
use tracing::info;
|
||||
|
||||
impl RpcHandler {
|
||||
/// webhook.get-config — Get current webhook configuration.
|
||||
pub(super) async fn handle_webhook_get_config(&self) -> Result<serde_json::Value> {
|
||||
let config = webhooks::load_config(&self.config.data_dir).await?;
|
||||
Ok(serde_json::json!({
|
||||
"enabled": config.enabled,
|
||||
"url": config.url,
|
||||
"events": config.events,
|
||||
"has_secret": config.secret.is_some(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// webhook.configure — Update webhook configuration.
|
||||
pub(super) async fn handle_webhook_configure(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.ok_or_else(|| anyhow::anyhow!("Missing params"))?;
|
||||
|
||||
let mut config = webhooks::load_config(&self.config.data_dir).await?;
|
||||
|
||||
if let Some(enabled) = params.get("enabled").and_then(|v| v.as_bool()) {
|
||||
config.enabled = enabled;
|
||||
}
|
||||
if let Some(url) = params.get("url").and_then(|v| v.as_str()) {
|
||||
config.url = url.to_string();
|
||||
}
|
||||
if let Some(secret) = params.get("secret").and_then(|v| v.as_str()) {
|
||||
config.secret = if secret.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(secret.to_string())
|
||||
};
|
||||
}
|
||||
if let Some(events) = params.get("events") {
|
||||
if let Ok(parsed) = serde_json::from_value::<Vec<webhooks::WebhookEvent>>(events.clone())
|
||||
{
|
||||
config.events = parsed;
|
||||
}
|
||||
}
|
||||
|
||||
webhooks::save_config(&self.config.data_dir, &config).await?;
|
||||
info!("Webhook config updated: enabled={}, url={}", config.enabled, config.url);
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"configured": true,
|
||||
"enabled": config.enabled,
|
||||
"url": config.url,
|
||||
}))
|
||||
}
|
||||
|
||||
/// webhook.test — Send a test webhook notification.
|
||||
pub(super) async fn handle_webhook_test(&self) -> Result<serde_json::Value> {
|
||||
let config = webhooks::load_config(&self.config.data_dir).await?;
|
||||
if !config.enabled || config.url.is_empty() {
|
||||
anyhow::bail!("Webhook is not configured. Set a URL and enable it first.");
|
||||
}
|
||||
|
||||
let payload = webhooks::WebhookPayload {
|
||||
event: webhooks::WebhookEvent::ContainerCrash,
|
||||
title: "Test Notification".to_string(),
|
||||
message: "This is a test webhook from your Archipelago node.".to_string(),
|
||||
timestamp: chrono::Utc::now().to_rfc3339(),
|
||||
node_id: {
|
||||
let (data, _) = self.state_manager.get_snapshot().await;
|
||||
data.server_info.id
|
||||
},
|
||||
details: Some(serde_json::json!({"test": true})),
|
||||
};
|
||||
|
||||
webhooks::send_webhook(&self.config.data_dir, payload).await;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"sent": true,
|
||||
"url": config.url,
|
||||
}))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user