Skip to main content

devsper_core/
events.rs

1use crate::types::{GraphMutation, GraphSnapshot, NodeId, NodeSpec, RunId};
2use serde::{Deserialize, Serialize};
3
4/// All events that can occur in a graph's lifecycle
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub enum GraphEvent {
7    NodeAdded {
8        id: NodeId,
9        spec: NodeSpec,
10        ts: u64,
11    },
12    NodeReady {
13        id: NodeId,
14        ts: u64,
15    },
16    NodeStarted {
17        id: NodeId,
18        ts: u64,
19    },
20    NodeCompleted {
21        id: NodeId,
22        result: serde_json::Value,
23        ts: u64,
24    },
25    NodeFailed {
26        id: NodeId,
27        error: String,
28        ts: u64,
29    },
30    NodeAbandoned {
31        id: NodeId,
32        ts: u64,
33    },
34    EdgeAdded {
35        from: NodeId,
36        to: NodeId,
37        ts: u64,
38    },
39    EdgeRemoved {
40        from: NodeId,
41        to: NodeId,
42        ts: u64,
43    },
44    MutationApplied {
45        mutation: GraphMutation,
46        ts: u64,
47    },
48    MutationRejected {
49        reason: String,
50        ts: u64,
51    },
52    SnapshotTaken {
53        snapshot: GraphSnapshot,
54        ts: u64,
55    },
56    RunStarted {
57        run_id: RunId,
58        ts: u64,
59    },
60    RunCompleted {
61        run_id: RunId,
62        ts: u64,
63    },
64    RunFailed {
65        run_id: RunId,
66        error: String,
67        ts: u64,
68    },
69}
70
71impl GraphEvent {
72    pub fn ts(&self) -> u64 {
73        match self {
74            GraphEvent::NodeAdded { ts, .. } => *ts,
75            GraphEvent::NodeReady { ts, .. } => *ts,
76            GraphEvent::NodeStarted { ts, .. } => *ts,
77            GraphEvent::NodeCompleted { ts, .. } => *ts,
78            GraphEvent::NodeFailed { ts, .. } => *ts,
79            GraphEvent::NodeAbandoned { ts, .. } => *ts,
80            GraphEvent::EdgeAdded { ts, .. } => *ts,
81            GraphEvent::EdgeRemoved { ts, .. } => *ts,
82            GraphEvent::MutationApplied { ts, .. } => *ts,
83            GraphEvent::MutationRejected { ts, .. } => *ts,
84            GraphEvent::SnapshotTaken { ts, .. } => *ts,
85            GraphEvent::RunStarted { ts, .. } => *ts,
86            GraphEvent::RunCompleted { ts, .. } => *ts,
87            GraphEvent::RunFailed { ts, .. } => *ts,
88        }
89    }
90}
91
92/// Helper to get current timestamp in milliseconds
93pub fn now_ms() -> u64 {
94    std::time::SystemTime::now()
95        .duration_since(std::time::UNIX_EPOCH)
96        .unwrap_or_default()
97        .as_millis() as u64
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::types::NodeId;
104
105    #[test]
106    fn graph_event_serializes() {
107        let id = NodeId::new();
108        let event = GraphEvent::NodeCompleted {
109            id: id.clone(),
110            result: serde_json::json!({"output": "done"}),
111            ts: now_ms(),
112        };
113        let json = serde_json::to_string(&event).unwrap();
114        let event2: GraphEvent = serde_json::from_str(&json).unwrap();
115        assert!(event2.ts() > 0);
116    }
117
118    #[test]
119    fn now_ms_is_reasonable() {
120        let ts = now_ms();
121        assert!(ts > 1_700_000_000_000); // after 2023
122    }
123}