diff --git a/haesli_core/src/exchange.rs b/haesli_core/src/exchange.rs index 9bb77d5..56e1e7c 100644 --- a/haesli_core/src/exchange.rs +++ b/haesli_core/src/exchange.rs @@ -1,4 +1,9 @@ -use std::{borrow::Borrow, collections::HashMap, sync::Arc}; +use std::{ + borrow::Borrow, + collections::HashMap, + fmt::{Display, Formatter}, + sync::Arc, +}; use crate::{newtype, Queue}; @@ -9,6 +14,16 @@ pub enum TopicSegment { MultiWildcard, } +impl Display for TopicSegment { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Word(str) => str.fmt(f), + Self::SingleWildcard => f.write_str("*"), + Self::MultiWildcard => f.write_str("#"), + } + } +} + #[derive(Debug)] pub enum ExchangeType { /// Routes a message to a queue if the routing-keys are equal diff --git a/haesli_dashboard/src/lib.rs b/haesli_dashboard/src/lib.rs index 9ef56d1..c1061fc 100644 --- a/haesli_dashboard/src/lib.rs +++ b/haesli_dashboard/src/lib.rs @@ -8,7 +8,7 @@ use axum::{ routing::{get, get_service}, Json, Router, }; -use haesli_core::GlobalData; +use haesli_core::{exchange::ExchangeType, GlobalData}; use serde::Serialize; use tower_http::cors::{Any, CorsLayer}; use tracing::{error, info}; @@ -56,6 +56,7 @@ pub async fn dashboard(global_data: GlobalData) -> anyhow::Result<()> { struct Data { connections: Vec, queues: Vec, + exchanges: Vec, } #[derive(Serialize)] @@ -80,6 +81,20 @@ struct Queue { messages: usize, } +#[derive(Serialize)] +struct Exchange { + name: String, + durable: bool, + bindings: Vec, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Binding { + queue: String, + routing_key: String, +} + async fn get_data(global_data: GlobalData) -> impl IntoResponse { let global_data = global_data.lock(); @@ -112,10 +127,49 @@ async fn get_data(global_data: GlobalData) -> impl IntoResponse { }) .collect(); + let exchanges = global_data.exchanges.values().map(map_exchange).collect(); + let data = Data { connections, queues, + exchanges, }; Json(data) } + +fn map_exchange(exch: &haesli_core::exchange::Exchange) -> Exchange { + Exchange { + name: exch.name.to_string(), + durable: exch.durable, + bindings: match &exch.kind { + ExchangeType::Direct { bindings } => bindings + .iter() + .map(|(name, _)| Binding { + queue: name.clone(), + routing_key: name.clone(), + }) + .collect(), + ExchangeType::Fanout { bindings } => bindings + .iter() + .map(|q| Binding { + queue: q.name.to_string(), + routing_key: "".to_owned(), + }) + .collect(), + ExchangeType::Topic { bindings } => bindings + .iter() + .map(|(segs, q)| Binding { + queue: q.name.to_string(), + routing_key: segs + .iter() + .map(|seg| seg.to_string()) + .collect::>() + .join("."), + }) + .collect(), + ExchangeType::Headers => Vec::new(), + ExchangeType::System => Vec::new(), + }, + } +}