pub mod bus;
pub mod config;
pub mod handlers;
pub mod hub;
pub mod local_bus;
pub mod metrics;
pub mod mqtt;
pub mod nats_bus;
pub mod presence;
pub mod rate_limit;
pub mod webhook;
pub mod ws;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
routing::{delete, get, post, put},
Json, Router,
};
use freshblu_core::error::FreshBluError;
use freshblu_store::DynStore;
use serde_json::json;
use std::sync::Arc;
use tower_http::{cors::CorsLayer, trace::TraceLayer};
pub use bus::DynBus;
pub use config::ServerConfig;
pub use hub::MessageHub;
pub use rate_limit::RateLimiter;
pub use webhook::WebhookExecutor;
pub struct ApiError(pub FreshBluError);
impl From<FreshBluError> for ApiError {
fn from(e: FreshBluError) -> Self {
ApiError(e)
}
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let status =
StatusCode::from_u16(self.0.http_status()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
let body = json!({ "error": self.0.to_string() });
(status, Json(body)).into_response()
}
}
#[derive(Clone)]
pub struct AppState {
pub store: DynStore,
pub bus: DynBus,
pub config: ServerConfig,
pub rate_limiter: Arc<RateLimiter>,
pub webhook_executor: Arc<WebhookExecutor>,
}
pub fn build_router(state: AppState) -> Router {
Router::new()
.route("/status", get(handlers::status::status))
.route("/healthcheck", get(handlers::status::healthcheck))
.route("/authenticate", post(handlers::auth::authenticate))
.route("/devices", post(handlers::devices::register))
.route("/devices/search", post(handlers::devices::search))
.route("/devices/:uuid", get(handlers::devices::get_device))
.route("/devices/:uuid", put(handlers::devices::update_device))
.route("/devices/:uuid", delete(handlers::devices::unregister))
.route("/v2/devices", post(handlers::devices::register))
.route("/v2/devices/:uuid", get(handlers::devices::get_device))
.route("/v2/devices/:uuid", put(handlers::devices::update_device))
.route("/v2/devices/:uuid", delete(handlers::devices::unregister))
.route("/v2/devices/search", post(handlers::devices::search))
.route("/v3/devices/:uuid", get(handlers::devices::get_device))
.route("/whoami", get(handlers::devices::whoami))
.route("/v2/whoami", get(handlers::devices::whoami))
.route("/messages", post(handlers::messages::send_message))
.route("/v2/messages", post(handlers::messages::send_message))
.route("/broadcasts", post(handlers::messages::broadcast))
.route("/mydevices", get(handlers::devices::my_devices))
.route(
"/claimdevice/:uuid",
post(handlers::devices::claim_device),
)
.route(
"/devices/:uuid/publickey",
get(handlers::devices::get_public_key),
)
.route("/publickey", get(handlers::status::server_public_key))
.route(
"/devices/:uuid/subscriptions",
post(handlers::subscriptions::create_subscription),
)
.route(
"/devices/:uuid/subscriptions",
get(handlers::subscriptions::list_subscriptions),
)
.route(
"/devices/:uuid/subscriptions/:emitter_uuid/:sub_type",
delete(handlers::subscriptions::delete_subscription),
)
.route(
"/devices/:uuid/tokens",
post(handlers::tokens::generate_token),
)
.route(
"/devices/:uuid/tokens/:token",
delete(handlers::tokens::revoke_token),
)
.route(
"/devices/:uuid/token",
post(handlers::tokens::reset_token),
)
.route(
"/search/tokens",
post(handlers::tokens::search_tokens),
)
.route("/subscribe", get(handlers::subscribe::subscribe))
.route("/ws", get(ws::ws_handler))
.route("/socket.io", get(ws::ws_handler))
.route("/metrics", get(metrics::metrics_handler))
.layer(CorsLayer::permissive())
.layer(TraceLayer::new_for_http())
.with_state(state)
}