1use axum::extract::{Path, State, WebSocketUpgrade};
2use axum::http::Method;
3use axum::response::Response;
4use axum::routing::get;
5use axum::{Json, Router};
6use ezrtc::protocol::SessionId;
7use serde::{Deserialize, Serialize};
8use tower_http::cors::{Any, CorsLayer};
9
10use crate::one_to_many;
11
12#[derive(Default, Clone)]
13pub struct ServerState {
14 one_to_many_connections: one_to_many::Connections,
15 one_to_many_sessions: one_to_many::Sessions,
16 one_to_many_pings: one_to_many::Pings,
17}
18
19#[derive(Serialize, Deserialize)]
20struct RootMessage {
21 status: u8,
22 build: String,
23}
24
25#[derive(Serialize, Deserialize)]
26struct StatusMessage {
27 online: bool,
28 metadata: Option<serde_json::Value>,
29}
30
31const VERSION: &str = env!("CARGO_PKG_VERSION");
32
33async fn root() -> Json<RootMessage> {
34 Json(RootMessage {
35 status: 200,
36 build: VERSION.to_string(),
37 })
38}
39
40#[allow(clippy::unused_async)]
41async fn health_handler() -> &'static str {
42 "OK"
43}
44
45#[allow(clippy::unused_async)]
46async fn one_to_many_handler(State(state): State<ServerState>, ws: WebSocketUpgrade) -> Response {
47 ws.on_upgrade(move |socket| one_to_many::user_connected(socket, state.one_to_many_connections, state.one_to_many_sessions, state.one_to_many_pings))
48}
49
50async fn status_handler(Path(session_id): Path<String>, State(state): State<ServerState>) -> Json<StatusMessage> {
51 let pings = state.one_to_many_pings.lock().unwrap().clone();
52
53 let ping = pings
55 .iter()
56 .find_map(|(_k, v)| if v.session_id == Some(SessionId::new(session_id.clone())) { Some(v.clone()) } else { None });
57
58 match ping {
59 Some(ping) => Json(StatusMessage { online: ping.online, metadata: ping.metadata.clone() }),
60 None => Json(StatusMessage { online: false, metadata: None }),
61 }
62}
63
64pub fn create(server_state: ServerState) -> Router {
65 Router::new()
66 .route("/health", get(health_handler))
67 .route("/", get(root))
68 .route("/one-to-many", get(one_to_many_handler))
69 .route("/status/:id", get(status_handler))
70 .layer(CorsLayer::new().allow_methods([Method::GET]).allow_origin(Any))
71 .with_state(server_state)
72}