unifly-api 0.8.0

Async Rust client, reactive data layer, and domain model for UniFi controller APIs
Documentation
use crate::command::{Command, CommandResult};
use crate::core_error::CoreError;
use crate::model::FirewallAction;

use super::super::{
    CommandContext, build_acl_filter_value, merge_acl_filter_value, require_integration,
    require_uuid,
};

pub(super) async fn route(ctx: &CommandContext, cmd: Command) -> Result<CommandResult, CoreError> {
    let integration = ctx.integration.as_ref();
    let site_id = ctx.site_id;

    match cmd {
        Command::CreateAclRule(req) => {
            let (ic, sid) = require_integration(integration, site_id, "CreateAclRule")?;
            let action_str = match req.action {
                FirewallAction::Allow => "ALLOW",
                FirewallAction::Block => "BLOCK",
                FirewallAction::Reject => "REJECT",
            };
            let body = crate::integration_types::AclRuleCreateUpdate {
                name: req.name,
                rule_type: req.rule_type,
                action: action_str.into(),
                enabled: req.enabled,
                description: req.description,
                source_filter: Some(build_acl_filter_value(
                    &req.source_zone_id,
                    req.source_port.as_deref(),
                    req.protocol.as_deref(),
                )),
                destination_filter: Some(build_acl_filter_value(
                    &req.destination_zone_id,
                    req.destination_port.as_deref(),
                    req.protocol.as_deref(),
                )),
                enforcing_device_filter: req.enforcing_device_filter,
            };
            ic.create_acl_rule(&sid, &body).await?;
            Ok(CommandResult::Ok)
        }
        Command::UpdateAclRule { id, update } => {
            let (ic, sid) = require_integration(integration, site_id, "UpdateAclRule")?;
            let uuid = require_uuid(&id)?;
            let existing = ic.get_acl_rule(&sid, &uuid).await?;
            let action_str = match update.action {
                Some(FirewallAction::Allow) => "ALLOW".into(),
                Some(FirewallAction::Block) => "BLOCK".into(),
                Some(FirewallAction::Reject) => "REJECT".into(),
                None => existing.action,
            };
            let body = crate::integration_types::AclRuleCreateUpdate {
                name: update.name.unwrap_or(existing.name),
                rule_type: update.rule_type.unwrap_or(existing.rule_type),
                action: action_str,
                enabled: update.enabled.unwrap_or(existing.enabled),
                description: update.description.or(existing.description),
                source_filter: merge_acl_filter_value(
                    existing.source_filter,
                    update.source_zone_id.as_ref(),
                    update.source_port.as_deref(),
                    update.protocol.as_deref(),
                ),
                destination_filter: merge_acl_filter_value(
                    existing.destination_filter,
                    update.destination_zone_id.as_ref(),
                    update.destination_port.as_deref(),
                    update.protocol.as_deref(),
                ),
                enforcing_device_filter: existing.enforcing_device_filter,
            };
            ic.update_acl_rule(&sid, &uuid, &body).await?;
            Ok(CommandResult::Ok)
        }
        Command::DeleteAclRule { id } => {
            let (ic, sid) = require_integration(integration, site_id, "DeleteAclRule")?;
            let uuid = require_uuid(&id)?;
            ic.delete_acl_rule(&sid, &uuid).await?;
            Ok(CommandResult::Ok)
        }
        Command::ReorderAclRules { ordered_ids } => {
            let (ic, sid) = require_integration(integration, site_id, "ReorderAclRules")?;
            let uuids: Result<Vec<uuid::Uuid>, _> = ordered_ids.iter().map(require_uuid).collect();
            let body = crate::integration_types::AclRuleOrdering {
                ordered_acl_rule_ids: uuids?,
            };
            ic.set_acl_rule_ordering(&sid, &body).await?;
            Ok(CommandResult::Ok)
        }
        _ => unreachable!("acl::route received non-acl command"),
    }
}