rs4a-vapix 0.1.0

Utilities for working with VAPIX
Documentation
use serde::Deserialize;

use crate::{
    soap::SimpleRequest,
    soap_http::{SoapHttpRequest, SoapRequest},
};

pub struct AddActionRuleRequest {
    pub name: String,
    pub enabled: bool,
    pub conditions: Conditions,
    pub primary_action: u16,
}

impl AddActionRuleRequest {
    pub(crate) fn new(name: String, primary_action: u16) -> Self {
        Self {
            name,
            enabled: true,
            conditions: Conditions {
                condition: Vec::new(),
            },
            primary_action,
        }
    }

    pub fn enabled(mut self, enabled: bool) -> Self {
        self.enabled = enabled;
        self
    }

    pub fn condition(mut self, condition: Condition) -> Self {
        self.conditions.condition.push(condition);
        self
    }
}

impl SoapRequest for AddActionRuleRequest {
    fn to_envelope(self) -> anyhow::Result<String> {
        let Self {
            name,
            enabled,
            conditions,
            primary_action,
        } = self;
        let mut params = String::new();
        params.push_str(r#"<NewActionRule xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tnsaxis="http://www.axis.com/2009/event/topics">"#);
        params.push_str(r#"<Name>"#);
        params.push_str(&name);
        params.push_str(r#"</Name>"#);
        params.push_str(r#"<Enabled>"#);
        params.push_str(&enabled.to_string());
        params.push_str(r#"</Enabled>"#);
        params.push_str(r#"<Conditions>"#);
        for condition in conditions.condition {
            let Condition {
                topic_expression,
                message_content,
            } = condition;
            params.push_str(r#"<Condition>"#);
            params.push_str(r#"<TopicExpression Dialect="http://docs.oasis-open.org/wsn/t-1/TopicExpression/Concrete" xmlns="http://docs.oasis-open.org/wsn/b-2">"#);
            params.push_str(&topic_expression);
            params.push_str(r#"</TopicExpression>"#);
            params.push_str(r#"<MessageContent Dialect="http://www.onvif.org/ver10/tev/messageContentFilter/ItemFilter" xmlns="http://docs.oasis-open.org/wsn/b-2">"#);
            params.push_str(&message_content);
            params.push_str(r#"</MessageContent>"#);
            params.push_str(r#"</Condition>"#);
        }
        params.push_str(r#"</Conditions>"#);
        params.push_str(r#"<PrimaryAction>"#);
        params.push_str(&primary_action.to_string());
        params.push_str(r#"</PrimaryAction>"#);
        params.push_str(r#"</NewActionRule>"#);
        SimpleRequest::<()>::new("http://www.axis.com/vapix/ws/action1", "AddActionRule")
            .params(params)
            .to_envelope()
    }
}

impl SoapHttpRequest for AddActionRuleRequest {
    type Data = AddActionRuleResponse;
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct AddActionRuleResponse {
    #[serde(rename = "RuleID")]
    pub id: u16,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Condition {
    pub topic_expression: String,
    pub message_content: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Conditions {
    pub condition: Vec<Condition>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ActionRule {
    #[serde(rename = "RuleID")]
    pub rule_id: u16,
    pub name: String,
    pub enabled: String,
    pub conditions: Conditions,
    pub primary_action: u16,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ActionRules {
    #[serde(default)]
    pub action_rule: Vec<ActionRule>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct GetActionRulesResponse {
    pub action_rules: ActionRules,
}

#[cfg(test)]
mod tests {
    use crate::{
        services::action1::{action_rules::AddActionRuleResponse, GetActionRulesResponse},
        soap::parse_soap,
    };

    #[test]
    fn can_deserialize_add_action_rule_200_response() {
        let text = include_str!("examples/add_action_rule_200_response.xml");
        let data = parse_soap::<AddActionRuleResponse>(text).unwrap();
        assert_eq!(1, data.id);
    }

    #[test]
    fn can_deserialize_get_action_rules_response() {
        let text = include_str!("examples/get_action_rules_response.xml");
        let data = parse_soap::<GetActionRulesResponse>(text).unwrap();
        assert!(data.action_rules.action_rule.is_empty());
    }
}