konnektoren_core/commands/
command_bus.rs

1use 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}