1use anyhow::Result;
4use serde::{Serialize, Deserialize};
5use tokio::sync::broadcast;
6use std::sync::Arc;
7use parking_lot::RwLock;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub enum ForgeEvent {
12 ToolStarted { tool_id: String, timestamp: i64 },
13 ToolCompleted { tool_id: String, duration_ms: u64, timestamp: i64 },
14 PipelineStarted { pipeline_id: String, timestamp: i64 },
15 PipelineCompleted { pipeline_id: String, duration_ms: u64, timestamp: i64 },
16 PackageInstallationBegin { package_id: String, timestamp: i64 },
17 PackageInstallationSuccess { package_id: String, timestamp: i64 },
18 SecurityViolationDetected { description: String, severity: String, timestamp: i64 },
19 MagicalConfigInjection { config_section: String, timestamp: i64 },
20 Custom { event_type: String, data: serde_json::Value, timestamp: i64 },
21}
22
23static mut EVENT_BUS: Option<Arc<RwLock<EventBus>>> = None;
24
25struct EventBus {
26 sender: broadcast::Sender<ForgeEvent>,
27}
28
29impl EventBus {
30 fn new() -> Self {
31 let (sender, _) = broadcast::channel(10000);
32 Self { sender }
33 }
34}
35
36fn get_event_bus() -> Arc<RwLock<EventBus>> {
37 unsafe {
38 if EVENT_BUS.is_none() {
39 EVENT_BUS = Some(Arc::new(RwLock::new(EventBus::new())));
40 }
41 EVENT_BUS.as_ref().unwrap().clone()
42 }
43}
44
45pub fn publish_event(event: ForgeEvent) -> Result<()> {
46 let bus = get_event_bus();
47 let bus = bus.read();
48 let _ = bus.sender.send(event);
49 Ok(())
50}
51
52pub fn subscribe_to_event_stream() -> broadcast::Receiver<ForgeEvent> {
53 let bus = get_event_bus();
54 let bus = bus.read();
55 bus.sender.subscribe()
56}
57
58pub fn emit_tool_started_event(tool_id: &str) -> Result<()> {
59 publish_event(ForgeEvent::ToolStarted {
60 tool_id: tool_id.to_string(),
61 timestamp: chrono::Utc::now().timestamp(),
62 })
63}
64
65pub fn emit_tool_completed_event(tool_id: &str, duration_ms: u64) -> Result<()> {
66 publish_event(ForgeEvent::ToolCompleted {
67 tool_id: tool_id.to_string(),
68 duration_ms,
69 timestamp: chrono::Utc::now().timestamp(),
70 })
71}
72
73pub fn emit_pipeline_started_event(pipeline_id: &str) -> Result<()> {
74 publish_event(ForgeEvent::PipelineStarted {
75 pipeline_id: pipeline_id.to_string(),
76 timestamp: chrono::Utc::now().timestamp(),
77 })
78}
79
80pub fn emit_pipeline_completed_event(pipeline_id: &str, duration_ms: u64) -> Result<()> {
81 publish_event(ForgeEvent::PipelineCompleted {
82 pipeline_id: pipeline_id.to_string(),
83 duration_ms,
84 timestamp: chrono::Utc::now().timestamp(),
85 })
86}
87
88pub fn emit_package_installation_begin(package_id: &str) -> Result<()> {
89 publish_event(ForgeEvent::PackageInstallationBegin {
90 package_id: package_id.to_string(),
91 timestamp: chrono::Utc::now().timestamp(),
92 })
93}
94
95pub fn emit_package_installation_success(package_id: &str) -> Result<()> {
96 publish_event(ForgeEvent::PackageInstallationSuccess {
97 package_id: package_id.to_string(),
98 timestamp: chrono::Utc::now().timestamp(),
99 })
100}
101
102pub fn emit_security_violation_detected(description: &str, severity: &str) -> Result<()> {
103 publish_event(ForgeEvent::SecurityViolationDetected {
104 description: description.to_string(),
105 severity: severity.to_string(),
106 timestamp: chrono::Utc::now().timestamp(),
107 })
108}
109
110pub fn emit_magical_config_injection(config_section: &str) -> Result<()> {
111 publish_event(ForgeEvent::MagicalConfigInjection {
112 config_section: config_section.to_string(),
113 timestamp: chrono::Utc::now().timestamp(),
114 })
115}