flare_core/common/message/
pipeline.rs1use crate::common::MessageParser;
6use crate::common::error::{FlareError, Result};
7use crate::common::protocol::Frame;
8use crate::transport::events::ConnectionEvent;
9use async_trait::async_trait;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12
13#[derive(Clone)]
17pub struct MessageContext {
18 pub frame: Frame,
20 pub connection_id: Option<String>,
22 pub parser: MessageParser,
24 pub metadata: Arc<RwLock<std::collections::HashMap<String, Vec<u8>>>>,
26}
27
28impl MessageContext {
29 pub fn new(frame: Frame, connection_id: Option<String>, parser: MessageParser) -> Self {
31 Self {
32 frame,
33 connection_id,
34 parser,
35 metadata: Arc::new(RwLock::new(std::collections::HashMap::new())),
36 }
37 }
38
39 pub async fn set_metadata(&self, key: String, value: Vec<u8>) {
41 let mut meta = self.metadata.write().await;
42 meta.insert(key, value);
43 }
44
45 pub async fn get_metadata(&self, key: &str) -> Option<Vec<u8>> {
47 let meta = self.metadata.read().await;
48 meta.get(key).cloned()
49 }
50}
51
52#[async_trait]
56pub trait MessageMiddleware: Send + Sync {
57 async fn before(&self, ctx: &MessageContext) -> Result<Option<Frame>> {
67 let _ = ctx;
68 Ok(None)
69 }
70
71 async fn after(&self, ctx: &MessageContext, response: Option<Frame>) -> Result<Option<Frame>> {
82 let _ = (ctx, response);
83 Ok(None)
84 }
85
86 fn name(&self) -> &str {
88 "UnknownMiddleware"
89 }
90
91 fn priority(&self) -> u32 {
93 100
94 }
95}
96
97pub type ArcMessageMiddleware = Arc<dyn MessageMiddleware>;
99
100#[async_trait]
104pub trait MessageProcessor: Send + Sync {
105 async fn process(&self, ctx: &MessageContext) -> Result<Option<Frame>>;
115
116 fn name(&self) -> &str {
118 "UnknownProcessor"
119 }
120}
121
122pub type ArcMessageProcessor = Arc<dyn MessageProcessor>;
124
125#[derive(Clone)]
132pub struct MessagePipeline {
133 middlewares: Arc<RwLock<Arc<Vec<ArcMessageMiddleware>>>>,
135 processors: Arc<RwLock<Arc<Vec<ArcMessageProcessor>>>>,
137 parser: Arc<tokio::sync::Mutex<MessageParser>>,
139}
140
141impl MessagePipeline {
142 pub fn new(parser: MessageParser) -> Self {
144 Self {
145 middlewares: Arc::new(RwLock::new(Arc::new(Vec::new()))),
146 processors: Arc::new(RwLock::new(Arc::new(Vec::new()))),
147 parser: Arc::new(tokio::sync::Mutex::new(parser)),
148 }
149 }
150
151 pub async fn update_parser(&self, parser: MessageParser) {
153 let mut p = self.parser.lock().await;
154 *p = parser;
155 }
156
157 pub async fn add_middleware(&self, middleware: ArcMessageMiddleware) {
159 let mut middlewares = self.middlewares.write().await;
160 let mut next = (**middlewares).clone();
161 next.push(middleware);
162 next.sort_by_key(|m| m.priority());
164 *middlewares = Arc::new(next);
165 }
166
167 pub async fn remove_middleware(&self, middleware: &ArcMessageMiddleware) {
169 let mut middlewares = self.middlewares.write().await;
170 let mut next = (**middlewares).clone();
171 next.retain(|m| !Arc::ptr_eq(m, middleware));
172 *middlewares = Arc::new(next);
173 }
174
175 pub async fn add_processor(&self, processor: ArcMessageProcessor) {
177 let mut processors = self.processors.write().await;
178 let mut next = (**processors).clone();
179 next.push(processor);
180 *processors = Arc::new(next);
181 }
182
183 pub async fn remove_processor(&self, processor: &ArcMessageProcessor) {
185 let mut processors = self.processors.write().await;
186 let mut next = (**processors).clone();
187 next.retain(|p| !Arc::ptr_eq(p, processor));
188 *processors = Arc::new(next);
189 }
190
191 pub async fn process_raw(
202 &self,
203 data: &[u8],
204 connection_id: Option<&str>,
205 ) -> Result<Option<Vec<u8>>> {
206 let parser = self.parser.lock().await;
208 let frame = parser.parse(data).map_err(|e| {
209 FlareError::deserialization_error(format!("Failed to parse message: {}", e))
210 })?;
211 let parser_snapshot = parser.clone();
212 drop(parser);
213
214 let response = self
216 .process_frame_with_parser(&frame, connection_id, parser_snapshot.clone())
217 .await?;
218
219 if let Some(response_frame) = response {
221 let response_data = parser_snapshot.serialize(&response_frame).map_err(|e| {
222 FlareError::encoding_error(format!("Failed to serialize response: {}", e))
223 })?;
224 Ok(Some(response_data))
225 } else {
226 Ok(None)
227 }
228 }
229
230 async fn middleware_snapshot(&self) -> Arc<Vec<ArcMessageMiddleware>> {
231 let middlewares = self.middlewares.read().await;
232 Arc::clone(&middlewares)
233 }
234
235 async fn processor_snapshot(&self) -> Arc<Vec<ArcMessageProcessor>> {
236 let processors = self.processors.read().await;
237 Arc::clone(&processors)
238 }
239
240 pub async fn process_frame(
251 &self,
252 frame: &Frame,
253 connection_id: Option<&str>,
254 ) -> Result<Option<Frame>> {
255 let parser = self.parser.lock().await;
256 let parser_snapshot = parser.clone();
257 drop(parser);
258
259 self.process_frame_with_parser(frame, connection_id, parser_snapshot)
260 .await
261 }
262
263 async fn process_frame_with_parser(
264 &self,
265 frame: &Frame,
266 connection_id: Option<&str>,
267 parser: MessageParser,
268 ) -> Result<Option<Frame>> {
269 let ctx = MessageContext::new(frame.clone(), connection_id.map(|s| s.to_string()), parser);
271
272 let middlewares = self.middleware_snapshot().await;
274 for middleware in middlewares.iter() {
275 if let Some(response) = middleware.before(&ctx).await? {
276 return Ok(Some(response));
278 }
279 }
280
281 let processors = self.processor_snapshot().await;
283 let mut response = None;
284 for processor in processors.iter() {
285 if let Some(resp) = processor.process(&ctx).await? {
286 response = Some(resp);
287 break; }
289 }
290
291 let middlewares = self.middleware_snapshot().await;
293 for middleware in middlewares.iter() {
294 if let Some(modified_response) = middleware.after(&ctx, response.clone()).await? {
295 response = Some(modified_response);
296 }
297 }
298
299 Ok(response)
300 }
301
302 pub async fn handle_connection_event(
308 &self,
309 _event: &ConnectionEvent,
310 _connection_id: Option<&str>,
311 ) -> Result<()> {
312 let middlewares = self.middleware_snapshot().await;
314 for _middleware in middlewares.iter() {
315 }
318 Ok(())
319 }
320}
321
322impl Default for MessagePipeline {
323 fn default() -> Self {
324 Self::new(MessageParser::protobuf())
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 use crate::common::protocol::{
332 Command, FrameBuilder, Reliability, SerializationFormat, frame_with_system_command, ping,
333 pong,
334 };
335 use tokio::sync::{Mutex, oneshot};
336
337 struct BlockingMiddleware {
338 entered_tx: Mutex<Option<oneshot::Sender<()>>>,
339 release_rx: Mutex<Option<oneshot::Receiver<()>>>,
340 }
341
342 #[async_trait]
343 impl MessageMiddleware for BlockingMiddleware {
344 async fn before(&self, _ctx: &MessageContext) -> Result<Option<Frame>> {
345 if let Some(tx) = self.entered_tx.lock().await.take() {
346 let _ = tx.send(());
347 }
348 if let Some(rx) = self.release_rx.lock().await.take() {
349 let _ = rx.await;
350 }
351 Ok(None)
352 }
353 }
354
355 struct NoopMiddleware;
356
357 #[async_trait]
358 impl MessageMiddleware for NoopMiddleware {}
359
360 struct ParserUpdatingProcessor {
361 pipeline: MessagePipeline,
362 }
363
364 #[async_trait]
365 impl MessageProcessor for ParserUpdatingProcessor {
366 async fn process(&self, _ctx: &MessageContext) -> Result<Option<Frame>> {
367 self.pipeline.update_parser(MessageParser::protobuf()).await;
368 Ok(Some(frame_with_system_command(
369 pong(),
370 Reliability::BestEffort,
371 )))
372 }
373 }
374
375 #[tokio::test]
376 async fn middleware_updates_do_not_wait_for_inflight_middleware_to_finish() {
377 let pipeline = MessagePipeline::new(MessageParser::json());
378 let (entered_tx, entered_rx) = oneshot::channel();
379 let (release_tx, release_rx) = oneshot::channel();
380 pipeline
381 .add_middleware(Arc::new(BlockingMiddleware {
382 entered_tx: Mutex::new(Some(entered_tx)),
383 release_rx: Mutex::new(Some(release_rx)),
384 }))
385 .await;
386
387 let frame = FrameBuilder::new()
388 .with_command(Command {
389 r#type: Some(
390 crate::common::protocol::flare::core::commands::command::Type::System(ping()),
391 ),
392 })
393 .with_reliability(Reliability::BestEffort)
394 .build();
395 let processing = {
396 let pipeline = pipeline.clone();
397 tokio::spawn(async move { pipeline.process_frame(&frame, Some("conn-1")).await })
398 };
399
400 entered_rx.await.expect("blocking middleware should start");
401 let add_result = tokio::time::timeout(
402 std::time::Duration::from_millis(50),
403 pipeline.add_middleware(Arc::new(NoopMiddleware)),
404 )
405 .await;
406
407 let _ = release_tx.send(());
408 processing
409 .await
410 .expect("pipeline task should not panic")
411 .expect("pipeline should succeed");
412
413 assert!(
414 add_result.is_ok(),
415 "middleware updates should use a copy-on-write snapshot and avoid waiting for in-flight middleware"
416 );
417 }
418
419 #[tokio::test]
420 async fn process_raw_serializes_response_with_request_parser_snapshot() {
421 let json_parser = MessageParser::json();
422 let pipeline = MessagePipeline::new(json_parser.clone());
423 pipeline
424 .add_processor(Arc::new(ParserUpdatingProcessor {
425 pipeline: pipeline.clone(),
426 }))
427 .await;
428 let request = frame_with_system_command(ping(), Reliability::BestEffort);
429 let request_data = json_parser
430 .serialize(&request)
431 .expect("json request should serialize");
432
433 let response_data = pipeline
434 .process_raw(&request_data, Some("conn-1"))
435 .await
436 .expect("pipeline should process request")
437 .expect("processor should produce response");
438
439 let response = json_parser.parse_with_format(&response_data, SerializationFormat::Json).expect(
440 "response should use the same parser snapshot as request even if parser is updated mid-pipeline",
441 );
442 let format = response
443 .command
444 .and_then(|command| command.r#type)
445 .and_then(|kind| match kind {
446 crate::common::protocol::flare::core::commands::command::Type::System(system) => {
447 SerializationFormat::try_from(system.format).ok()
448 }
449 _ => None,
450 })
451 .expect("response should be a system command");
452 assert_eq!(format, SerializationFormat::Protobuf);
453 }
454}