|  | #include <ipmid/entity_map_json.hpp> | 
|  | #include <ipmid/types.hpp> | 
|  | #include <nlohmann/json.hpp> | 
|  |  | 
|  | #include <exception> | 
|  | #include <fstream> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | namespace ipmi | 
|  | { | 
|  | namespace sensor | 
|  | { | 
|  |  | 
|  | EntityInfoMapContainer* EntityInfoMapContainer::getContainer() | 
|  | { | 
|  | static std::unique_ptr<EntityInfoMapContainer> instance; | 
|  |  | 
|  | if (!instance) | 
|  | { | 
|  | /* TODO: With multi-threading this would all need to be locked so | 
|  | * the first thread to hit it would set it up. | 
|  | */ | 
|  | EntityInfoMap builtEntityMap = buildEntityMapFromFile(); | 
|  | instance = std::unique_ptr<EntityInfoMapContainer>( | 
|  | new EntityInfoMapContainer(builtEntityMap)); | 
|  | } | 
|  |  | 
|  | return instance.get(); | 
|  | } | 
|  |  | 
|  | const EntityInfoMap& EntityInfoMapContainer::getIpmiEntityRecords() | 
|  | { | 
|  | return entityRecords; | 
|  | } | 
|  |  | 
|  | EntityInfoMap buildEntityMapFromFile() | 
|  | { | 
|  | const char* entityMapJsonFilename = | 
|  | "/usr/share/ipmi-providers/entity-map.json"; | 
|  | EntityInfoMap builtMap; | 
|  |  | 
|  | std::ifstream mapFile(entityMapJsonFilename); | 
|  | if (!mapFile.is_open()) | 
|  | { | 
|  | return builtMap; | 
|  | } | 
|  |  | 
|  | auto data = nlohmann::json::parse(mapFile, nullptr, false); | 
|  | if (data.is_discarded()) | 
|  | { | 
|  | return builtMap; | 
|  | } | 
|  |  | 
|  | return buildJsonEntityMap(data); | 
|  | } | 
|  |  | 
|  | EntityInfoMap buildJsonEntityMap(const nlohmann::json& data) | 
|  | { | 
|  | EntityInfoMap builtMap; | 
|  |  | 
|  | if (data.type() != nlohmann::json::value_t::array) | 
|  | { | 
|  | return builtMap; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | for (const auto& entry : data) | 
|  | { | 
|  | /* It's an array entry with the following fields: id, | 
|  | * containerEntityId, containerEntityInstance, isList, isLinked, | 
|  | * entities[4] | 
|  | */ | 
|  | EntityInfo obj; | 
|  | Id recordId = entry.at("id").get<Id>(); | 
|  | obj.containerEntityId = | 
|  | entry.at("containerEntityId").get<uint8_t>(); | 
|  | obj.containerEntityInstance = | 
|  | entry.at("containerEntityInstance").get<uint8_t>(); | 
|  | obj.isList = entry.at("isList").get<bool>(); | 
|  | obj.isLinked = entry.at("isLinked").get<bool>(); | 
|  |  | 
|  | auto jsonEntities = entry.at("entities"); | 
|  |  | 
|  | if (jsonEntities.type() != nlohmann::json::value_t::array) | 
|  | { | 
|  | throw std::runtime_error( | 
|  | "Invalid type for entities entry, must be array"); | 
|  | } | 
|  | if (jsonEntities.size() != obj.containedEntities.size()) | 
|  | { | 
|  | throw std::runtime_error( | 
|  | "Entities must be in pairs of " + | 
|  | std::to_string(obj.containedEntities.size())); | 
|  | } | 
|  |  | 
|  | for (std::size_t i = 0; i < obj.containedEntities.size(); i++) | 
|  | { | 
|  | obj.containedEntities[i] = std::make_pair( | 
|  | jsonEntities[i].at("id").get<uint8_t>(), | 
|  | jsonEntities[i].at("instance").get<uint8_t>()); | 
|  | } | 
|  |  | 
|  | builtMap.insert({recordId, obj}); | 
|  | } | 
|  | } | 
|  | catch (const std::exception& e) | 
|  | { | 
|  | /* If any entry is invalid, the entire file cannot be trusted. */ | 
|  | builtMap.clear(); | 
|  | } | 
|  |  | 
|  | return builtMap; | 
|  | } | 
|  |  | 
|  | } // namespace sensor | 
|  | } // namespace ipmi |