    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

    use std::{sync::Arc, path::PathBuf};

    use axum::{
        extract::{ws::{WebSocketUpgrade, WebSocket, Message}, State},
        response::Response,
        routing::get,
        Router,
    };

    use tokio::sync::RwLock;
    use tower_http::services::ServeDir;

    use crate::comms::RadarData;

    #[derive(Clone)]
    struct AppState {
        data_lock: Arc<RwLock<RadarData>>
    }

    async fn ws_handler(ws: WebSocketUpgrade, State(state): State<AppState>) -> Response {
        ws.on_upgrade(|socket| handle_socket(socket, state))
    }

    async fn handle_socket(mut socket: WebSocket, state: AppState) {
        while let Some(msg) = socket.recv().await {
            if let Ok(msg) = msg {
                if msg == Message::Text("requestInfo".to_string()) {
                    let data = state.data_lock.read().await;

                    let str = {
                        match serde_json::to_string(&*data) {
                            Ok(json) => json,
                            Err(e) => {
                                log::error!("Could not serialize data into json: {}", e.to_string());
                                log::error!("Sending \"error\" instead");
                                "error".to_string()
                            },
                        }
                    };

                    if socket.send(Message::Text(str)).await.is_err() {
                        // client disconnected
                        return;
                    }
                }
            } else {
                // client disconnected
                return;
            }
        }
    }

    pub async fn run(path: PathBuf, port: u16, data_lock: Arc<RwLock<RadarData>>) -> anyhow::Result<()> {
        let app = Router::new()
            .nest_service("/", ServeDir::new(path))
            .route("/ws", get(ws_handler))
            .with_state(AppState { data_lock });

        let address = format!("0.0.0.0:{}", port);

        axum::Server::bind(&address.parse()?)
            .serve(app.into_make_service())
            .await?;

        Ok(())
    }