bootstrap: SQLite config, HTTP API on :3000, TCP on :2699, poll loops.
http-api: added serve() so bootstrap doesn't depend on axum directly.
polling: reads data sources from config, polls via http-json adapter,
pushes changed widgets to connected clients.
configure via API, e.g.:
curl -X POST localhost:3000/api/data-sources -H 'Content-Type: application/json' -d '{...}'
curl -X PUT localhost:3000/api/layout -H 'Content-Type: application/json' -d '{...}'
46 lines
1.1 KiB
Rust
46 lines
1.1 KiB
Rust
mod routes;
|
|
|
|
use std::sync::Arc;
|
|
use axum::Router;
|
|
use tower_http::cors::CorsLayer;
|
|
use domain::{ConfigRepository, EventPublisher};
|
|
|
|
pub struct AppState<C, E> {
|
|
pub config: Arc<C>,
|
|
pub events: Arc<E>,
|
|
}
|
|
|
|
impl<C, E> Clone for AppState<C, E> {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
config: self.config.clone(),
|
|
events: self.events.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn router<C, E>(state: AppState<C, E>) -> Router
|
|
where
|
|
C: ConfigRepository + Send + Sync + 'static,
|
|
C::Error: std::fmt::Debug + Send,
|
|
E: EventPublisher + Send + Sync + 'static,
|
|
E::Error: std::fmt::Debug + Send,
|
|
{
|
|
Router::new()
|
|
.nest("/api", routes::api_routes())
|
|
.layer(CorsLayer::permissive())
|
|
.with_state(state)
|
|
}
|
|
|
|
pub async fn serve<C, E>(addr: &str, state: AppState<C, E>) -> Result<(), std::io::Error>
|
|
where
|
|
C: ConfigRepository + Send + Sync + 'static,
|
|
C::Error: std::fmt::Debug + Send,
|
|
E: EventPublisher + Send + Sync + 'static,
|
|
E::Error: std::fmt::Debug + Send,
|
|
{
|
|
let app = router(state);
|
|
let listener = tokio::net::TcpListener::bind(addr).await?;
|
|
axum::serve(listener, app).await
|
|
}
|