Skip to main content

flare_core/common/message/
middleware.rs

1//! 消息处理中间件
2//!
3//! 提供常用的中间件实现
4
5use super::pipeline::{MessageContext, MessageMiddleware};
6use crate::common::error::Result;
7use crate::common::platform::wall_clock_ms;
8use crate::common::protocol::Frame;
9use async_trait::async_trait;
10use std::sync::Arc;
11use tracing::{debug, info, warn};
12
13/// 日志中间件
14///
15/// 记录所有消息的日志
16pub struct LoggingMiddleware {
17    name: String,
18    log_level: LogLevel,
19}
20
21#[derive(Clone, Copy)]
22pub enum LogLevel {
23    Debug,
24    Info,
25    Warn,
26}
27
28impl LoggingMiddleware {
29    /// 创建新的日志中间件
30    pub fn new(name: impl Into<String>) -> Self {
31        Self {
32            name: name.into(),
33            log_level: LogLevel::Info,
34        }
35    }
36
37    /// 设置日志级别
38    pub fn with_level(mut self, level: LogLevel) -> Self {
39        self.log_level = level;
40        self
41    }
42}
43
44#[async_trait]
45impl MessageMiddleware for LoggingMiddleware {
46    async fn before(&self, ctx: &MessageContext) -> Result<Option<Frame>> {
47        match self.log_level {
48            LogLevel::Debug => {
49                debug!(
50                    connection_id = ?ctx.connection_id,
51                    message_id = %ctx.frame.message_id,
52                    "Processing message"
53                );
54            }
55            LogLevel::Info => {
56                info!(
57                    connection_id = ?ctx.connection_id,
58                    message_id = %ctx.frame.message_id,
59                    "Processing message"
60                );
61            }
62            LogLevel::Warn => {
63                warn!(
64                    connection_id = ?ctx.connection_id,
65                    message_id = %ctx.frame.message_id,
66                    "Processing message"
67                );
68            }
69        }
70        Ok(None)
71    }
72
73    fn name(&self) -> &str {
74        &self.name
75    }
76
77    fn priority(&self) -> u32 {
78        10 // 高优先级,最先执行
79    }
80}
81
82/// 性能监控中间件
83///
84/// 记录消息处理耗时
85pub struct MetricsMiddleware {
86    name: String,
87}
88
89impl MetricsMiddleware {
90    /// 创建新的性能监控中间件
91    pub fn new(name: impl Into<String>) -> Self {
92        Self { name: name.into() }
93    }
94}
95
96#[async_trait]
97impl MessageMiddleware for MetricsMiddleware {
98    async fn before(&self, ctx: &MessageContext) -> Result<Option<Frame>> {
99        // 记录开始时间
100        ctx.set_metadata(
101            "start_time".to_string(),
102            wall_clock_ms().to_le_bytes().to_vec(),
103        )
104        .await;
105        Ok(None)
106    }
107
108    async fn after(&self, ctx: &MessageContext, response: Option<Frame>) -> Result<Option<Frame>> {
109        // 计算处理耗时
110        if let Some(start_bytes) = ctx.get_metadata("start_time").await {
111            let start_ms = u64::from_le_bytes(start_bytes.try_into().unwrap_or([0; 8]));
112            let duration_ms = wall_clock_ms().saturating_sub(start_ms);
113
114            debug!(
115                connection_id = ?ctx.connection_id,
116                message_id = %ctx.frame.message_id,
117                duration_ms,
118                "Message processed"
119            );
120        }
121        Ok(response)
122    }
123
124    fn name(&self) -> &str {
125        &self.name
126    }
127
128    fn priority(&self) -> u32 {
129        20
130    }
131}
132
133/// 验证中间件
134///
135/// 验证消息格式和内容
136pub struct ValidationMiddleware {
137    name: String,
138    #[allow(clippy::type_complexity)]
139    validator: Arc<dyn Fn(&Frame) -> Result<()> + Send + Sync>,
140}
141
142impl ValidationMiddleware {
143    /// 创建新的验证中间件
144    pub fn new<F>(name: impl Into<String>, validator: F) -> Self
145    where
146        F: Fn(&Frame) -> Result<()> + Send + Sync + 'static,
147    {
148        Self {
149            name: name.into(),
150            validator: Arc::new(validator),
151        }
152    }
153}
154
155#[async_trait]
156impl MessageMiddleware for ValidationMiddleware {
157    async fn before(&self, ctx: &MessageContext) -> Result<Option<Frame>> {
158        (self.validator)(&ctx.frame)?;
159        Ok(None)
160    }
161
162    fn name(&self) -> &str {
163        &self.name
164    }
165
166    fn priority(&self) -> u32 {
167        5 // 最高优先级,最先验证
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    use crate::common::MessageParser;
175    use crate::common::platform::wall_clock_ms;
176    use crate::common::protocol::{FrameBuilder, Reliability, ping};
177
178    #[tokio::test]
179    async fn metrics_middleware_records_absolute_start_time_millis() {
180        let frame = FrameBuilder::new()
181            .with_command(crate::common::protocol::Command {
182                r#type: Some(
183                    crate::common::protocol::flare::core::commands::command::Type::System(ping()),
184                ),
185            })
186            .with_reliability(Reliability::BestEffort)
187            .build();
188        let ctx = MessageContext::new(frame, Some("conn-1".to_string()), MessageParser::json());
189        let metrics = MetricsMiddleware::new("metrics");
190
191        let before = wall_clock_ms();
192        metrics.before(&ctx).await.expect("before should succeed");
193        let after = wall_clock_ms();
194
195        let start_bytes = ctx
196            .get_metadata("start_time")
197            .await
198            .expect("metrics should store start_time");
199        let start_ms = u64::from_le_bytes(
200            start_bytes
201                .try_into()
202                .expect("start_time should be a u64 millis value"),
203        );
204
205        assert!(
206            (before..=after).contains(&start_ms),
207            "start_time should be an absolute wall-clock millis timestamp, got {start_ms}, expected within {before}..={after}"
208        );
209    }
210}