Skip to main content

server/
lib.rs

1#![deny(clippy::await_holding_lock)]
2
3mod http;
4mod json;
5mod mcp;
6mod mcp_tasks;
7mod subscribe;
8mod ws;
9
10use core_api::{MutationEvent, SharedDb};
11
12pub use mcp::{run_mcp_stdio, run_mcp_stdio_with, ASSOCIATION_TOOLS, CODE_GRAPH_TOOLS};
13
14/// The root this crate's `tracing` events are filtered by.
15///
16/// It is the **lib** name, which is not the package name — `server`, not
17/// `mushroomdb-server`. A log filter naming the package matches nothing, and a
18/// filter that matches nothing looks exactly like a server with nothing to
19/// report. Exported so the binary's default filter can be checked against it
20/// rather than against a guess.
21pub const LOG_TARGET_ROOT: &str = module_path!();
22
23/// Resolved authentication identity for a single request.
24///
25/// Injected into request extensions by `auth_middleware` before any handler
26/// runs.  Handlers that need to enforce role-based access control extract it
27/// via `Extension<AuthIdentity>`.
28#[derive(Clone, Debug)]
29pub(crate) enum AuthIdentity {
30    /// Full-access token (or no auth configured).
31    Full,
32    /// Role-bound token; the inner string is the role name.
33    Role(String),
34    /// Reached an endpoint that is open by design without presenting a token
35    /// that resolves to anything — today only `GET /health`, which a load
36    /// balancer must be able to call before it has a credential.
37    ///
38    /// Distinct from [`Full`](AuthIdentity::Full) because the difference is
39    /// what may be disclosed: an anonymous caller gets liveness and nothing
40    /// that describes the graph.
41    Anonymous,
42}
43
44/// Router state: the database plus the watch broadcast fan-out.
45#[derive(Clone)]
46struct AppState {
47    db: SharedDb,
48    watch: tokio::sync::broadcast::Sender<MutationEvent>,
49    /// Full-access bearer token (`--token` / `MUSHROOMDB_TOKEN`).
50    token: Option<String>,
51    /// Role-bound tokens: bearer value → role name.
52    /// A non-empty map enables role enforcement on every request.
53    role_tokens: std::collections::HashMap<String, String>,
54    /// Bind address advertised in `GET /health`.
55    addr: std::net::SocketAddr,
56    /// True when the server is serving over TLS (via the `tls` feature).
57    /// When true, the auth cookie gains the `Secure` attribute.
58    tls_active: bool,
59    /// Instant the router was first built; used by `GET /metrics` uptime_s.
60    started_at: std::time::Instant,
61}
62
63#[allow(deprecated)]
64pub use http::{
65    router, router_with_auth, router_with_role_tokens, router_with_ui, router_with_ui_tls, serve,
66    serve_with_role_tokens, serve_with_role_tokens_and_shutdown, serve_with_shutdown,
67    serve_with_ui, serve_with_ui_and_role_tokens, serve_with_ui_and_role_tokens_and_shutdown,
68};
69#[cfg(feature = "embed-ui")]
70pub use http::{
71    router_with_embedded_ui, serve_with_embedded_ui, serve_with_embedded_ui_and_shutdown,
72};
73#[cfg(feature = "tls")]
74pub use http::{serve_tls, serve_tls_with_shutdown};