Skip to main content

acta_maker_sdk/
io_observer.rs

1//! Optional process-local observations at transport boundaries.
2use std::sync::OnceLock;
3
4pub enum Event<'a> {
5    HttpRequest {
6        venue: &'a str,
7        endpoint: &'a str,
8    },
9    HttpStatus {
10        venue: &'a str,
11        endpoint: &'a str,
12        status: u16,
13    },
14    HttpBytes {
15        venue: &'a str,
16        endpoint: &'a str,
17        bytes: usize,
18    },
19    Ws {
20        venue: &'a str,
21        stream: &'a str,
22        bytes: usize,
23    },
24    Rpc {
25        method: &'a str,
26    },
27}
28static OBSERVER: OnceLock<fn(Event<'_>)> = OnceLock::new();
29pub fn install(observer: fn(Event<'_>)) {
30    let _ = OBSERVER.set(observer);
31}
32pub fn record(event: Event<'_>) {
33    if let Some(observer) = OBSERVER.get() {
34        observer(event);
35    }
36}
37
38#[cfg(feature = "http")]
39pub async fn send(
40    request: reqwest::RequestBuilder,
41    venue: &str,
42    endpoint: &str,
43) -> Result<reqwest::Response, reqwest::Error> {
44    record(Event::HttpRequest { venue, endpoint });
45    let response = request.send().await;
46    record(Event::HttpStatus {
47        venue,
48        endpoint,
49        status: response.as_ref().map_or(0, |r| r.status().as_u16()),
50    });
51    response
52}
53#[cfg(feature = "http")]
54pub async fn bytes(
55    mut response: reqwest::Response,
56    venue: &str,
57    endpoint: &str,
58) -> Result<Vec<u8>, reqwest::Error> {
59    let mut count = BodyCount {
60        venue,
61        endpoint,
62        bytes: 0,
63    };
64    let mut body = Vec::new();
65    while let Some(chunk) = response.chunk().await? {
66        count.bytes += chunk.len();
67        body.extend_from_slice(&chunk);
68    }
69    Ok(body)
70}
71
72#[cfg(feature = "http")]
73struct BodyCount<'a> {
74    venue: &'a str,
75    endpoint: &'a str,
76    bytes: usize,
77}
78#[cfg(feature = "http")]
79impl Drop for BodyCount<'_> {
80    fn drop(&mut self) {
81        record(Event::HttpBytes {
82            venue: self.venue,
83            endpoint: self.endpoint,
84            bytes: self.bytes,
85        });
86    }
87}