diff --git a/api/Cargo.toml b/api/Cargo.toml index c933e2f91..15733a9a8 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -11,7 +11,7 @@ members = [ # Define shared dependencies for all workspace members [workspace.dependencies] anyhow = "1.0.86" -chrono = { version = "0.4.38", features = ["serde"] } +chrono = { version = "=0.4.38", features = ["serde"] } serde = { version = "1.0.117", features = ["derive"] } serde_json = { version = "1.0.117", features = ["preserve_order"] } serde_yaml = "0.9.34" diff --git a/api/src/routes/ws/metrics/get_metric.rs b/api/src/routes/ws/metrics/get_metric.rs new file mode 100644 index 000000000..684c25855 --- /dev/null +++ b/api/src/routes/ws/metrics/get_metric.rs @@ -0,0 +1,55 @@ +use anyhow::{anyhow, Result}; +use handlers::metrics::get_metric_handler; +use middleware::AuthenticatedUser; +use serde::Deserialize; +use uuid::Uuid; + +use crate::routes::ws::{ + metrics::metrics_router::{MetricEvent, MetricRoute}, + ws::{WsErrorCode, WsEvent, WsResponseMessage, WsSendMethod}, + ws_router::WsRoutes, + ws_utils::{send_error_message, send_ws_message}, +}; + +#[derive(Deserialize)] +pub struct GetMetricWsRequest { + pub id: Uuid, +} + +pub async fn get_metric(user: &AuthenticatedUser, request: GetMetricWsRequest) -> Result<()> { + tracing::info!( + "Processing WebSocket GET request for metric with ID: {}, user_id: {}", + request.id, + user.id + ); + + let metric = match get_metric_handler(&request.id, &user.id).await { + Ok(metric) => metric, + Err(e) => { + tracing::error!("Error getting metric: {}", e); + send_error_message( + &user.id.to_string(), + WsRoutes::Metrics(MetricRoute::Get), + WsEvent::Metrics(MetricEvent::GetMetric), + WsErrorCode::InternalServerError, + "Failed to get metric.".to_string(), + user, + ) + .await?; + return Err(anyhow!("Error getting metric: {}", e)); + } + }; + + let response_message = WsResponseMessage::new( + WsRoutes::Metrics(MetricRoute::Get), + WsEvent::Metrics(MetricEvent::GetMetric), + metric, + None, + user, + WsSendMethod::SenderOnly, + ); + + send_ws_message(&user.id.to_string(), &response_message).await?; + + Ok(()) +} diff --git a/api/src/routes/ws/metrics/get_metric_data.rs b/api/src/routes/ws/metrics/get_metric_data.rs new file mode 100644 index 000000000..5991432dd --- /dev/null +++ b/api/src/routes/ws/metrics/get_metric_data.rs @@ -0,0 +1,60 @@ +use anyhow::{anyhow, Result}; +use handlers::metrics::get_metric_data_handler::{GetMetricDataRequest, MetricDataResponse}; +use middleware::AuthenticatedUser; +use serde::Deserialize; +use uuid::Uuid; + +use crate::routes::ws::{ + metrics::metrics_router::{MetricEvent, MetricRoute}, + ws::{WsErrorCode, WsEvent, WsResponseMessage, WsSendMethod}, + ws_router::WsRoutes, + ws_utils::{send_error_message, send_ws_message}, +}; + +#[derive(Deserialize)] +pub struct GetMetricDataWsRequest { + pub id: Uuid, + pub limit: Option, +} + +pub async fn get_metric_data(user: &AuthenticatedUser, request: GetMetricDataWsRequest) -> Result<()> { + tracing::info!( + "Processing WebSocket GET request for metric data with ID: {}", + request.id + ); + + let handler_request = GetMetricDataRequest { + metric_id: request.id, + limit: request.limit, + }; + + let response = match handlers::metrics::get_metric_data_handler(handler_request, user.clone()).await { + Ok(response) => response, + Err(e) => { + tracing::error!("Error getting metric data: {}", e); + send_error_message( + &user.id.to_string(), + WsRoutes::Metrics(MetricRoute::GetData), + WsEvent::Metrics(MetricEvent::FetchingData), + WsErrorCode::InternalServerError, + "Failed to get metric data.".to_string(), + user, + ) + .await?; + return Err(anyhow!("Error getting metric data: {}", e)); + } + }; + + let response_message = WsResponseMessage::new( + WsRoutes::Metrics(MetricRoute::GetData), + WsEvent::Metrics(MetricEvent::FetchingData), + response, + None, + user, + WsSendMethod::SenderOnly, + ); + + send_ws_message(&user.id.to_string(), &response_message).await?; + + Ok(()) +} \ No newline at end of file diff --git a/api/src/routes/ws/metrics/metrics_router.rs b/api/src/routes/ws/metrics/metrics_router.rs new file mode 100644 index 000000000..d805fee8b --- /dev/null +++ b/api/src/routes/ws/metrics/metrics_router.rs @@ -0,0 +1,63 @@ +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use uuid::Uuid; + +use middleware::AuthenticatedUser; + +use super::{ + get_metric::{get_metric, GetMetricWsRequest}, + get_metric_data::get_metric_data, +}; + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub enum MetricRoute { + #[serde(rename = "/metrics/get")] + Get, + #[serde(rename = "/metrics/get_data")] + GetData, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub enum MetricEvent { + GetMetric, + FetchingData, +} + +pub async fn metrics_router( + route: MetricRoute, + data: Value, + user: &AuthenticatedUser, +) -> Result<()> { + match route { + MetricRoute::Get => { + let request = match serde_json::from_value::(data) { + Ok(id) => id, + Err(e) => return Err(anyhow!("Error parsing metric ID: {}", e)), + }; + + get_metric(user, request).await?; + } + MetricRoute::GetData => { + let req = match serde_json::from_value(data) { + Ok(req) => req, + Err(e) => return Err(anyhow!("Error parsing request: {}", e)), + }; + + get_metric_data(user, req).await?; + } + }; + + Ok(()) +} + +impl MetricRoute { + pub fn from_str(path: &str) -> Result { + match path { + "/metrics/get" => Ok(Self::Get), + "/metrics/get_data" => Ok(Self::GetData), + _ => Err(anyhow!("Invalid path")), + } + } +} diff --git a/api/src/routes/ws/metrics/mod.rs b/api/src/routes/ws/metrics/mod.rs new file mode 100644 index 000000000..97974b536 --- /dev/null +++ b/api/src/routes/ws/metrics/mod.rs @@ -0,0 +1,5 @@ +pub mod metrics_router; +pub mod get_metric; +pub mod get_metric_data; + +pub use metrics_router::*; \ No newline at end of file