use mqttrust::{Mqtt, QoS};
use serde::Serialize;
use crate::jobs::JobTopic;
use super::{JobError, MAX_CLIENT_TOKEN_LEN, MAX_THING_NAME_LEN};
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StartNextPendingJobExecutionRequest<'a> {
#[serde(rename = "stepTimeoutInMinutes")]
#[serde(skip_serializing_if = "Option::is_none")]
pub step_timeout_in_minutes: Option<i64>,
#[serde(rename = "clientToken")]
#[serde(skip_serializing_if = "Option::is_none")]
pub client_token: Option<&'a str>,
}
#[derive(Default)]
pub struct StartNext<'a> {
client_token: Option<&'a str>,
step_timeout_in_minutes: Option<i64>,
}
impl<'a> StartNext<'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 step_timeout_in_minutes(self, step_timeout_in_minutes: i64) -> Self {
Self {
step_timeout_in_minutes: Some(step_timeout_in_minutes),
..self
}
}
pub fn topic_payload(
self,
client_id: &str,
) -> Result<
(
heapless::String<{ MAX_THING_NAME_LEN + 28 }>,
heapless::Vec<u8, { MAX_CLIENT_TOKEN_LEN + 2 }>,
),
JobError,
> {
let payload = serde_json_core::to_vec(&StartNextPendingJobExecutionRequest {
step_timeout_in_minutes: self.step_timeout_in_minutes,
client_token: self.client_token,
})
.map_err(|_| JobError::Encoding)?;
Ok((JobTopic::StartNext.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 = StartNextPendingJobExecutionRequest {
client_token: Some("test_client:token_next_pending"),
step_timeout_in_minutes: Some(50),
};
assert_eq!(
&to_string::<_, 512>(&req).unwrap(),
r#"{"stepTimeoutInMinutes":50,"clientToken":"test_client:token_next_pending"}"#
);
let req_none = StartNextPendingJobExecutionRequest {
client_token: Some("test_client:token_next_pending"),
step_timeout_in_minutes: None,
};
assert_eq!(
&to_string::<_, 512>(&req_none).unwrap(),
r#"{"clientToken":"test_client:token_next_pending"}"#
);
}
#[test]
fn topic_payload() {
let (topic, payload) = StartNext::new()
.client_token("test_client:token_next_pending")
.step_timeout_in_minutes(43)
.topic_payload("test_client")
.unwrap();
assert_eq!(
payload,
br#"{"stepTimeoutInMinutes":43,"clientToken":"test_client:token_next_pending"}"#
);
assert_eq!(topic.as_str(), "$aws/things/test_client/jobs/start-next");
}
}