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