#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BridgeTrafficKind {
Topic,
Service,
Mission,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BridgeDropReason {
KindNotAllowed,
LabelMismatch,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct BridgeStats {
pub forwarded: u64,
pub dropped_kind: u64,
pub dropped_label: u64,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BridgePolicy {
pub allow_topic: bool,
pub allow_service: bool,
pub allow_mission: bool,
pub include_labels: Vec<String>,
}
impl Default for BridgePolicy {
fn default() -> Self {
Self {
allow_topic: true,
allow_service: true,
allow_mission: true,
include_labels: Vec::new(),
}
}
}
impl BridgePolicy {
pub fn should_forward(&self, kind: BridgeTrafficKind, labels: &[String]) -> bool {
let kind_allowed = match kind {
BridgeTrafficKind::Topic => self.allow_topic,
BridgeTrafficKind::Service => self.allow_service,
BridgeTrafficKind::Mission => self.allow_mission,
};
if !kind_allowed {
return false;
}
if self.include_labels.is_empty() {
return true;
}
self.include_labels
.iter()
.all(|label| labels.iter().any(|candidate| candidate == label))
}
pub fn evaluate_with_stats(
&self,
kind: BridgeTrafficKind,
labels: &[String],
stats: &mut BridgeStats,
) -> bool {
let kind_allowed = match kind {
BridgeTrafficKind::Topic => self.allow_topic,
BridgeTrafficKind::Service => self.allow_service,
BridgeTrafficKind::Mission => self.allow_mission,
};
if !kind_allowed {
stats.dropped_kind += 1;
return false;
}
if !self.include_labels.is_empty() {
let labels_match = self
.include_labels
.iter()
.all(|label| labels.iter().any(|candidate| candidate == label));
if !labels_match {
stats.dropped_label += 1;
return false;
}
}
stats.forwarded += 1;
true
}
}