summaryrefslogtreecommitdiffstats
path: root/crates/core/c8y_smartrest/src/smartrest_serializer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/core/c8y_smartrest/src/smartrest_serializer.rs')
-rw-r--r--crates/core/c8y_smartrest/src/smartrest_serializer.rs367
1 files changed, 367 insertions, 0 deletions
diff --git a/crates/core/c8y_smartrest/src/smartrest_serializer.rs b/crates/core/c8y_smartrest/src/smartrest_serializer.rs
new file mode 100644
index 00000000..81e7ed4f
--- /dev/null
+++ b/crates/core/c8y_smartrest/src/smartrest_serializer.rs
@@ -0,0 +1,367 @@
+use crate::error::SmartRestSerializerError;
+use csv::{QuoteStyle, WriterBuilder};
+use json_sm::{SoftwareOperationStatus, SoftwareUpdateResponse};
+use serde::{Deserialize, Serialize, Serializer};
+
+type SmartRest = String;
+
+#[derive(Debug)]
+pub enum CumulocitySupportedOperations {
+ C8ySoftwareUpdate,
+ C8yLogFileRequest,
+}
+
+impl From<CumulocitySupportedOperations> for &'static str {
+ fn from(op: CumulocitySupportedOperations) -> Self {
+ match op {
+ CumulocitySupportedOperations::C8ySoftwareUpdate => "c8y_SoftwareUpdate",
+ CumulocitySupportedOperations::C8yLogFileRequest => "c8y_LogfileRequest",
+ }
+ }
+}
+
+pub trait SmartRestSerializer<'a>
+where
+ Self: Serialize,
+{
+ fn to_smartrest(&self) -> Result<SmartRest, SmartRestSerializerError> {
+ serialize_smartrest(self)
+ }
+}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSetSupportedLogType {
+ pub message_id: &'static str,
+ pub supported_operations: Vec<&'static str>,
+}
+
+impl Default for SmartRestSetSupportedLogType {
+ fn default() -> Self {
+ Self {
+ message_id: "118",
+ supported_operations: vec!["software-management".into()],
+ }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestSetSupportedLogType {}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSetSupportedOperations {
+ pub message_id: &'static str,
+ pub supported_operations: Vec<&'static str>,
+}
+
+impl Default for SmartRestSetSupportedOperations {
+ fn default() -> Self {
+ Self {
+ message_id: "114",
+ supported_operations: vec![
+ CumulocitySupportedOperations::C8ySoftwareUpdate.into(),
+ CumulocitySupportedOperations::C8yLogFileRequest.into(),
+ ],
+ }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestSetSupportedOperations {}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSoftwareModuleItem {
+ pub software: String,
+ pub version: Option<String>,
+ pub url: Option<String>,
+}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestGetPendingOperations {
+ pub id: &'static str,
+}
+
+impl Default for SmartRestGetPendingOperations {
+ fn default() -> Self {
+ Self { id: "500" }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestGetPendingOperations {}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSetOperationToExecuting {
+ pub message_id: &'static str,
+ pub operation: &'static str,
+}
+
+impl SmartRestSetOperationToExecuting {
+ pub fn new(operation: CumulocitySupportedOperations) -> Self {
+ Self {
+ message_id: "501",
+ operation: operation.into(),
+ }
+ }
+
+ pub fn from_thin_edge_json(
+ response: SoftwareUpdateResponse,
+ ) -> Result<Self, SmartRestSerializerError> {
+ match response.status() {
+ SoftwareOperationStatus::Executing => {
+ Ok(Self::new(CumulocitySupportedOperations::C8ySoftwareUpdate))
+ }
+ _ => Err(SmartRestSerializerError::UnsupportedOperationStatus { response }),
+ }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestSetOperationToExecuting {}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSetOperationToSuccessful {
+ pub message_id: &'static str,
+ pub operation: &'static str,
+ pub operation_parameter: Option<String>,
+}
+
+impl SmartRestSetOperationToSuccessful {
+ pub fn new(operation: CumulocitySupportedOperations) -> Self {
+ Self {
+ message_id: "503",
+ operation: operation.into(),
+ operation_parameter: None,
+ }
+ }
+
+ pub fn with_response_parameter(self, response_parameter: &str) -> Self {
+ Self {
+ operation_parameter: Some(response_parameter.into()),
+ ..self
+ }
+ }
+
+ pub fn from_thin_edge_json(
+ response: SoftwareUpdateResponse,
+ ) -> Result<Self, SmartRestSerializerError> {
+ match response.status() {
+ SoftwareOperationStatus::Successful => {
+ Ok(Self::new(CumulocitySupportedOperations::C8ySoftwareUpdate))
+ }
+ _ => Err(SmartRestSerializerError::UnsupportedOperationStatus { response }),
+ }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestSetOperationToSuccessful {}
+
+#[derive(Debug, Deserialize, Serialize, PartialEq)]
+pub struct SmartRestSetOperationToFailed {
+ pub message_id: &'static str,
+ pub operation: &'static str,
+ #[serde(serialize_with = "reason_to_string_with_quotes")]
+ pub reason: String,
+}
+
+impl SmartRestSetOperationToFailed {
+ fn new(operation: CumulocitySupportedOperations, reason: String) -> Self {
+ Self {
+ message_id: "502",
+ operation: operation.into(),
+ reason,
+ }
+ }
+
+ pub fn from_thin_edge_json(
+ response: SoftwareUpdateResponse,
+ ) -> Result<Self, SmartRestSerializerError> {
+ match &response.status() {
+ SoftwareOperationStatus::Failed => Ok(Self::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ response.error().unwrap_or_else(|| "".to_string()),
+ )),
+ _ => Err(SmartRestSerializerError::UnsupportedOperationStatus { response }),
+ }
+ }
+}
+
+impl<'a> SmartRestSerializer<'a> for SmartRestSetOperationToFailed {}
+
+fn reason_to_string_with_quotes<S>(reason: &str, serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+{
+ let s = format!("\"{}\"", reason);
+ serializer.serialize_str(&s)
+}
+
+fn serialize_smartrest<S: Serialize>(record: S) -> Result<String, SmartRestSerializerError> {
+ let mut wtr = WriterBuilder::new()
+ .has_headers(false)
+ .quote_style(QuoteStyle::Never)
+ .double_quote(false)
+ .from_writer(vec![]);
+ wtr.serialize(record)?;
+ let csv = String::from_utf8(wtr.into_inner()?)?;
+ Ok(csv)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use json_sm::*;
+
+ #[test]
+ fn serialize_smartrest_supported_operations() {
+ let smartrest = SmartRestSetSupportedOperations::default()
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(smartrest, "114,c8y_SoftwareUpdate,c8y_LogfileRequest\n");
+ }
+
+ #[test]
+ fn serialize_smartrest_get_pending_operations() {
+ let smartrest = SmartRestGetPendingOperations::default()
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(smartrest, "500\n");
+ }
+
+ #[test]
+ fn serialize_smartrest_set_operation_to_executing() {
+ let smartrest =
+ SmartRestSetOperationToExecuting::new(CumulocitySupportedOperations::C8ySoftwareUpdate)
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(smartrest, "501,c8y_SoftwareUpdate\n");
+ }
+
+ #[test]
+ fn from_thin_edge_json_to_smartrest_set_operation_to_executing() {
+ let json_response = r#"{
+ "id": "123",
+ "status": "executing"
+ }"#;
+ let response = SoftwareUpdateResponse::from_json(json_response).unwrap();
+ let smartrest_obj =
+ SmartRestSetOperationToExecuting::from_thin_edge_json(response).unwrap();
+
+ let expected_smartrest_obj = SmartRestSetOperationToExecuting {
+ message_id: "501",
+ operation: "c8y_SoftwareUpdate",
+ };
+ assert_eq!(smartrest_obj, expected_smartrest_obj);
+ }
+
+ #[test]
+ fn serialize_smartrest_set_operation_to_successful() {
+ let smartrest = SmartRestSetOperationToSuccessful::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ )
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(smartrest, "503,c8y_SoftwareUpdate,\n");
+ }
+
+ #[test]
+ fn from_thin_edge_json_to_smartrest_set_operation_to_successful() {
+ let json_response = r#"{
+ "id":"1",
+ "status":"successful",
+ "currentSoftwareList":[]
+ }"#;
+ let response = SoftwareUpdateResponse::from_json(json_response).unwrap();
+ let smartrest_obj =
+ SmartRestSetOperationToSuccessful::from_thin_edge_json(response).unwrap();
+
+ let expected_smartrest_obj = SmartRestSetOperationToSuccessful {
+ message_id: "503",
+ operation: "c8y_SoftwareUpdate",
+ operation_parameter: None,
+ };
+ assert_eq!(smartrest_obj, expected_smartrest_obj);
+ }
+
+ #[test]
+ fn serialize_smartrest_set_operation_to_failed() {
+ let smartrest = SmartRestSetOperationToFailed::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ "Failed due to permission.".into(),
+ )
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(
+ smartrest,
+ "502,c8y_SoftwareUpdate,\"Failed due to permission.\"\n"
+ );
+ }
+
+ #[test]
+ fn serialize_smartrest_set_operation_to_failed_with_comma_reason() {
+ let smartrest = SmartRestSetOperationToFailed::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ "Failed to install collectd, modbus, and golang.".into(),
+ )
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(
+ smartrest,
+ "502,c8y_SoftwareUpdate,\"Failed to install collectd, modbus, and golang.\"\n"
+ );
+ }
+
+ #[test]
+ fn serialize_smartrest_set_operation_to_failed_with_empty_reason() {
+ let smartrest = SmartRestSetOperationToFailed::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ "".into(),
+ )
+ .to_smartrest()
+ .unwrap();
+ assert_eq!(smartrest, "502,c8y_SoftwareUpdate,\"\"\n");
+ }
+
+ #[test]
+ fn from_thin_edge_json_to_smartrest_set_operation_to_failed() {
+ let json_response = r#"{
+ "id": "123",
+ "status":"failed",
+ "reason":"2 errors: fail to install [ collectd ] fail to remove [ mongodb ]",
+ "currentSoftwareList": [],
+ "failures": []
+ }"#;
+ let response = SoftwareUpdateResponse::from_json(json_response).unwrap();
+
+ let smartrest_obj = SmartRestSetOperationToFailed::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ response.error().unwrap(),
+ );
+
+ let expected_smartrest_obj = SmartRestSetOperationToFailed {
+ message_id: "502",
+ operation: "c8y_SoftwareUpdate",
+ reason: "2 errors: fail to install [ collectd ] fail to remove [ mongodb ]".to_string(),
+ };
+ assert_eq!(smartrest_obj, expected_smartrest_obj);
+ }
+
+ #[test]
+ fn from_thin_edge_json_to_smartrest_set_operation_to_failed_with_empty_reason() {
+ let json_response = r#"{
+ "id": "123",
+ "status":"failed",
+ "reason":"",
+ "currentSoftwareList": [],
+ "failures": []
+ }"#;
+ let response = SoftwareUpdateResponse::from_json(json_response).unwrap();
+
+ let smartrest_obj = SmartRestSetOperationToFailed::new(
+ CumulocitySupportedOperations::C8ySoftwareUpdate,
+ response.error().unwrap(),
+ );
+
+ let expected_smartrest_obj = SmartRestSetOperationToFailed {
+ message_id: "502",
+ operation: "c8y_SoftwareUpdate",
+ reason: "".to_string(),
+ };
+ assert_eq!(smartrest_obj, expected_smartrest_obj);
+ }
+}