docspec_http/lib.rs
1#![forbid(unsafe_code)]
2//! HTTP API server for `DocSpec` document conversion.
3
4extern crate alloc;
5
6pub mod cache;
7pub mod cli;
8pub mod error;
9pub mod format;
10pub mod handlers;
11pub mod metrics;
12pub mod mime;
13pub mod mime_parser;
14pub mod router;
15pub mod server;
16pub mod telemetry;
17pub mod tracing_init;
18
19pub use cli::Args;
20pub use server::{serve, ServerError};
21
22/// Initialize Sentry (if DSN env var set) and return a guard that flushes Sentry on drop.
23/// MUST be called BEFORE building the tokio runtime; `main()` MUST hold the returned guard for the entire process lifetime.
24#[must_use]
25#[inline]
26pub fn init_telemetry() -> telemetry::TelemetryGuard {
27 telemetry::init()
28}
29
30/// Initialize the global tracing subscriber. Called internally by [`run_server`].
31///
32/// Idempotent: if a global subscriber is already installed, this is a no-op so library
33/// consumers can safely call [`run_server`] more than once per process.
34#[inline]
35pub fn init_tracing() {
36 // Discard the "already initialized" error — the global subscriber is a process-wide
37 // singleton, so subsequent calls are correctly handled as no-ops.
38 drop(tracing_init::try_init());
39}
40
41/// Synchronous server entrypoint. Builds a multi-threaded tokio runtime, installs the
42/// global tracing subscriber, and runs the HTTP server until SIGINT/SIGTERM.
43///
44/// # Lifetime requirement
45///
46/// The caller MUST call [`init_telemetry`] BEFORE this function and hold the returned
47/// `TelemetryGuard` for the entire process lifetime.
48///
49/// # Errors
50///
51/// Returns [`ServerError`] if runtime construction fails or the HTTP server fails.
52#[inline]
53pub fn run_server(args: cli::Args) -> Result<(), ServerError> {
54 let config = args.into_config();
55 let runtime = tokio::runtime::Builder::new_multi_thread()
56 .enable_all()
57 .build()
58 .map_err(ServerError::RuntimeBuild)?;
59
60 runtime.block_on(async {
61 init_tracing();
62 serve(config).await
63 })
64}