konnektoren_core/commands/
command_bus.rs1use super::{Command, CommandTrait, CommandType};
2use std::collections::HashMap;
3use std::sync::{Arc, Mutex};
4
5type CommandHandler = Arc<dyn Fn(Command) + Send + Sync>;
6
7#[derive(Default, Clone)]
8pub struct CommandBus {
9 pub listeners: Arc<Mutex<HashMap<CommandType, Vec<CommandHandler>>>>,
10}
11
12impl CommandBus {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn subscribe<F>(&self, command_type: CommandType, callback: F)
18 where
19 F: Fn(Command) + Send + Sync + 'static,
20 {
21 let mut listeners = self.listeners.lock().unwrap();
22 listeners
23 .entry(command_type)
24 .or_default()
25 .push(Arc::new(callback));
26 }
27
28 pub fn publish(&self, command: Command) {
29 let listeners = self.listeners.lock().unwrap();
30 if let Some(handlers) = listeners.get(&command.get_type()) {
31 for handler in handlers {
32 handler(command.clone());
33 }
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use crate::commands::GameCommand;
41
42 use super::super::{Command, CommandType};
43 use super::*;
44 use std::sync::Arc;
45 use std::sync::atomic::{AtomicUsize, Ordering};
46
47 #[test]
48 fn test_command_bus() {
49 let command_bus = CommandBus::new();
50 let counter = Arc::new(AtomicUsize::new(0));
51 let counter_clone = counter.clone();
52 command_bus.subscribe(CommandType::Game, move |command| {
53 if let Command::Game(_) = command {
54 counter_clone.fetch_add(1, Ordering::SeqCst);
55 }
56 });
57
58 command_bus.publish(Command::Game(GameCommand::NextChallenge));
59 assert_eq!(counter.load(Ordering::SeqCst), 1);
60 }
61}