1 #pragma once
2 
3 #include "config.h"
4 
5 #include <cereal/archives/json.hpp>
6 #include <phosphor-logging/lg2.hpp>
7 
8 #include <filesystem>
9 #include <fstream>
10 
11 namespace phosphor
12 {
13 namespace inventory
14 {
15 namespace manager
16 {
17 
18 namespace fs = std::filesystem;
19 
20 namespace detail
21 {
getStoragePath(const std::string & path,const std::string & iface)22 inline fs::path getStoragePath(const std::string& path,
23                                const std::string& iface)
24 {
25     auto p = fs::path(PIM_PERSIST_PATH);
26     p /= fs::path(path).relative_path();
27     p /= fs::path(iface).relative_path();
28     return p;
29 }
30 } // namespace detail
31 
32 struct SerialOps
33 {
34     /** @brief Serialize inventory item path
35      *  Serializing only path for an empty interface to be consistent
36      *  interfaces.
37      *  @param[in] path - DBus object path
38      *  @param[in] iface - Inventory interface name
39      */
serializephosphor::inventory::manager::SerialOps40     static void serialize(const std::string& path, const std::string& iface)
41     {
42         auto p = detail::getStoragePath(path, iface);
43         fs::create_directories(p.parent_path());
44         std::ofstream os(p, std::ios::binary);
45     }
46 
47     /** @brief Serialize inventory item
48      *
49      *  @param[in] path - DBus object path
50      *  @param[in] iface - Inventory interface name
51      *  @param[in] object - Object to be serialized
52      */
53     template <typename T>
serializephosphor::inventory::manager::SerialOps54     static void serialize(const std::string& path, const std::string& iface,
55                           const T& object)
56     {
57         auto p = detail::getStoragePath(path, iface);
58         fs::create_directories(p.parent_path());
59         std::ofstream os(p, std::ios::binary);
60         cereal::JSONOutputArchive oarchive(os);
61         oarchive(object);
62     }
63 
deserializephosphor::inventory::manager::SerialOps64     static void deserialize(const std::string&, const std::string&)
65     {
66         // This is intentionally a noop.
67     }
68 
69     /** @brief Deserialize inventory item
70      *
71      *  @param[in] path - DBus object path
72      *  @param[in] iface - Inventory interface name
73      *  @param[in] object - Object to be serialized
74      */
75     template <typename T>
deserializephosphor::inventory::manager::SerialOps76     static void deserialize(const std::string& path, const std::string& iface,
77                             T& object)
78     {
79         auto p = detail::getStoragePath(path, iface);
80         try
81         {
82             if (fs::exists(p))
83             {
84                 std::ifstream is(p, std::ios::in | std::ios::binary);
85                 cereal::JSONInputArchive iarchive(is);
86                 iarchive(object);
87             }
88         }
89         catch (const cereal::Exception& e)
90         {
91             lg2::error("Deserialization failed: {ERROR}", "ERROR", e);
92             fs::remove(p);
93         }
94     }
95 };
96 } // namespace manager
97 } // namespace inventory
98 } // namespace phosphor
99