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#[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}