Skip to main content

freshblu_server/
lib.rs

1pub mod bus;
2pub mod config;
3pub mod handlers;
4pub mod hub;
5pub mod local_bus;
6pub mod metrics;
7pub mod mqtt;
8pub mod nats_bus;
9pub mod presence;
10pub mod rate_limit;
11pub mod webhook;
12pub mod ws;
13
14use axum::{
15    http::StatusCode,
16    response::{IntoResponse, Response},
17    routing::{delete, get, post, put},
18    Json, Router,
19};
20use freshblu_core::error::FreshBluError;
21use freshblu_store::DynStore;
22use serde_json::json;
23use std::sync::Arc;
24use tower_http::{cors::CorsLayer, trace::TraceLayer};
25
26pub use bus::DynBus;
27pub use config::ServerConfig;
28pub use hub::MessageHub;
29pub use rate_limit::RateLimiter;
30pub use webhook::WebhookExecutor;
31
32/// Newtype wrapper to implement IntoResponse for FreshBluError (orphan rule)
33pub struct ApiError(pub FreshBluError);
34
35impl From<FreshBluError> for ApiError {
36    fn from(e: FreshBluError) -> Self {
37        ApiError(e)
38    }
39}
40
41impl IntoResponse for ApiError {
42    fn into_response(self) -> Response {
43        let status =
44            StatusCode::from_u16(self.0.http_status()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
45        let body = json!({ "error": self.0.to_string() });
46        (status, Json(body)).into_response()
47    }
48}
49
50/// Shared application state
51#[derive(Clone)]
52pub struct AppState {
53    pub store: DynStore,
54    pub bus: DynBus,
55    pub config: ServerConfig,
56    pub rate_limiter: Arc<RateLimiter>,
57    pub webhook_executor: Arc<WebhookExecutor>,
58}
59
60pub fn build_router(state: AppState) -> Router {
61    Router::new()
62        // Status & healthcheck
63        .route("/status", get(handlers::status::status))
64        .route("/healthcheck", get(handlers::status::healthcheck))
65        // Authentication
66        .route("/authenticate", post(handlers::auth::authenticate))
67        // Device registration / auth
68        .route("/devices", post(handlers::devices::register))
69        .route("/devices/search", post(handlers::devices::search))
70        .route("/devices/:uuid", get(handlers::devices::get_device))
71        .route("/devices/:uuid", put(handlers::devices::update_device))
72        .route("/devices/:uuid", delete(handlers::devices::unregister))
73        // v2 aliases
74        .route("/v2/devices", post(handlers::devices::register))
75        .route("/v2/devices/:uuid", get(handlers::devices::get_device))
76        .route("/v2/devices/:uuid", put(handlers::devices::update_device))
77        .route("/v2/devices/:uuid", delete(handlers::devices::unregister))
78        .route("/v2/devices/search", post(handlers::devices::search))
79        // v3 aliases
80        .route("/v3/devices/:uuid", get(handlers::devices::get_device))
81        // Whoami
82        .route("/whoami", get(handlers::devices::whoami))
83        .route("/v2/whoami", get(handlers::devices::whoami))
84        // Messaging
85        .route("/messages", post(handlers::messages::send_message))
86        .route("/v2/messages", post(handlers::messages::send_message))
87        // Broadcasts
88        .route("/broadcasts", post(handlers::messages::broadcast))
89        // My devices
90        .route("/mydevices", get(handlers::devices::my_devices))
91        // Claim device
92        .route(
93            "/claimdevice/:uuid",
94            post(handlers::devices::claim_device),
95        )
96        // Public key endpoints
97        .route(
98            "/devices/:uuid/publickey",
99            get(handlers::devices::get_public_key),
100        )
101        .route("/publickey", get(handlers::status::server_public_key))
102        // Subscriptions
103        .route(
104            "/devices/:uuid/subscriptions",
105            post(handlers::subscriptions::create_subscription),
106        )
107        .route(
108            "/devices/:uuid/subscriptions",
109            get(handlers::subscriptions::list_subscriptions),
110        )
111        .route(
112            "/devices/:uuid/subscriptions/:emitter_uuid/:sub_type",
113            delete(handlers::subscriptions::delete_subscription),
114        )
115        // Token management
116        .route(
117            "/devices/:uuid/tokens",
118            post(handlers::tokens::generate_token),
119        )
120        .route(
121            "/devices/:uuid/tokens/:token",
122            delete(handlers::tokens::revoke_token),
123        )
124        .route(
125            "/devices/:uuid/token",
126            post(handlers::tokens::reset_token),
127        )
128        // Token search
129        .route(
130            "/search/tokens",
131            post(handlers::tokens::search_tokens),
132        )
133        // Firehose / HTTP streaming
134        .route("/subscribe", get(handlers::subscribe::subscribe))
135        // WebSocket
136        .route("/ws", get(ws::ws_handler))
137        .route("/socket.io", get(ws::ws_handler))
138        // Metrics
139        .route("/metrics", get(metrics::metrics_handler))
140        // Middleware
141        .layer(CorsLayer::permissive())
142        .layer(TraceLayer::new_for_http())
143        .with_state(state)
144}