From d1e57dd36d642f4d93764afa887a0eb0a82d1746 Mon Sep 17 00:00:00 2001 From: Lukasz Woznicki <75632179+makr11st@users.noreply.github.com> Date: Thu, 23 Sep 2021 11:11:40 +0100 Subject: Move smartrest to separate crate (#446) Signed-off-by: Lukasz Woznicki --- Cargo.lock | 369 +++++++++-------- Cargo.toml | 1 + mapper/cumulocity/c8y_smartrest/Cargo.toml | 20 + mapper/cumulocity/c8y_smartrest/src/error.rs | 31 ++ mapper/cumulocity/c8y_smartrest/src/lib.rs | 3 + .../c8y_smartrest/src/smartrest_deserializer.rs | 449 ++++++++++++++++++++ .../c8y_smartrest/src/smartrest_serializer.rs | 335 +++++++++++++++ mapper/tedge_mapper/Cargo.toml | 1 + mapper/tedge_mapper/src/sm_c8y_mapper/error.rs | 32 +- mapper/tedge_mapper/src/sm_c8y_mapper/mapper.rs | 15 +- mapper/tedge_mapper/src/sm_c8y_mapper/mod.rs | 2 - .../src/sm_c8y_mapper/smartrest_deserializer.rs | 454 --------------------- .../src/sm_c8y_mapper/smartrest_serializer.rs | 335 --------------- 13 files changed, 1041 insertions(+), 1006 deletions(-) create mode 100644 mapper/cumulocity/c8y_smartrest/Cargo.toml create mode 100644 mapper/cumulocity/c8y_smartrest/src/error.rs create mode 100644 mapper/cumulocity/c8y_smartrest/src/lib.rs create mode 100644 mapper/cumulocity/c8y_smartrest/src/smartrest_deserializer.rs create mode 100644 mapper/cumulocity/c8y_smartrest/src/smartrest_serializer.rs delete mode 100644 mapper/tedge_mapper/src/sm_c8y_mapper/smartrest_deserializer.rs delete mode 100644 mapper/tedge_mapper/src/sm_c8y_mapper/smartrest_serializer.rs diff --git a/Cargo.lock b/Cargo.lock index 670f2fba..dc039c84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,15 +46,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" [[package]] name = "argh" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e" +checksum = "f023c76cd7975f9969f8e29f0e461decbdc7f51048ce43427107a3d192f1c9bf" dependencies = [ "argh_derive", "argh_shared", @@ -62,22 +62,22 @@ dependencies = [ [[package]] name = "argh_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c" +checksum = "48ad219abc0c06ca788aface2e3a1970587e3413ab70acd20e54b6ec524c1f8f" dependencies = [ "argh_shared", "heck", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] name = "argh_shared" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00" +checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33" [[package]] name = "arrayvec" @@ -97,13 +97,13 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f002ce7d0c5e809ebb02be78fd503aeed4a511fd0fcaff6e6914cbdabbfa33" +checksum = "b800c4403e8105d959595e1f88119e78bc12bc874c4336973658b648a746ba93" dependencies = [ "bstr", "doc-comment", - "predicates 2.0.1", + "predicates 2.0.2", "predicates-core", "predicates-tree", "wait-timeout", @@ -164,9 +164,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -175,9 +175,9 @@ version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" [[package]] name = "byteorder" @@ -304,9 +304,22 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "c8y_smartrest" +version = "0.3.1" +dependencies = [ + "assert-json-diff", + "assert_matches", + "csv", + "json_sm", + "serde", + "serde_json", + "thiserror", +] [[package]] name = "c8y_translator_lib" @@ -343,9 +356,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "certificate" @@ -444,9 +457,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -555,12 +568,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -578,7 +591,7 @@ dependencies = [ "nom", "num-bigint", "num-traits", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -766,9 +779,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" dependencies = [ "futures-channel", "futures-core", @@ -781,9 +794,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -791,15 +804,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -808,34 +821,34 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg", "proc-macro-hack", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] name = "futures-sink" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-timer" @@ -845,9 +858,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", "futures-channel", @@ -904,9 +917,9 @@ checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" [[package]] name = "h2" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" +checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" dependencies = [ "bytes", "fnv", @@ -978,9 +991,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ "bytes", "fnv", @@ -1000,9 +1013,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" @@ -1027,9 +1040,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.11" +version = "0.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" +checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" dependencies = [ "bytes", "futures-channel", @@ -1120,9 +1133,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jackiechan" @@ -1158,9 +1171,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.52" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -1212,15 +1225,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.98" +version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -1246,15 +1259,15 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap" @@ -1345,9 +1358,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7e25b214433f669161f414959594216d8e6ba83b6679d3db96899c0b4639033" dependencies = [ "cfg-if 1.0.0", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -1428,9 +1441,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3728fec49d363a50a8828a190b379a446cc5cf085c06259bbbeb34447e4ec7" +checksum = "e27ff0416812c5dec77c5047d26f34ff0fda13ec8d8e87110056c22a213a3de7" dependencies = [ "bitflags", "cc", @@ -1469,9 +1482,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" dependencies = [ "autocfg", "num-integer", @@ -1509,9 +1522,9 @@ dependencies = [ [[package]] name = "object" -version = "0.26.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "memchr", ] @@ -1554,9 +1567,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -1565,9 +1578,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if 1.0.0", "instant", @@ -1609,9 +1622,9 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -1700,9 +1713,9 @@ dependencies = [ [[package]] name = "predicates" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3d91237f5de3bcd9d927e24d03b495adb6135097b001cea7403e2d573d00a9" +checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" dependencies = [ "difflib", "float-cmp 0.9.0", @@ -1757,9 +1770,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", "version_check", ] @@ -1769,7 +1782,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", "version_check", ] @@ -1797,9 +1810,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid 0.2.2", ] @@ -1851,7 +1864,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", ] [[package]] @@ -1977,9 +1990,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.8.11" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48b4fc1b81d685fcd442a86da2e2c829d9e353142633a8159f42bf28e7e94428" +checksum = "2351cbef4bf91837f5ff7face6091cb277ba960d1638d2c5ae2327859912fbba" dependencies = [ "chrono", "pem", @@ -2163,9 +2176,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc_version" @@ -2178,9 +2191,9 @@ dependencies = [ [[package]] name = "rusticata-macros" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8db3e42c9a4a9479e121c66d4925d15a87734f6fa37f1df0434708718d316ce" +checksum = "fbbee512c633ecabd4481c40111b6ded03ddd9ab10ba6caa5a74e14c889921ad" dependencies = [ "nom", ] @@ -2279,18 +2292,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -2298,20 +2311,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] name = "serde_json" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -2347,16 +2360,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] name = "sha-1" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer", "cfg-if 1.0.0", @@ -2397,9 +2410,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "socket2" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ "libc", "winapi", @@ -2431,9 +2444,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" dependencies = [ "clap", "lazy_static", @@ -2442,15 +2455,15 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -2466,11 +2479,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -2494,7 +2507,7 @@ dependencies = [ "hyper", "mockito", "pem", - "predicates 2.0.1", + "predicates 2.0.2", "reqwest", "rpassword", "rumqttc", @@ -2528,7 +2541,7 @@ dependencies = [ "mqtt_client", "once_cell", "plugin_sm", - "predicates 2.0.1", + "predicates 2.0.2", "rumqttd", "rumqttlog", "serde", @@ -2582,6 +2595,7 @@ dependencies = [ "assert_matches", "async-trait", "batcher", + "c8y_smartrest", "c8y_translator_lib", "chrono", "clock", @@ -2683,22 +2697,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -2733,9 +2747,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" dependencies = [ "tinyvec_macros", ] @@ -2748,9 +2762,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c" +checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" dependencies = [ "autocfg", "bytes", @@ -2772,9 +2786,9 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] @@ -2827,9 +2841,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" dependencies = [ "bytes", "futures-core", @@ -2856,9 +2870,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.26" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" dependencies = [ "cfg-if 1.0.0", "log", @@ -2869,20 +2883,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", ] [[package]] name = "tracing-core" -version = "0.1.18" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" dependencies = [ "lazy_static", ] @@ -2910,9 +2924,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.19" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab69019741fca4d98be3c62d2b75254528b5432233fd8a4d2739fec20278de48" +checksum = "fdd0568dbfe3baf7048b7908d2b32bca0d81cd56bec6d2a8f894b01d74f86be3" dependencies = [ "ansi_term 0.12.1", "chrono", @@ -2972,9 +2986,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicase" @@ -2987,12 +3001,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" @@ -3011,9 +3022,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -3156,9 +3167,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "serde", @@ -3168,24 +3179,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.25" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16646b21c3add8e13fdb8f20172f8a28c3dbf62f45406bcff0233188226cfe0c" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3195,9 +3206,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote 1.0.9", "wasm-bindgen-macro-support", @@ -3205,28 +3216,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.28", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.52" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -3337,6 +3348,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd" +checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" diff --git a/Cargo.toml b/Cargo.toml index c3309045..3ab12af1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "common/tedge_users", "common/tedge_utils", "mapper/cumulocity/c8y_translator_lib", + "mapper/cumulocity/c8y_smartrest", "mapper/tedge_mapper", "mapper/thin_edge_json", "sm/json_sm", diff --git a/mapper/cumulocity/c8y_smartrest/Cargo.toml b/mapper/cumulocity/c8y_smartrest/Cargo.toml new file mode 100644 index 00000000..330b43d2 --- /dev/null +++ b/mapper/cumulocity/c8y_smartrest/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "c8y_smartrest" +version = "0.3.1" +authors = ["Software AG "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +csv = "1.1" +json_sm = { path = "../../../sm/json_sm" } +serde = { version = "1.0", features = ["derive"] } +thiserror = "1.0" + +[dev-dependencies] +assert_matches = "1.5" +assert-json-diff = "2.0" +serde_json = "1.0" + + diff --git a/mapper/cumulocity/c8y_smartrest/src/error.rs b/mapper/cumulocity/c8y_smartrest/src/error.rs new file mode 100644 index 00000000..1f883947 --- /dev/null +++ b/mapper/cumulocity/c8y_smartrest/src/error.rs @@ -0,0 +1,31 @@ +use json_sm::SoftwareUpdateResponse; + +#[derive(thiserror::Error, Debug)] +pub enum SmartRestSerializerError { + #[error("The operation status is not supported. {response:?}")] + UnsupportedOperationStatus { response: SoftwareUpdateResponse }, + + #[error("Failed to serialize SmartREST.")] + InvalidCsv(#[from] csv::Error), + + #[error(transparent)] + FromCsvWriter(#[from] csv::IntoInnerError>>), + + #[error(transparent)] + FromUtf8Error(#[from] std::string::FromUtf8Error), +} + +#[derive(thiserror::Error, Debug)] +pub enum SmartRestDeserializerError { + #[error("The received SmartREST message ID {id} is unsupported.")] + UnsupportedOperation { id: String }, + + #[error("Failed to deserialize SmartREST.")] + InvalidCsv(#[from] csv::Error), + + #[error("Jwt response contains incorrect ID: {0}")] + InvalidMessageId(u16), + + #[error("Action {action} is not recognized. It must be install or delete.")] + ActionNotFound { action: String }, +} diff --git a/mapper/cumulocity/c8y_smartrest/src/lib.rs b/mapper/cumulocity/c8y_smartrest/src/lib.rs new file mode 100644 index 00000000..596af9be --- /dev/null +++ b/mapper/cumulocity/c8y_smartrest/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod smartrest_deserializer; +pub mod smartrest_serializer; diff --git a/mapper/cumulocity/c8y_smartrest/src/smartrest_deserializer.rs b/mapper/cumulocity/c8y_smartrest/src/smartrest_deserializer.rs new file mode 100644 index 00000000..b9e6d1f9 --- /dev/null +++ b/mapper/cumulocity/c8y_smartrest/src/smartrest_deserializer.rs @@ -0,0 +1,449 @@ +use crate::error::SmartRestDeserializerError; +use csv::ReaderBuilder; +use json_sm::{SoftwareModule, SoftwareModuleUpdate, SoftwareUpdateRequest}; +use serde::{Deserialize, Serialize}; +use std::convert::{TryFrom, TryInto}; + +#[derive(Debug)] +enum CumulocitySoftwareUpdateActions { + Install, + Delete, +} + +impl TryFrom for CumulocitySoftwareUpdateActions { + type Error = SmartRestDeserializerError; + + fn try_from(action: String) -> Result { + match action.as_str() { + "install" => Ok(Self::Install), + "delete" => Ok(Self::Delete), + _ => Err(SmartRestDeserializerError::ActionNotFound { action }), + } + } +} + +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub struct SmartRestUpdateSoftware { + pub message_id: String, + pub external_id: String, + pub update_list: Vec, +} + +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub struct SmartRestUpdateSoftwareModule { + pub software: String, + pub version: Option, + pub url: Option, + pub action: String, +} + +impl SmartRestUpdateSoftware { + pub fn new() -> Self { + Self { + message_id: "528".into(), + external_id: "".into(), + update_list: vec![], + } + } + + pub fn from_smartrest(&self, smartrest: &str) -> Result { + let mut message_id = smartrest.to_string(); + let () = message_id.truncate(3); + if message_id != self.message_id { + return Err(SmartRestDeserializerError::UnsupportedOperation { id: message_id }); + } + + let mut rdr = ReaderBuilder::new() + .has_headers(false) + .flexible(true) + .from_reader(smartrest.as_bytes()); + let mut record: Self = Self::new(); + for result in rdr.deserialize() { + record = result?; + } + Ok(record) + } + + pub fn to_thin_edge_json(&self) -> Result { + let request = self.map_to_software_update_request(SoftwareUpdateRequest::new())?; + Ok(request) + } + + pub fn modules(&self) -> Vec { + let mut modules = vec![]; + for module in &self.update_list { + modules.push(SmartRestUpdateSoftwareModule { + software: module.software.clone(), + version: module.version.clone(), + url: module.url.clone(), + action: module.action.clone(), + }); + } + modules + } + + fn map_to_software_update_request( + &self, + mut request: SoftwareUpdateRequest, + ) -> Result { + for module in &self.modules() { + match module.action.clone().try_into()? { + CumulocitySoftwareUpdateActions::Install => { + request.add_update(SoftwareModuleUpdate::Install { + module: SoftwareModule { + module_type: module.get_module_version_and_type().1, + name: module.software.clone(), + version: module.get_module_version_and_type().0, + url: module.url.clone(), + }, + }); + } + CumulocitySoftwareUpdateActions::Delete => { + request.add_update(SoftwareModuleUpdate::Remove { + module: SoftwareModule { + module_type: module.get_module_version_and_type().1, + name: module.software.clone(), + version: module.get_module_version_and_type().0, + url: None, + }, + }); + } + } + } + Ok(request) + } +} + +impl SmartRestUpdateSoftwareModule { + fn get_module_version_and_type(&self) -> (Option, Option) { + let split; + match &self.version { + Some(version) => { + if version.matches("::").count() > 1 { + split = version.rsplit_once("::"); + } else { + split = version.split_once("::"); + } + + match split { + Some((v, t)) => { + if v.is_empty() { + (None, Some(t.into())) // ::debian + } else if !t.is_empty() { + (Some(v.into()), Some(t.into())) // 1.0::debian + } else { + (Some(v.into()), None) + } + } + None => { + if version == " " { + (None, None) // as long as c8y UI forces version input + } else { + (Some(version.into()), None) // 1.0 + } + } + } + } + + None => (None, None), // (empty) + } + } +} + +type JwtToken = String; + +#[derive(Debug, Deserialize, PartialEq)] +pub struct SmartRestJwtResponse { + id: u16, + token: JwtToken, +} + +impl SmartRestJwtResponse { + pub fn new() -> Self { + Self { + id: 71, + token: "".into(), + } + } + + pub fn try_new(to_parse: &str) -> Result { + let mut csv = csv::ReaderBuilder::new() + .has_headers(false) + .from_reader(to_parse.as_bytes()); + + let mut jwt = Self::new(); + for result in csv.deserialize() { + jwt = result.unwrap(); + } + + if jwt.id != 71 { + return Err(SmartRestDeserializerError::InvalidMessageId(jwt.id)); + } + + Ok(jwt) + } + + pub fn token(&self) -> JwtToken { + self.token.clone() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_json_diff::*; + use json_sm::*; + use serde_json::json; + + // To avoid using an ID randomly generated, which is not convenient for testing. + impl SmartRestUpdateSoftware { + fn to_thin_edge_json_with_id( + &self, + id: &str, + ) -> Result { + let request = SoftwareUpdateRequest::new_with_id(id); + self.map_to_software_update_request(request) + } + } + + #[test] + fn jwt_token_create_new() { + let jwt = SmartRestJwtResponse::new(); + + assert!(jwt.token.is_empty()); + } + + #[test] + fn jwt_token_deserialize_correct_id_returns_token() { + let test_response = "71,123456"; + let jwt = SmartRestJwtResponse::try_new(test_response).unwrap(); + + assert_eq!(jwt.token(), "123456"); + } + + #[test] + fn jwt_token_deserialize_incorrect_id_returns_error() { + let test_response = "42,123456"; + + let jwt = SmartRestJwtResponse::try_new(test_response); + + assert!(jwt.is_err()); + assert_matches::assert_matches!(jwt, Err(SmartRestDeserializerError::InvalidMessageId(42))); + } + + #[test] + fn verify_get_module_version_and_type() { + let mut module = SmartRestUpdateSoftwareModule { + software: "software1".into(), + version: None, + url: None, + action: "install".into(), + }; // "" + assert_eq!(module.get_module_version_and_type(), (None, None)); + + module.version = Some(" ".into()); // " " (space) + assert_eq!(module.get_module_version_and_type(), (None, None)); + + module.version = Some("::debian".into()); + assert_eq!( + module.get_module_version_and_type(), + (None, Some("debian".to_string())) + ); + + module.version = Some("1.0.0::debian".into()); + assert_eq!( + module.get_module_version_and_type(), + (Some("1.0.0".to_string()), Some("debian".to_string())) + ); + + module.version = Some("1.0.0::1::debian".into()); + assert_eq!( + module.get_module_version_and_type(), + (Some("1.0.0::1".to_string()), Some("debian".to_string())) + ); + + module.version = Some("1.0.0::1::".into()); + assert_eq!( + module.get_module_version_and_type(), + (Some("1.0.0::1".to_string()), None) + ); + + module.version = Some("1.0.0".into()); + assert_eq!( + module.get_module_version_and_type(), + (Some("1.0.0".to_string()), None) + ); + } + + #[test] + fn deserialize_smartrest_update_software() { + let smartrest = + String::from("528,external_id,software1,version1,url1,install,software2,,,delete"); + let update_software = SmartRestUpdateSoftware::new() + .from_smartrest(&smartrest) + .unwrap(); + + let expected_update_software = SmartRestUpdateSoftware { + message_id: "528".into(), + external_id: "external_id".into(), + update_list: vec![ + SmartRestUpdateSoftwareModule { + software: "software1".into(), + version: Some("version1".into()), + url: Some("url1".into()), + action: "install".into(), + }, + SmartRestUpdateSoftwareModule { + software: "software2".into(), + version: None, + url: None, + action: "delete".into(), + }, + ], + }; + + assert_eq!(update_software, expected_update_software); + } + + #[test] + fn deserialize_incorrect_smartrest_message_id() { + let smartrest = String::from("516,external_id"); + assert!(SmartRestUpdateSoftware::new() + .from_smartrest(&smartrest) + .is_err()); + } + + #[test] + fn deserialize_incorrect_smartrest_action() { + let smartrest = + String::from("528,external_id,software1,version1,url1,action,software2,,,remove"); + assert!(SmartRestUpdateSoftware::new() + .from_smartrest(&smartrest) + .unwrap() + .to_thin_edge_json() + .is_err()); + } + + #[test] + fn from_smartrest_update_software_to_software_update_request() { + let smartrest_obj = SmartRestUpdateSoftware { + message_id: "528".into(), + external_id: "external_id".into(), + update_list: vec![ + SmartRestUpdateSoftwareModule { + software: "software1".into(), + version: Some("version1::debian".into()), + url: Some("url1".into()), + action: "install".into(), + }, + SmartRestUpdateSoftwareModule { + software: "software2".into(), + version: None, + url: None, + action: "delete".into(), + }, + ], + }; + let thin_edge_json = smartrest_obj.to_thin_edge_json_with_id("123").unwrap(); + + let mut expected_thin_edge_json = SoftwareUpdateRequest::new_with_id("123"); + let () = + expected_thin_edge_json.add_update(SoftwareModuleUpdate::install(SoftwareModule { + module_type: Some("debian".to_string()), + name: "software1".to_string(), + version: Some("version1".to_string()), + url: Some("url1".to_string()), + })); + let () = expected_thin_edge_json.add_update(SoftwareModuleUpdate::remove(SoftwareModule { + module_type: Some("".to_string()), + name: "software2".to_string(), + version: None, + url: None, + })); + + assert_eq!(thin_edge_json, expected_thin_edge_json); + } + + #[test] + fn from_smartrest_update_software_to_json() { + let smartrest = + String::from("528,external_id,nodered,1.0.0::debian,,install,\ + collectd,5.7::debian,https://collectd.org/download/collectd-tarballs/collectd-5.12.0.tar.bz2,install,\ + nginx,1.21.0::docker,,install,mongodb,4.4.6::docker,,delete"); + let update_software = SmartRestUpdateSoftware::new(); + let software_update_request = update_software + .from_smartrest(&smartrest) + .unwrap() + .to_thin_edge_json_with_id("123"); + let output_json = software_update_request.unwrap().to_json().unwrap(); + + let expected_json = json!({ + "id": "123", + "updateList": [ + { + "type": "debian", + "modules": [ + { + "name": "nodered", + "version": "1.0.0", + "action": "install" + }, + { + "name": "collectd", + "version": "5.7", + "url": "https://collectd.org/download/collectd-tarballs/collectd-5.12.0.tar.bz2", + "action": "install" + } + ] + }, + { + "type": "docker", + "modules": [ + { + "name": "nginx", + "version": "1.21.0", + "action": "install" + }, + { + "name": "mongodb", + "version": "4.4.6", + "action": "remove" + } + ] + } + ] + }); + assert_json_eq!( + serde_json::from_str::(output_json.as_str()).unwrap(), + expected_json + ); + } + + #[test] + fn access_smartrest_update_modules() { + let smartrest = + String::from("528,external_id,software1,version1,url1,install,software2,,,delete"); + let update_software = SmartRestUpdateSoftware::new(); + let vec = update_software + .from_smartrest(&smartrest) + .unwrap() + .modules(); + + let expected_vec = vec![ + SmartRestUpdateSoftwareModule { + software: "software1".into(), + version: Some("version1".into()), + url: Some("url1".into()), + action: "install".into(), + }, + SmartRestUpdateSoftwareModule { + software: "software2".into(), + version: None, + url: None, + action: "delete".into(), + }, + ]; + + assert_eq!(vec, expected_vec); + } +} diff --git a/mapper/cumulocity/c8y_smartrest/src/smartrest_serializer.rs b/mapper/cumulocity/c8y_smartrest/src/smartrest_serializer.rs new file mode 100644 index 00000000..5d9052df --- /dev/null +++ b/mapper/cumulocity/c8y_smartrest/src/smartrest_serializer.rs @@ -0,0 +1,335 @@ +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, +} + +impl From for &'static str { + fn from(op: CumulocitySupportedOperations) -> Self { + match op { + CumulocitySupportedOperations::C8ySoftwareUpdate => "c8y_SoftwareUpdate", + } + } +} + +pub trait SmartRestSerializer<'a> +where + Self: Serialize, +{ + fn to_smartrest(&self) -> Result { + serialize_smartrest(self) + } +} + +#[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()], + } + } +} + +impl<'a> SmartRestSerializer<'a> for SmartRestSetSupportedOperations {} + +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub struct SmartRestSoftwareModuleItem { + pub software: String, + pub version: Option, + pub url: Option, +} + +#[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 { + 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, +} + +impl SmartRestSetOperationToSuccessful { + fn new(operation: CumulocitySupportedOperations) -> Self { + Self { + message_id: "503", + operation: operation.into(), + } + } + + pub fn from_thin_edge_json( + response: SoftwareUpdateResponse, + ) -> Result { + 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 { + 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(reason: &str, serializer: S) -> Result +where + S: Serializer, +{ + let s = format!("\"{}\"", reason); + serializer.serialize_str(&s) +} + +fn serialize_smartrest(record: S) -> Result { + 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\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", + }; + 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); + } +} diff --git a/mapper/tedge_mapper/Cargo.toml b/mapper/tedge_mapper/Cargo.toml index f6073bcb..25f547e1 100644 --- a/mapper/tedge_mapper/Cargo.toml +++ b/mapper/tedge_mapper/Cargo.toml @@ -29,6 +29,7 @@ anyhow = "1.0" async-trait = "0.1" batcher = {path = "../../common/batcher" } c8y_translator_lib = {path = "../cumulocity/c8y_translator_lib" } +c8y_smartrest = { path = "../cumulocity/c8y_smartrest" } chrono = "0.4" clock = {path = "../../common/clock" } csv = "1.1" diff --git a/mapper/tedge_mapper/src/sm_c8y_mapper/error.rs b/mapper/tedge_mapper/src/sm_c8y_mapper/error.rs index d025d731..3fe145d4 100644 --- a/mapper/tedge_mapper/src/sm_c8y_mapper/error.rs +++ b/mapper/tedge_mapper/src/sm_c8y_mapper/error.rs @@ -1,34 +1,4 @@ -use json_sm::SoftwareUpdateResponse; - -#[derive(thiserror::Error, Debug)] -pub(crate) enum SmartRestSerializerError { - #[error("The operation status is not supported. {response:?}")] - UnsupportedOperationStatus { response: SoftwareUpdateResponse }, - - #[error("Failed to serialize SmartREST.")] - InvalidCsv(#[from] csv::Error), - - #[error(transparent)] - FromCsvWriter(#[from] csv::IntoInnerError>>), - - #[error(transparent)] - FromUtf8Error(#[from] std::string::FromUtf8Error), -} - -#[derive(thiserror::Error, Debug)] -pub(crate) enum SmartRestDeserializerError { - #[error("The received SmartREST message ID {id} is unsupported.")] - UnsupportedOperation { id: String }, - - #[error("Failed to deserialize SmartREST.")] - InvalidCsv(#[from] csv::Error), - - #[error("Jwt response contains incorrect ID: {0}")] - InvalidMessageId(u16), - - #[error("Action {action} is not recognized. It must be install or delete.")] - ActionNotFound { action: String }, -} +use c8y_smartrest::error::{SmartRestDeserializerError, SmartRestSerializerError}; #[derive(thiserror::Error, Debug)] pub(crate) enum MapperTopicError { diff --git a/mapper/tedge_mapper/src/sm_c8y_mapper/mapper.rs b/mapper/tedge_mapper/src/sm_c8y_mapper/mapper.rs index e2508dd6..e5d5dc69 100644 --- a/mapper/tedge_mapper/src/sm_c8y_mapper/mapper.rs +++ b/mapper/tedge_mapper/src/sm_c8y_mapper/mapper.rs @@ -1,10 +1,15 @@ use crate::mapper::mqtt_config; -use crate::sm_c8y_mapper::{ - error::*, json_c8y::C8yUpdateSoftwareListResponse, smartrest_deserializer::*, - smartrest_serializer::*, topic::*, -}; +use crate::sm_c8y_mapper::{error::*, json_c8y::C8yUpdateSoftwareListResponse, topic::*}; use crate::{component::TEdgeComponent, sm_c8y_mapper::json_c8y::InternalIdResponse}; use async_trait::async_trait; +use c8y_smartrest::{ + smartrest_deserializer::{SmartRestJwtResponse, SmartRestUpdateSoftware}, + smartrest_serializer::{ + SmartRestGetPendingOperations, SmartRestSerializer, SmartRestSetOperationToExecuting, + SmartRestSetOperationToFailed, SmartRestSetOperationToSuccessful, + SmartRestSetSupportedOperations, + }, +}; use json_sm::{ Jsonify, SoftwareListRequest, SoftwareListResponse, SoftwareOperationStatus, SoftwareUpdateResponse, @@ -208,7 +213,7 @@ impl CumulocitySoftwareManagement { let topic = OutgoingTopic::SoftwareUpdateRequest.to_topic()?; let update_software = SmartRestUpdateSoftware::new(); let json_update_request = update_software - .from_smartrest(smartrest.into())? +