use mqttrust::{Mqtt, QoS};
use serde::Serialize;
use crate::jobs::JobTopic;
use super::{JobError, MAX_CLIENT_TOKEN_LEN, MAX_JOB_ID_LEN, MAX_THING_NAME_LEN};
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct DescribeJobExecutionRequest<'a> {
#[serde(rename = "executionNumber")]
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_number: Option<i64>,
#[serde(rename = "includeJobDocument")]
#[serde(skip_serializing_if = "Option::is_none")]
pub include_job_document: Option<bool>,
#[serde(rename = "clientToken")]
#[serde(skip_serializing_if = "Option::is_none")]
pub client_token: Option<&'a str>,
}
#[derive(Default)]
pub struct Describe<'a> {
job_id: Option<&'a str>,
client_token: Option<&'a str>,
include_job_document: bool,
execution_number: Option<i64>,
}
impl<'a> Describe<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn client_token(self, client_token: &'a str) -> Self {
assert!(client_token.len() < MAX_CLIENT_TOKEN_LEN);
Self {
client_token: Some(client_token),
..self
}
}
pub fn job_id(self, job_id: &'a str) -> Self {
assert!(job_id.len() < MAX_JOB_ID_LEN);
Self {
job_id: Some(job_id),
..self
}
}
pub fn include_job_document(self) -> Self {
Self {
include_job_document: true,
..self
}
}
pub fn execution_number(self, execution_number: i64) -> Self {
Self {
execution_number: Some(execution_number),
..self
}
}
pub fn topic_payload(
self,
client_id: &str,
) -> Result<
(
heapless::String<{ MAX_THING_NAME_LEN + MAX_JOB_ID_LEN + 22 }>,
heapless::Vec<u8, { MAX_CLIENT_TOKEN_LEN + 2 }>,
),
JobError,
> {
let payload = serde_json_core::to_vec(&DescribeJobExecutionRequest {
execution_number: self.execution_number,
include_job_document: self.include_job_document.then(|| true),
client_token: self.client_token,
})
.map_err(|_| JobError::Encoding)?;
Ok((
self.job_id
.map(JobTopic::Get)
.unwrap_or(JobTopic::GetNext)
.format(client_id)?,
payload,
))
}
pub fn send<M: Mqtt>(self, mqtt: &M, qos: QoS) -> Result<(), JobError> {
let (topic, payload) = self.topic_payload(mqtt.client_id())?;
mqtt.publish(topic.as_str(), &payload, qos)?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use serde_json_core::to_string;
#[test]
fn serialize_requests() {
let req = DescribeJobExecutionRequest {
execution_number: Some(1),
include_job_document: Some(true),
client_token: Some("test_client:token"),
};
assert_eq!(
to_string::<_, 512>(&req).unwrap().as_str(),
r#"{"executionNumber":1,"includeJobDocument":true,"clientToken":"test_client:token"}"#
);
}
#[test]
fn topic_payload() {
let (topic, payload) = Describe::new()
.include_job_document()
.execution_number(1)
.client_token("test_client:token")
.topic_payload("test_client")
.unwrap();
assert_eq!(
payload,
br#"{"executionNumber":1,"includeJobDocument":true,"clientToken":"test_client:token"}"#
);
assert_eq!(topic.as_str(), "$aws/things/test_client/jobs/$next/get");
}
#[test]
fn topic_job_id() {
let (topic, payload) = Describe::new()
.include_job_document()
.execution_number(1)
.job_id("test_job_id")
.client_token("test_client:token")
.topic_payload("test_client")
.unwrap();
assert_eq!(
payload,
br#"{"executionNumber":1,"includeJobDocument":true,"clientToken":"test_client:token"}"#
);
assert_eq!(
topic.as_str(),
"$aws/things/test_client/jobs/test_job_id/get"
);
}
}