You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
13 KiB
310 lines
13 KiB
// License: Apache 2.0. See LICENSE file in root directory.
|
|
// Copyright(c) 2020 Intel Corporation. All Rights Reserved.
|
|
|
|
#include "versions-db-manager.h"
|
|
#include <rsutils/json.h>
|
|
#include <rsutils/os/os.h>
|
|
#include <rsutils/easylogging/easyloggingpp.h>
|
|
#include <fstream>
|
|
#include <unordered_map>
|
|
#include <algorithm>
|
|
#include <regex>
|
|
|
|
|
|
namespace rs2
|
|
{
|
|
|
|
namespace sw_update
|
|
{
|
|
using json = rsutils::json;
|
|
using namespace http;
|
|
|
|
query_status_type versions_db_manager::query_versions(const std::string &device_name, component_part_type component, const update_policy_type policy, version& out_version)
|
|
{
|
|
// Load server versions info on first access
|
|
if (!init())
|
|
{
|
|
out_version.clear();
|
|
return DB_LOAD_FAILURE;
|
|
}
|
|
|
|
std::string platform = rsutils::os::get_platform_name();
|
|
|
|
std::string up_str(to_string(policy));
|
|
std::string comp_str(to_string(component));
|
|
|
|
if (up_str.empty() || comp_str.empty()) return NO_VERSION_FOUND;
|
|
|
|
// Look for the required version
|
|
auto res = std::find_if(_server_versions_vec.begin(), _server_versions_vec.end(),
|
|
[&, device_name, up_str, comp_str, platform](std::unordered_map<std::string, std::string> ver)
|
|
{
|
|
return (is_device_name_equal(ver["device_name"],device_name,true) && up_str == ver["policy_type"] && comp_str == ver["component"] && (platform == ver["platform"] || ver["platform"] == "*"));
|
|
});
|
|
|
|
if (res != _server_versions_vec.end())
|
|
{
|
|
auto version_str = (*res)["version"];
|
|
out_version = version(version_str);
|
|
return VERSION_FOUND;
|
|
}
|
|
|
|
out_version.clear();
|
|
return NO_VERSION_FOUND; // Nothing found
|
|
}
|
|
|
|
bool versions_db_manager::get_version_data_common(const component_part_type component, const version& version, const std::string& req_field, std::string& out)
|
|
{
|
|
// Check if server versions are loaded
|
|
if (!_server_versions_loaded) return false;
|
|
|
|
std::string platform = rsutils::os::get_platform_name();
|
|
|
|
std::string component_str(to_string(component));
|
|
|
|
if (component_str.empty()) return false;
|
|
|
|
// Look for the required version
|
|
auto res = std::find_if(_server_versions_vec.begin(), _server_versions_vec.end(),
|
|
[version, component_str, platform](std::unordered_map<std::string, std::string> version_map)
|
|
{
|
|
return (sw_update::version(version_map["version"]) == version && component_str == version_map["component"] && (platform == version_map["platform"] || version_map["platform"] == "*"));
|
|
});
|
|
|
|
if (res != _server_versions_vec.end())
|
|
{
|
|
out = (*res)[req_field];
|
|
return true;
|
|
}
|
|
|
|
return false; // Nothing found
|
|
}
|
|
|
|
|
|
std::string to_string(const component_part_type& component)
|
|
{
|
|
switch (component)
|
|
{
|
|
case LIBREALSENSE: return "LIBREALSENSE";
|
|
case VIEWER: return "VIEWER";
|
|
case DEPTH_QUALITY_TOOL: return "DEPTH_QUALITY_TOOL";
|
|
case FIRMWARE: return "FIRMWARE";
|
|
break;
|
|
default:
|
|
LOG_ERROR( "Unknown component type: " << component );
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
std::string to_string(const update_policy_type& policy)
|
|
{
|
|
|
|
switch (policy)
|
|
{
|
|
case EXPERIMENTAL: return "EXPERIMENTAL";
|
|
case RECOMMENDED: return "RECOMMENDED";
|
|
case ESSENTIAL: return "ESSENTIAL";
|
|
break;
|
|
default:
|
|
LOG_ERROR( "Unknown policy type: " << policy );
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bool from_string(const std::string &component_str, component_part_type& component_val)
|
|
{
|
|
static std::unordered_map<std::string, component_part_type> map =
|
|
{ {"LIBREALSENSE",LIBREALSENSE},
|
|
{"VIEWER", VIEWER} ,
|
|
{"DEPTH_QUALITY_TOOL", DEPTH_QUALITY_TOOL},
|
|
{"FIRMWARE", FIRMWARE} };
|
|
|
|
auto val = map.find(component_str);
|
|
if (val != map.end())
|
|
{
|
|
component_val = val->second;
|
|
return true;
|
|
}
|
|
|
|
LOG_ERROR( "Unknown component type: " << component_str );
|
|
return false;
|
|
}
|
|
bool from_string(const std::string &policy_str, update_policy_type& policy_val)
|
|
{
|
|
static std::unordered_map<std::string, update_policy_type> map =
|
|
{ {"EXPERIMENTAL",EXPERIMENTAL},
|
|
{"RECOMMENDED", RECOMMENDED} ,
|
|
{"ESSENTIAL", ESSENTIAL} };
|
|
|
|
auto val = map.find(policy_str);
|
|
if (val != map.end())
|
|
{
|
|
policy_val = val->second;
|
|
return true;
|
|
}
|
|
|
|
LOG_ERROR( "Unknown policy type: " << policy_str );
|
|
return false;
|
|
}
|
|
|
|
bool versions_db_manager::get_server_data(std::stringstream &ver_data)
|
|
{
|
|
bool server_data_retrieved(false);
|
|
|
|
if (false == _local_source_file)
|
|
{
|
|
// download file from URL
|
|
http_downloader hd;
|
|
if (hd.download_to_stream(_dev_info_url, ver_data, _download_cb_func))
|
|
{
|
|
server_data_retrieved = true;
|
|
}
|
|
}
|
|
#ifdef CHECK_FOR_UPDATES
|
|
else
|
|
{
|
|
// read from local file
|
|
std::ifstream file(_dev_info_url);
|
|
if (file.good())
|
|
{
|
|
server_data_retrieved = true;
|
|
ver_data << file.rdbuf();
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR( "Cannot open file: " << _dev_info_url );
|
|
}
|
|
}
|
|
#endif
|
|
return server_data_retrieved;
|
|
}
|
|
|
|
void versions_db_manager::parse_versions_data(const std::stringstream &ver_data)
|
|
{
|
|
// Parse the json file
|
|
json j(json::parse(ver_data.str()));
|
|
|
|
std::unordered_map<std::string, std::function<bool(const std::string&)>> schema;
|
|
build_schema(schema);
|
|
|
|
// Validate json file has a versions array
|
|
if (j.begin().key() == "versions" && j.begin().value().is_array())
|
|
{
|
|
// Iterate through the versions
|
|
for (auto &ver : j["versions"])
|
|
{ // Iterate through the version fields
|
|
std::unordered_map<std::string, std::string> curr_version;
|
|
for (auto it = ver.begin(); it != ver.end(); ++it)
|
|
{
|
|
std::string element_key(it.key());
|
|
|
|
auto schema_field(schema.find(element_key));
|
|
if (schema_field != schema.end()) {
|
|
if (it.value().is_string())
|
|
{
|
|
if (schema_field->second(it.value().get<std::string>()))
|
|
{
|
|
// Value validation passed - add to current version
|
|
curr_version[element_key] = it.value().get<std::string>();
|
|
}
|
|
else
|
|
{
|
|
std::string error_str(
|
|
"Server versions file parsing error - validation fail on key: " + element_key
|
|
+ " value: " + it.value().get< std::string >() + " \n" );
|
|
LOG_ERROR(error_str);
|
|
throw std::runtime_error(error_str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string error_str( "Server versions file parsing error - " + element_key
|
|
+ " should be represented as a string" );
|
|
LOG_ERROR(error_str);
|
|
throw std::runtime_error(error_str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string error_str("Server versions file parsing error - " + element_key + " - unknown field");
|
|
LOG_ERROR(error_str);
|
|
throw std::runtime_error(error_str);
|
|
}
|
|
}
|
|
|
|
// Verify each key in the schema can be found in the current version fields
|
|
//std::pair<const K, E> &item
|
|
if (std::all_of(schema.cbegin(), schema.cend(), [curr_version](const std::pair<std::string, std::function<bool(const std::string&)>> &schema_item)
|
|
{
|
|
return curr_version.end() != std::find_if(curr_version.cbegin(), curr_version.cend(), [schema_item](const std::pair<std::string, std::string> &ver_item) {return schema_item.first == ver_item.first; });
|
|
}))
|
|
{
|
|
_server_versions_vec.emplace_back(curr_version); // Version added to valid versions vector
|
|
}
|
|
else
|
|
{
|
|
std::string error_str("Server versions json file corrupted - not matching schema requirements");
|
|
LOG_ERROR(error_str);
|
|
throw std::runtime_error(error_str);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string error_str("Server versions json file corrupted - Expect versions field of type array \n)"
|
|
"Parsed key: " + j.begin().key() + ", value type array: " + (j.begin().value().is_array() ? "TRUE" : "FALSE"));
|
|
LOG_ERROR(error_str);
|
|
throw std::runtime_error(error_str);
|
|
}
|
|
}
|
|
|
|
|
|
bool versions_db_manager::init()
|
|
{
|
|
// Load server versions info on first access
|
|
if (!_server_versions_loaded)
|
|
{
|
|
std::stringstream server_versions_data;
|
|
// Download / Open the json file
|
|
if (!get_server_data(server_versions_data))
|
|
{
|
|
return false; // Failed to get version from server/file
|
|
}
|
|
else
|
|
{
|
|
// Parse and validate the json file - Throws exception on error
|
|
parse_versions_data(server_versions_data);
|
|
_server_versions_loaded = true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void versions_db_manager::build_schema(std::unordered_map<std::string, std::function<bool(const std::string&)>>& verifier)
|
|
{
|
|
// Builds a map of fields + validation function
|
|
verifier.emplace("device_name", [](const std::string& val) -> bool { return true; });
|
|
verifier.emplace("policy_type", [](const std::string& val) -> bool { return (val == "EXPERIMENTAL") || (val == "RECOMMENDED") || (val == "ESSENTIAL"); });
|
|
verifier.emplace("component", [](const std::string& val) -> bool { return (val == "LIBREALSENSE") || (val == "VIEWER") || (val == "DEPTH_QUALITY_TOOL") || (val == "FIRMWARE"); });
|
|
verifier.emplace("version", [](const std::string& val) -> bool { return version(val) != version(); });
|
|
verifier.emplace("platform", [&](const std::string& val) -> bool { return (val == "*") || (val == "Windows amd64") || (val == "Windows x86") || (val == "Linux amd64") || (val == "Linux arm") || (val == "Mac OS"); });
|
|
verifier.emplace("link", [](const std::string& val) -> bool { return true; });
|
|
verifier.emplace("release_notes_link", [](const std::string& val) -> bool { return true; });
|
|
verifier.emplace("description", [](const std::string& val) -> bool { return true; });
|
|
|
|
}
|
|
|
|
bool versions_db_manager::is_device_name_equal(const std::string &str_from_db, const std::string &str_compared, bool allow_wildcard)
|
|
{
|
|
if (allow_wildcard)
|
|
return (0 == str_from_db.compare(0, str_from_db.find('*'), str_compared, 0, str_from_db.find('*')));
|
|
else
|
|
return (str_from_db == str_compared);
|
|
}
|
|
}
|
|
|
|
|
|
}
|