1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::{
    policy::{content::ContentPolicy, record::RecordPolicy},
    services::CoreService,
};
use axum::{body::Body, http::Request, Router};
use std::{path::PathBuf, sync::Arc};
use tower::ServiceBuilder;
use tower_http::{
    cors::{Any, CorsLayer},
    services::ServeDir,
    trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
    LatencyUnit,
};
use tracing::{Level, Span};
use url::Url;

pub mod v1;

#[cfg(feature = "debug")]
pub mod debug;

/// Creates the router for the API.
pub fn create_router(
    content_base_url: Url,
    core: CoreService,
    temp_dir: PathBuf,
    files_dir: PathBuf,
    content_policy: Option<Arc<dyn ContentPolicy>>,
    record_policy: Option<Arc<dyn RecordPolicy>>,
) -> Router {
    let router = Router::new();
    #[cfg(feature = "debug")]
    let router = router.nest("/debug", debug::Config::new(core.clone()).into_router());
    router
        .nest(
            "/v1",
            v1::create_router(
                content_base_url,
                core,
                temp_dir,
                files_dir.clone(),
                content_policy,
                record_policy,
            ),
        )
        .nest_service("/content", ServeDir::new(files_dir))
        .layer(
            ServiceBuilder::new()
                .layer(
                    TraceLayer::new_for_http()
                        .make_span_with(DefaultMakeSpan::new().include_headers(true))
                        .on_request(|request: &Request<Body>, _span: &Span| {
                            tracing::info!("starting {} {}", request.method(), request.uri().path())
                        })
                        .on_response(
                            DefaultOnResponse::new()
                                .level(Level::INFO)
                                .latency_unit(LatencyUnit::Micros),
                        ),
                )
                .layer(
                    CorsLayer::new()
                        .allow_origin(Any)
                        .allow_methods([axum::http::Method::GET, axum::http::Method::POST])
                        .allow_headers([
                            axum::http::header::CONTENT_TYPE,
                            axum::http::header::ACCEPT,
                        ]),
                ),
        )
}