Skip to main content

middleware_core/
bridge.rs

1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2pub enum BridgeTrafficKind {
3    Topic,
4    Service,
5    Mission,
6}
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum BridgeDropReason {
10    KindNotAllowed,
11    LabelMismatch,
12}
13
14#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
15pub struct BridgeStats {
16    pub forwarded: u64,
17    pub dropped_kind: u64,
18    pub dropped_label: u64,
19}
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct BridgePolicy {
23    pub allow_topic: bool,
24    pub allow_service: bool,
25    pub allow_mission: bool,
26    pub include_labels: Vec<String>,
27}
28
29impl Default for BridgePolicy {
30    fn default() -> Self {
31        Self {
32            allow_topic: true,
33            allow_service: true,
34            allow_mission: true,
35            include_labels: Vec::new(),
36        }
37    }
38}
39
40impl BridgePolicy {
41    pub fn should_forward(&self, kind: BridgeTrafficKind, labels: &[String]) -> bool {
42        let kind_allowed = match kind {
43            BridgeTrafficKind::Topic => self.allow_topic,
44            BridgeTrafficKind::Service => self.allow_service,
45            BridgeTrafficKind::Mission => self.allow_mission,
46        };
47
48        if !kind_allowed {
49            return false;
50        }
51
52        if self.include_labels.is_empty() {
53            return true;
54        }
55
56        self.include_labels
57            .iter()
58            .all(|label| labels.iter().any(|candidate| candidate == label))
59    }
60
61    pub fn evaluate_with_stats(
62        &self,
63        kind: BridgeTrafficKind,
64        labels: &[String],
65        stats: &mut BridgeStats,
66    ) -> bool {
67        let kind_allowed = match kind {
68            BridgeTrafficKind::Topic => self.allow_topic,
69            BridgeTrafficKind::Service => self.allow_service,
70            BridgeTrafficKind::Mission => self.allow_mission,
71        };
72
73        if !kind_allowed {
74            stats.dropped_kind += 1;
75            return false;
76        }
77
78        if !self.include_labels.is_empty() {
79            let labels_match = self
80                .include_labels
81                .iter()
82                .all(|label| labels.iter().any(|candidate| candidate == label));
83            if !labels_match {
84                stats.dropped_label += 1;
85                return false;
86            }
87        }
88
89        stats.forwarded += 1;
90        true
91    }
92}