#![allow(dead_code)]
#![feature(impl_trait_in_assoc_type)]
use serde::Deserialize;
use thiserror::Error;
use tokio::io;
use tosic_http::body::BoxBody;
use tosic_http::error::response_error::ResponseError;
use tosic_http::extractors::json::Json;
use tosic_http::extractors::path::Path as HttpPath;
use tosic_http::extractors::query::Query;
use tosic_http::resource::post;
use tosic_http::response::HttpResponse;
use tosic_http::server::builder::HttpServerBuilder;
use tosic_http::traits::responder::Responder;
use tosic_http_macro::get;
use tracing::dispatcher::SetGlobalDefaultError;
#[derive(Debug, Error)]
enum HttpServerError {
#[error(transparent)]
Tracing(#[from] SetGlobalDefaultError),
#[error(transparent)]
Io(#[from] io::Error),
}
impl ResponseError for HttpServerError {}
mod logger {
use crate::HttpServerError;
#[cfg(feature = "log-subscriber")]
use tracing::level_filters::LevelFilter;
#[cfg(feature = "log-subscriber")]
use tracing_subscriber::fmt::format::FmtSpan;
#[cfg(feature = "log-subscriber")]
use tracing_subscriber::fmt::Layer as FmtLayer;
#[cfg(feature = "log-subscriber")]
use tracing_subscriber::layer::SubscriberExt;
#[cfg(feature = "log-subscriber")]
use tracing_subscriber::{EnvFilter, Layer, Registry};
#[cfg(feature = "log-subscriber")]
pub fn init_tracing() -> Result<(), HttpServerError> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
#[cfg(not(debug_assertions))]
let level = LevelFilter::INFO;
#[cfg(debug_assertions)]
let level = LevelFilter::DEBUG;
EnvFilter::builder()
.with_default_directive(level.into())
.from_env_lossy()
});
let def_layer = FmtLayer::new()
.with_line_number(true)
.with_span_events(FmtSpan::CLOSE)
.with_level(true)
.with_target(true)
.with_thread_names(true)
.with_thread_ids(true)
.compact()
.with_filter(filter);
let subscriber = Registry::default().with(def_layer);
tracing::subscriber::set_global_default(subscriber)?;
Ok(())
}
#[cfg(all(feature = "console-subscriber", not(feature = "log-subscriber")))]
pub fn init_tracing() -> Result<(), HttpServerError> {
console_subscriber::init();
Ok(())
}
}
#[derive(Deserialize, Debug)]
struct TestTest {
username: String,
password: String,
}
#[get("/{id}/{name}")]
#[tracing::instrument]
async fn not_working(
path: HttpPath<(u8, String)>,
) -> Result<impl Responder<Body = BoxBody>, HttpServerError> {
let (id, name) = path.into_inner();
Ok(HttpResponse::new(200).body((id.to_string(), name)))
}
async fn test_handler(
query: Option<Query<TestTest>>,
json: Json<TestTest>,
) -> impl Responder<Body = BoxBody> {
let json = json.into_inner();
if let Some(query) = query {
let test = query.into_inner();
assert_eq!(test.username, json.username);
assert_eq!(test.password, json.password);
}
format!("Hello, {}!", json.username)
}
async fn test_get() -> impl Responder<Body = BoxBody> {
"hi"
}
#[get("/test")]
async fn test_fn() -> impl Responder<Body = BoxBody> {
"hello testing world"
}
struct State {
dir: String,
}
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> Result<(), HttpServerError> {
logger::init_tracing()?;
let state = State {
dir: "/Users/emil/projects/tosic-http/target/doc".to_string(),
};
let server = HttpServerBuilder::default()
.app_state(state)
.bind("0.0.0.0:4221")
.route(post("/", test_handler).get(test_get))
.service(not_working)
.service(test_fn)
.build()
.await?;
match server.serve().await {
Ok(_) => (),
Err(e) => panic!("Failed to serve: {}", e),
}
Ok(())
}