1use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct WebhookStatus {
14 pub configured: bool,
16 pub port: Option<u16>,
18 pub healthy: bool,
20 pub fallback_mode: bool,
22 pub last_check_utc: Option<DateTime<Utc>>,
24 pub last_failure_reason: Option<String>,
26 pub startup_attempts: u32,
28}
29
30impl Default for WebhookStatus {
31 fn default() -> Self {
32 Self {
33 configured: false,
34 port: None,
35 healthy: false,
36 fallback_mode: true,
37 last_check_utc: None,
38 last_failure_reason: None,
39 startup_attempts: 0,
40 }
41 }
42}
43
44pub fn status_path() -> anyhow::Result<PathBuf> {
46 Ok(crate::home::orch_home()?.join("webhook_status.json"))
47}
48
49impl WebhookStatus {
50 pub async fn save(&self) {
52 match status_path().and_then(|p| {
53 serde_json::to_string_pretty(self)
54 .map(|j| (p, j))
55 .map_err(anyhow::Error::from)
56 }) {
57 Ok((p, json)) => {
58 if let Err(e) = tokio::fs::write(&p, json).await {
59 tracing::warn!(error = ?e, "failed to persist webhook status");
60 }
61 }
62 Err(e) => tracing::warn!(?e, "failed to persist webhook status"),
63 }
64 }
65
66 pub fn load() -> Option<Self> {
69 let path = status_path().ok()?;
70 let json = std::fs::read_to_string(path).ok()?;
71 serde_json::from_str(&json).ok()
72 }
73}