awsim_core/
request_event.rs1use serde::Serialize;
2use tokio::sync::broadcast;
3
4#[derive(Debug, Clone, Serialize)]
5pub struct RequestEvent {
6 pub id: String,
7 pub ts: f64,
8 pub method: String,
9 pub path: String,
10 pub service: String,
11 pub operation: Option<String>,
12 pub account_id: String,
13 pub region: String,
14 pub principal_arn: Option<String>,
15 pub status_code: u16,
16 pub duration_ms: f64,
17 pub request_size: u64,
18 pub response_size: u64,
19 pub error_code: Option<String>,
20}
21
22#[derive(Clone, Debug)]
23pub struct RequestEventBus {
24 sender: broadcast::Sender<RequestEvent>,
25}
26
27impl RequestEventBus {
28 pub fn new() -> Self {
29 let (sender, _) = broadcast::channel(256);
30 Self { sender }
31 }
32
33 pub fn publish(&self, event: RequestEvent) {
34 let _ = self.sender.send(event);
35 }
36
37 pub fn subscribe(&self) -> broadcast::Receiver<RequestEvent> {
38 self.sender.subscribe()
39 }
40
41 pub fn sender(&self) -> &broadcast::Sender<RequestEvent> {
42 &self.sender
43 }
44}
45
46impl Default for RequestEventBus {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[tokio::test]
57 async fn broadcast_round_trip() {
58 let bus = RequestEventBus::new();
59 let mut rx = bus.subscribe();
60 let event = RequestEvent {
61 id: "req-1".to_string(),
62 ts: 1735041600.123,
63 method: "POST".to_string(),
64 path: "/".to_string(),
65 service: "s3".to_string(),
66 operation: Some("PutObject".to_string()),
67 account_id: "000000000000".to_string(),
68 region: "us-east-1".to_string(),
69 principal_arn: None,
70 status_code: 200,
71 duration_ms: 12.5,
72 request_size: 1024,
73 response_size: 256,
74 error_code: None,
75 };
76 bus.publish(event.clone());
77 let received = rx.recv().await.expect("receive event");
78 assert_eq!(received.id, event.id);
79 assert_eq!(received.service, "s3");
80 assert_eq!(received.operation.as_deref(), Some("PutObject"));
81 assert_eq!(received.status_code, 200);
82 }
83}