vapix 0.1.0

Client for AXIS Communications devices' VAPIX API
Documentation
use crate::{Device, Error, Transport};
use serde::{Deserialize, Serialize};

pub(crate) struct JsonService<'a, T: Transport> {
    device: &'a Device<T>,
    uri: http::Uri,
    api_version: String,
}

impl<'a, T: Transport> JsonService<'a, T> {
    pub fn new(device: &'a Device<T>, path_and_query: &str, api_version: String) -> Self {
        Self {
            device,
            uri: device.uri_for(path_and_query).unwrap(),
            api_version,
        }
    }

    async fn inner<RQ, RS>(&self, method: &str, request: Option<RQ>) -> Result<RS, Error<T::Error>>
    where
        RQ: serde::Serialize,
        RS: serde::de::DeserializeOwned,
    {
        #[derive(Serialize)]
        #[serde(rename_all = "camelCase")]
        struct Req<'a, RQ> {
            api_version: &'a str,
            method: &'a str,
            #[serde(skip_serializing_if = "Option::is_none")]
            params: Option<&'a RQ>,
        }
        #[derive(Deserialize)]
        #[serde(rename_all = "camelCase")]
        struct Resp<RS> {
            error: Option<crate::error::RawJsonApiError>,
            data: Option<RS>,
        }

        let req = {
            let json_request = Req {
                api_version: &self.api_version,
                method,
                params: request.as_ref(),
            };
            let json_request = serde_json::to_vec(&json_request).unwrap();

            http::Request::builder()
                .method(http::method::Method::POST)
                .uri(&self.uri)
                .header(http::header::CONTENT_TYPE, "application/json")
                .body(json_request)
                .unwrap()
        };

        let (_resp, resp_body) = self.device.roundtrip(req, "application/json").await?;

        let resp_body: Resp<RS> = serde_json::from_slice(resp_body.as_slice())?;

        if let Some(e) = resp_body.error {
            return Err(e.into());
        }
        if let Some(d) = resp_body.data {
            Ok(d)
        } else {
            Err(Error::Other("response included neither `data` nor `error`"))
        }
    }

    pub async fn call_method<RQ, RS>(&self, method: &str, params: RQ) -> Result<RS, Error<T::Error>>
    where
        RQ: serde::Serialize,
        RS: serde::de::DeserializeOwned,
    {
        self.inner(method, Some(params)).await
    }

    pub async fn call_method_bare<RS>(&self, method: &str) -> Result<RS, Error<T::Error>>
    where
        RS: serde::de::DeserializeOwned,
    {
        let params: Option<()> = None;
        self.inner(method, params).await
    }
}