pub mod api;
pub mod auth;
pub mod calls;
pub mod config;
pub mod db;
pub mod error;
pub mod hub;
pub mod ocpp;
pub mod reservation;
pub mod server;
pub mod smart;
pub mod state;
pub mod tariff;
pub mod tls;
pub mod tz;
use std::sync::Arc;
use axum::Router;
use axum::routing::any;
use tokio::net::TcpListener;
use tokio::sync::{Semaphore, watch};
use crate::config::Config;
use crate::state::{App, AppState};
pub fn ocpp_router(app: App) -> Router {
Router::new()
.route("/{*path}", any(ocpp::handshake::upgrade))
.with_state(app)
}
pub fn build_state(cfg: Config, db: db::Db, shutdown: watch::Receiver<bool>) -> App {
Arc::new(AppState {
auth: auth::Authenticator::new(cfg.auth_concurrency),
cfg,
db,
hub: hub::Hub::new(),
ids: ocpp_core::MessageIdGenerator::new(),
zones: tz::Zones::default(),
shutdown,
})
}
pub struct Listeners {
pub ocpp: Option<TcpListener>,
pub ocpp_tls: Option<(TcpListener, Arc<tls::TlsAcceptor>)>,
pub api: TcpListener,
}
pub async fn serve(
app: App,
listeners: Listeners,
shutdown: impl std::future::Future<Output = ()> + Send + 'static,
) -> std::io::Result<()> {
let (stop_tx, stop_rx) = watch::channel(false);
let router = ocpp_router(app.clone());
let mut tasks = Vec::new();
if let Some(l) = listeners.ocpp {
let limit = Arc::new(Semaphore::new(app.cfg.max_connections));
tasks.push(tokio::spawn(server::serve_ocpp(
l,
None,
router.clone(),
limit,
stop_rx.clone(),
)));
}
if let Some((l, acceptor)) = listeners.ocpp_tls {
let limit = Arc::new(Semaphore::new(app.cfg.max_connections));
tasks.push(tokio::spawn(server::serve_ocpp(
l,
Some(acceptor),
router.clone(),
limit,
stop_rx.clone(),
)));
}
reservation::spawn_sweeper(app.clone(), stop_rx.clone());
let mut api_stop = stop_rx.clone();
let api_server =
axum::serve(listeners.api, api::router(app.clone())).with_graceful_shutdown(async move {
let _ = api_stop.changed().await;
});
tokio::spawn(async move {
shutdown.await;
let _ = stop_tx.send(true);
});
let result = api_server.await;
for t in tasks {
let _ = t.await;
}
result
}