1#![allow(dead_code)]
2#![feature(impl_trait_in_assoc_type)]
3
4use serde::Deserialize;
5use thiserror::Error;
6use tokio::io;
7use tosic_http::body::BoxBody;
8use tosic_http::error::response_error::ResponseError;
9use tosic_http::extractors::json::Json;
10use tosic_http::extractors::path::Path as HttpPath;
11use tosic_http::extractors::query::Query;
12use tosic_http::resource::post;
13use tosic_http::response::HttpResponse;
14use tosic_http::server::builder::HttpServerBuilder;
15use tosic_http::traits::responder::Responder;
16use tosic_http_macro::get;
17use tracing::dispatcher::SetGlobalDefaultError;
18
19#[derive(Debug, Error)]
20enum HttpServerError {
21 #[error(transparent)]
22 Tracing(#[from] SetGlobalDefaultError),
23 #[error(transparent)]
24 Io(#[from] io::Error),
25}
26
27impl ResponseError for HttpServerError {}
28
29mod logger {
30 use crate::HttpServerError;
31 #[cfg(feature = "log-subscriber")]
32 use tracing::level_filters::LevelFilter;
33 #[cfg(feature = "log-subscriber")]
34 use tracing_subscriber::fmt::format::FmtSpan;
35 #[cfg(feature = "log-subscriber")]
36 use tracing_subscriber::fmt::Layer as FmtLayer;
37 #[cfg(feature = "log-subscriber")]
38 use tracing_subscriber::layer::SubscriberExt;
39 #[cfg(feature = "log-subscriber")]
40 use tracing_subscriber::{EnvFilter, Layer, Registry};
41
42 #[cfg(feature = "log-subscriber")]
43 pub fn init_tracing() -> Result<(), HttpServerError> {
44 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
45 #[cfg(not(debug_assertions))]
46 let level = LevelFilter::INFO;
47
48 #[cfg(debug_assertions)]
49 let level = LevelFilter::DEBUG;
50
51 EnvFilter::builder()
52 .with_default_directive(level.into())
53 .from_env_lossy()
54 });
55 let def_layer = FmtLayer::new()
56 .with_line_number(true)
57 .with_span_events(FmtSpan::CLOSE)
58 .with_level(true)
59 .with_target(true)
60 .with_thread_names(true)
61 .with_thread_ids(true)
62 .compact()
63 .with_filter(filter);
64
65 let subscriber = Registry::default().with(def_layer);
66
67 tracing::subscriber::set_global_default(subscriber)?;
68
69 Ok(())
70 }
71
72 #[cfg(all(feature = "console-subscriber", not(feature = "log-subscriber")))]
73 pub fn init_tracing() -> Result<(), HttpServerError> {
74 console_subscriber::init();
75
76 Ok(())
77 }
78}
79
80#[derive(Deserialize, Debug)]
81struct TestTest {
82 username: String,
83 password: String,
84}
85
86#[get("/{id}/{name}")]
87#[tracing::instrument]
88async fn not_working(
89 path: HttpPath<(u8, String)>,
90) -> Result<impl Responder<Body = BoxBody>, HttpServerError> {
91 let (id, name) = path.into_inner();
92
93 Ok(HttpResponse::new(200).body((id.to_string(), name)))
94}
95
96async fn test_handler(
97 query: Option<Query<TestTest>>,
98 json: Json<TestTest>,
99) -> impl Responder<Body = BoxBody> {
100 let json = json.into_inner();
101
102 if let Some(query) = query {
103 let test = query.into_inner();
104
105 assert_eq!(test.username, json.username);
106 assert_eq!(test.password, json.password);
107 }
108
109 format!("Hello, {}!", json.username)
110}
111
112async fn test_get() -> impl Responder<Body = BoxBody> {
113 "hi"
114}
115
116#[get("/test")]
117async fn test_fn() -> impl Responder<Body = BoxBody> {
118 "hello testing world"
119}
120
121struct State {
122 dir: String,
123}
124
125#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
187async fn main() -> Result<(), HttpServerError> {
189 logger::init_tracing()?;
190 let state = State {
191 dir: "/Users/emil/projects/tosic-http/target/doc".to_string(),
192 };
193
194 let server = HttpServerBuilder::default()
195 .app_state(state)
196 .bind("0.0.0.0:4221")
197 .route(post("/", test_handler).get(test_get))
199 .service(not_working)
201 .service(test_fn)
202 .build()
204 .await?;
205
206 match server.serve().await {
207 Ok(_) => (),
208 Err(e) => panic!("Failed to serve: {}", e),
209 }
210
211 Ok(())
212}