#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionSelector {
Cloud,
ScopeMode,
Hub,
RequestPlacement,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelayPolicy {
DirectOnly,
CloudRelayAllowed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RoutePolicy {
pub execution: ExecutionSelector,
pub relay: RelayPolicy,
}
const DIRECT_CLOUD: RoutePolicy = RoutePolicy {
execution: ExecutionSelector::Cloud,
relay: RelayPolicy::DirectOnly,
};
const DIRECT_SCOPE: RoutePolicy = RoutePolicy {
execution: ExecutionSelector::ScopeMode,
relay: RelayPolicy::DirectOnly,
};
const DIRECT_HUB: RoutePolicy = RoutePolicy {
execution: ExecutionSelector::Hub,
relay: RelayPolicy::DirectOnly,
};
const RELAYABLE_HUB: RoutePolicy = RoutePolicy {
execution: ExecutionSelector::Hub,
relay: RelayPolicy::CloudRelayAllowed,
};
const REQUEST_PLACEMENT: RoutePolicy = RoutePolicy {
execution: ExecutionSelector::RequestPlacement,
relay: RelayPolicy::DirectOnly,
};
include!("routing.generated.rs");
pub fn route_policy_for_target(target: &str) -> Option<RoutePolicy> {
if !target.starts_with(TARGET_PREFIX) {
return None;
}
if SCOPE_MODE_TARGETS.contains(&target) {
return Some(DIRECT_SCOPE);
}
if CLOUD_TARGETS.contains(&target) {
return Some(DIRECT_CLOUD);
}
if CLOUD_RELAY_TARGETS.contains(&target) {
return Some(RELAYABLE_HUB);
}
if REQUEST_PLACEMENT_PREFIXES
.iter()
.any(|prefix| target.starts_with(prefix))
{
return Some(REQUEST_PLACEMENT);
}
if HUB_PREFIXES.iter().any(|prefix| target.starts_with(prefix)) {
return Some(DIRECT_HUB);
}
if CLOUD_PREFIXES
.iter()
.any(|prefix| target.starts_with(prefix))
{
return Some(DIRECT_CLOUD);
}
Some(DIRECT_SCOPE)
}
pub fn request_placement(payload: &str) -> Option<crate::messaging::Placement> {
let call: crate::FacadeCall = serde_json::from_str(payload).ok()?;
serde_json::from_value(call.input.get("placement")?.clone()).ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn exact_exceptions_win_over_domain_defaults() {
assert_eq!(
route_policy_for_target("/app/scope/context/get"),
Some(DIRECT_SCOPE)
);
assert_eq!(
route_policy_for_target(crate::plugin::INSTALLED_LIST_TARGET),
Some(RELAYABLE_HUB)
);
assert_eq!(
route_policy_for_target(crate::topology::GET_TARGET),
Some(RELAYABLE_HUB)
);
assert_eq!(
route_policy_for_target(crate::plugin::ADD_START_TARGET),
Some(DIRECT_HUB)
);
}
#[test]
fn domains_select_their_authoritative_executor() {
assert_eq!(
route_policy_for_target("/app/scope/member/list"),
Some(DIRECT_CLOUD)
);
assert_eq!(
route_policy_for_target("/app/messaging/provider/list"),
Some(REQUEST_PLACEMENT)
);
assert_eq!(
route_policy_for_target("/app/object-storage/session/acquire"),
Some(DIRECT_HUB)
);
assert_eq!(
route_policy_for_target("/app/runtime/status/list"),
Some(DIRECT_HUB)
);
assert_eq!(
route_policy_for_target(crate::topology::CHANGED_TARGET),
Some(DIRECT_HUB)
);
assert_eq!(
route_policy_for_target(crate::device_topology::GET_TARGET),
Some(DIRECT_SCOPE)
);
assert_eq!(
route_policy_for_target(crate::device_topology::CHANGED_TARGET),
Some(DIRECT_SCOPE)
);
assert_eq!(
route_policy_for_target("/app/device/list"),
Some(DIRECT_SCOPE)
);
}
#[test]
fn legacy_targets_are_outside_the_contract() {
assert_eq!(route_policy_for_target("/scope/get"), None);
assert_eq!(route_policy_for_target("/chat"), None);
}
#[test]
fn placement_is_read_only_from_the_canonical_input() {
assert_eq!(
request_placement(r#"{"control":{"mode":"direct"},"input":{"placement":"local"}}"#),
Some(crate::messaging::Placement::Local)
);
assert_eq!(request_placement(r#"{"placement":"cloud"}"#), None);
assert_eq!(
request_placement(r#"{"control":{"mode":"direct"},"input":{}}"#),
None
);
}
}