groundwork/
lib.rs

1use std::sync::{Arc, Mutex};
2
3use poem::error::InternalServerError;
4use poem::middleware::AddData;
5use poem::web::{Data, Html, WithContentType};
6use poem::{EndpointExt, IntoResponse};
7use poem::{Result, handler};
8use poem::{Route, get};
9use trace::Buffer;
10use tracing_subscriber::fmt::MakeWriter;
11pub mod call;
12pub mod descriptors;
13pub mod stat;
14pub mod trace;
15
16pub type DefaultGroundwork = Groundwork<{ trace::DEFAULT_BUFFER_SIZE }, 100>;
17
18pub struct Groundwork<const LOG_SIZE: usize, const CALL_SIZE: usize> {
19    stats_data: Arc<stat::StatsData>,
20    logs: Arc<Mutex<Buffer<LOG_SIZE>>>,
21    calls_middleware: call::CallMiddleware<CALL_SIZE>,
22}
23
24impl<const LOG_SIZE: usize, const CALL_SIZE: usize> Groundwork<LOG_SIZE, CALL_SIZE> {
25    pub fn new(name: &str) -> Self {
26        Self {
27            stats_data: Arc::new(stat::StatsData::new(name)),
28            logs: Arc::new(Mutex::new(Buffer::new())),
29            calls_middleware: call::CallMiddleware::new(),
30        }
31    }
32
33    pub fn register_handlers(&self, route: Route, page_path: &str) -> Route {
34        route
35            .at(
36                "/groundwork/stats",
37                get(stat::stats).with(AddData::new(self.stats_data.clone())),
38            )
39            .at(
40                "/groundwork/logs",
41                get(logs).with(AddData::new(self.logs.clone())),
42            )
43            .at(
44                "/groundwork/calls",
45                get(calls).with(AddData::new(self.calls_middleware().get())),
46            )
47            .at("/groundwork/descriptors", get(descriptors::descriptors))
48            .at("/groundwork/w3.css", css)
49            .at(page_path, index)
50    }
51
52    pub fn register_stdout_tracing_subscriber(&self) {
53        tracing_subscriber::fmt::Subscriber::builder()
54            .with_ansi(false)
55            .with_writer(self.trace_writer_stdout())
56            .init();
57    }
58
59    pub fn trace_writer_stdout(&self) -> impl for<'a> MakeWriter<'a> + 'static {
60        trace::StdoutTraceWriterMaker::new(self.logs.clone())
61    }
62
63    pub fn trace_writer<W>(&self, writer: W) -> impl for<'a> MakeWriter<'a> + 'static
64    where
65        W: for<'a> MakeWriter<'a> + 'static,
66    {
67        trace::TraceWriterWrapperMaker::new(self.logs.clone(), writer)
68    }
69
70    pub fn calls_middleware(&self) -> call::CallMiddleware<CALL_SIZE> {
71        self.calls_middleware.clone()
72    }
73}
74
75#[handler]
76fn logs(
77    buffer: Data<&std::sync::Arc<std::sync::Mutex<trace::Buffer<{ trace::DEFAULT_BUFFER_SIZE }>>>>,
78) -> Result<String> {
79    serde_json::to_string(&buffer.lock().unwrap().get_traces().unwrap())
80        .map_err(InternalServerError)
81}
82
83// FIXME convert to implementation of Endpoint
84#[handler]
85fn calls(buffer: Data<&call::BufferRef<100>>) -> Result<String> {
86    serde_json::to_string(&buffer.lock().unwrap().iter().collect::<Vec<_>>())
87        .map_err(InternalServerError)
88}
89
90#[handler]
91fn css() -> WithContentType<&'static str> {
92    include_str!("w3.css").with_content_type("text/css")
93}
94
95#[handler]
96fn index() -> Html<&'static str> {
97    Html(include_str!("index.html"))
98}