#include "HMS.hpp" #include "DeviceManager.hpp" #include static const char* HMS_PATH = "hms"; static const char* HMS_LOCAL_IMG_PATH = "hms/local_image"; namespace Slic3r { namespace GUI { int get_hms_info_version(std::string& version) { AppConfig* config = wxGetApp().app_config; if (!config) return -1; std::string hms_host = config->get_hms_host(); if(hms_host.empty()) { BOOST_LOG_TRIVIAL(error) << "hms_host is empty"; return -1; } int result = -1; version = ""; std::string lang; std::string query_params = HMSQuery::build_query_params(lang); std::string url = (boost::format("https://%1%/GetVersion.php?%2%") % hms_host % query_params).str(); Slic3r::Http http = Slic3r::Http::get(url); http.timeout_max(10) .on_complete([&result, &version](std::string body, unsigned status){ try { json j = json::parse(body); if (j.contains("ver")) { version = std::to_string(j["ver"].get()); } } catch (...) { ; } }) .on_error([&result](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "get_hms_info_version: body = " << body << ", status = " << status << ", error = " << error; result = -1; }) .perform_sync(); return result; } // Note: Download the hms into receive_json int HMSQuery::download_hms_related(const std::string& hms_type, const std::string& dev_id_type, json* receive_json) { std::string local_version = "0"; load_from_local(hms_type, dev_id_type, receive_json, local_version); AppConfig* config = wxGetApp().app_config; if (!config) return -1; std::string hms_host = wxGetApp().app_config->get_hms_host(); std::string lang; std::string query_params = HMSQuery::build_query_params(lang); std::string url; if (hms_type.compare(QUERY_HMS_INFO) == 0) { url = (boost::format("https://%1%/query.php?%2%") % hms_host % query_params).str(); } else if (hms_type.compare(QUERY_HMS_ACTION) == 0) { url = (boost::format("https://%1%/hms/GetActionImage.php?") % hms_host).str(); } if (!local_version.empty()) { url += (url.find('?') != std::string::npos ? "&" : "?") + (boost::format("v=%1%") % local_version).str(); } if (!dev_id_type.empty()) { url += (url.find('?') != std::string::npos ? "&" : "?") + (boost::format("d=%1%") % dev_id_type).str(); } bool to_save_local = false; BOOST_LOG_TRIVIAL(info) << "hms: download url = " << url; Slic3r::Http http = Slic3r::Http::get(url); http.on_complete([this, receive_json, hms_type, &to_save_local, &local_version](std::string body, unsigned status) { try { json j = json::parse(body); if (j.contains("result")) { if (j["result"] == 0 && j.contains("data")) { if (!j.contains("ver")) { return; } const std::string& remote_ver = std::to_string(j["ver"].get()); if (remote_ver <= local_version) { return; } (*receive_json)["version"] = remote_ver; if (hms_type.compare(QUERY_HMS_INFO) == 0) { (*receive_json) = j["data"]; to_save_local = true; } else if (hms_type.compare(QUERY_HMS_ACTION) == 0) { (*receive_json)["data"] = j["data"]; to_save_local = true; } } else if (j["result"] == 201){ BOOST_LOG_TRIVIAL(info) << "HMSQuery: HMS info is the latest version"; }else{ BOOST_LOG_TRIVIAL(info) << "HMSQuery: update hms info error = " << j["result"].get(); } } } catch (...) { ; } }) .timeout_max(20) .on_error([](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "HMSQuery: update hms info error = " << error << ", body = " << body << ", status = " << status; }).perform_sync(); if (to_save_local && !receive_json->empty()) { save_to_local(lang, hms_type, dev_id_type, *receive_json); } return 0; } static void _copy_dir(const fs::path& from_dir, const fs::path& to_dir) /* the copy will not override files*/ { try { if (!fs::exists(from_dir)) { return; } if (!fs::exists(to_dir)) { fs::create_directory(to_dir); } for (const auto &entry : fs::directory_iterator(from_dir)) { const fs::path &source_path = entry.path(); const fs::path &relative_path = fs::relative(source_path, from_dir); const fs::path &dest_path = to_dir / relative_path; if (fs::is_regular_file(source_path) && !fs::exists(dest_path)) { copy_file(source_path, dest_path); } else if (fs::is_directory(source_path)) { _copy_dir(source_path, dest_path); } } } catch (...) { } } void HMSQuery::copy_from_data_dir_to_local() { const fs::path& from_dir = fs::path(Slic3r::resources_dir()) / HMS_PATH; const fs::path& to_dir = fs::path(Slic3r::data_dir()) / HMS_PATH; _copy_dir(from_dir, to_dir); } int HMSQuery::load_from_local(const std::string& hms_type, const std::string& dev_id_type, json* load_json, std::string& load_version) { if (data_dir().empty()) { load_version = "0"; BOOST_LOG_TRIVIAL(error) << "HMS: load_from_local, data_dir() is empty"; return -1; } std::string filename = get_hms_file(hms_type, HMSQuery::hms_language_code(), dev_id_type); auto hms_folder = (boost::filesystem::path(data_dir()) / "hms"); if (!fs::exists(hms_folder)) fs::create_directory(hms_folder); std::string dir_str = (hms_folder / filename).make_preferred().string(); std::ifstream json_file(encode_path(dir_str.c_str())); try { if (json_file.is_open()) { json_file >> (*load_json); if ((*load_json).contains("version")) { load_version = (*load_json)["version"].get(); return 0; } else { BOOST_LOG_TRIVIAL(warning) << "HMS: load_from_local, no version info"; return 0; } } } catch(...) { load_version = "0"; BOOST_LOG_TRIVIAL(error) << "HMS: load_from_local failed"; return -1; } load_version = "0"; return 0; } int HMSQuery::save_to_local(std::string lang, std::string hms_type, std::string dev_id_type, json save_json) { if (data_dir().empty()) { BOOST_LOG_TRIVIAL(error) << "HMS: save_to_local, data_dir() is empty"; return -1; } std::string filename = get_hms_file(hms_type,lang, dev_id_type); auto hms_folder = (boost::filesystem::path(data_dir()) / "hms"); if (!fs::exists(hms_folder)) fs::create_directory(hms_folder); std::string dir_str = (hms_folder / filename).make_preferred().string(); std::ofstream json_file(encode_path(dir_str.c_str())); if (json_file.is_open()) { json_file << std::setw(4) << save_json << std::endl; json_file.close(); return 0; } BOOST_LOG_TRIVIAL(error) << "HMS: save_to_local failed"; return -1; } std::string HMSQuery::hms_language_code() { AppConfig* config = wxGetApp().app_config; if (!config) // set language code to en by default return "en"; std::string lang_code = wxGetApp().app_config->get_language_code(); if (lang_code.compare("uk") == 0 || lang_code.compare("cs") == 0 || lang_code.compare("ru") == 0 || lang_code.compare("tr") == 0 || lang_code.compare("pt") == 0 || lang_code.compare("ko") == 0 ) { BOOST_LOG_TRIVIAL(info) << "HMS: using english for lang_code = " << lang_code; return "en"; } else if (lang_code.empty()) { // set language code to en by default return "en"; } return lang_code; } std::string HMSQuery::build_query_params(std::string& lang) { std::string lang_code = HMSQuery::hms_language_code(); lang = lang_code; std::string query_params = (boost::format("lang=%1%") % lang_code).str(); return query_params; } std::string HMSQuery::get_hms_file(std::string hms_type, std::string lang, std::string dev_id_type) { //return hms action filename if (hms_type.compare(QUERY_HMS_ACTION) == 0) { return (boost::format("hms_action_%1%.json") % dev_id_type).str(); } //return hms filename return (boost::format("hms_%1%_%2%.json") % lang % dev_id_type).str(); } wxString HMSQuery::query_hms_msg(const MachineObject* obj, const std::string& long_error_code) { if (!obj) { return wxEmptyString; } AppConfig* config = wxGetApp().app_config; if (!config) return wxEmptyString; const std::string& lang_code = HMSQuery::hms_language_code(); return _query_hms_msg(get_dev_id_type(obj),long_error_code, lang_code); } wxString HMSQuery::query_hms_msg(const std::string& dev_id, const std::string& long_error_code) { AppConfig* config = wxGetApp().app_config; if (!config) return wxEmptyString; const std::string& lang_code = HMSQuery::hms_language_code(); return _query_hms_msg(dev_id.substr(0, 3), long_error_code, lang_code); } string HMSQuery::get_dev_id_type(const MachineObject* obj) const { if (obj) { return obj->dev_id.substr(0, 3); } return string(); } wxString HMSQuery::_query_hms_msg(const string& dev_id_type, const string& long_error_code, const string& lang_code) { if (long_error_code.empty()) { return wxEmptyString; } init_hms_info(dev_id_type); auto iter = m_hms_info_jsons.find(dev_id_type); if (iter == m_hms_info_jsons.end()) { BOOST_LOG_TRIVIAL(error) << "there are no hms info for the device"; return wxEmptyString; } const json& m_hms_info_json = iter->second; if (!m_hms_info_json.is_object()) { BOOST_LOG_TRIVIAL(error) << "the hms info is not a valid json object"; return wxEmptyString; } const json& device_hms_json = m_hms_info_json.value("device_hms", json()); if (device_hms_json.is_null() || !device_hms_json.is_object()) { BOOST_LOG_TRIVIAL(error) << "there are no valid json object named device_hms"; return wxEmptyString; } const json& device_hms_msg_json = device_hms_json.value(lang_code, json()); if (device_hms_msg_json.is_null()) { BOOST_LOG_TRIVIAL(error) << "hms: query_hms_msg, do not contains lang_code = " << lang_code; if (lang_code.empty()) /*traverse all if lang_code is empty*/ { for (const auto& lang_item : device_hms_json) { for (const auto& msg_item : lang_item) { if (msg_item.is_object()) { const std::string& error_code = msg_item.value("ecode", json()).get(); if (boost::to_upper_copy(error_code) == long_error_code && msg_item.contains("intro")) { BOOST_LOG_TRIVIAL(info) << "retry without lang_code successed."; return wxString::FromUTF8(msg_item["intro"].get()); } } } } } return wxEmptyString; } for (const auto& item : device_hms_msg_json) { if (item.is_object()) { const std::string& error_code = item.value("ecode", json()).get(); if (boost::to_upper_copy(error_code) == long_error_code && item.contains("intro")) { return wxString::FromUTF8(item["intro"].get()); } } } BOOST_LOG_TRIVIAL(error) << "hms: query_hms_msg, do not contains valid message, lang_code = " << lang_code << " long_error_code = " << long_error_code; return wxEmptyString; } wxString HMSQuery::_query_error_msg(const std::string& dev_id_type, const std::string& error_code, const std::string& lang_code) { init_hms_info(dev_id_type); auto iter = m_hms_info_jsons.find(dev_id_type); if (iter == m_hms_info_jsons.end()) { return wxEmptyString; } const json& m_hms_info_json = iter->second; if (m_hms_info_json.contains("device_error")) { if (m_hms_info_json["device_error"].contains(lang_code)) { for (auto item = m_hms_info_json["device_error"][lang_code].begin(); item != m_hms_info_json["device_error"][lang_code].end(); item++) { if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get()) == error_code) { if (item->contains("intro")) { return wxString::FromUTF8((*item)["intro"].get()); } } } BOOST_LOG_TRIVIAL(info) << "hms: query_error_msg, not found error_code = " << error_code; } else { BOOST_LOG_TRIVIAL(error) << "hms: query_error_msg, do not contains lang_code = " << lang_code; // return first language if (!m_hms_info_json["device_error"].empty()) { for (auto lang : m_hms_info_json["device_error"]) { for (auto item = lang.begin(); item != lang.end(); item++) { if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get()) == error_code) { if (item->contains("intro")) { return wxString::FromUTF8((*item)["intro"].get()); } } } } } } } else { BOOST_LOG_TRIVIAL(info) << "device_error is not exists"; return wxEmptyString; } return wxEmptyString; } wxString HMSQuery::_query_error_image_action(const std::string& dev_id_type, const std::string& long_error_code, std::vector& button_action) { init_hms_info(dev_id_type); auto iter = m_hms_action_jsons.find(dev_id_type); if (iter == m_hms_action_jsons.end()) { return wxEmptyString; } const json& m_hms_action_json = iter->second; if (m_hms_action_json.contains("data")) { for (auto item = m_hms_action_json["data"].begin(); item != m_hms_action_json["data"].end(); item++) { if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get()) == long_error_code) { if (item->contains("device") && (boost::to_upper_copy((*item)["device"].get()) == dev_id_type || (*item)["device"].get() == "default")) { if (item->contains("actions")) { for (auto item_actions = (*item)["actions"].begin(); item_actions != (*item)["actions"].end(); item_actions++) { button_action.emplace_back(item_actions->get()); } } if (item->contains("image")) { return wxString::FromUTF8((*item)["image"].get()); } } } } } else { BOOST_LOG_TRIVIAL(info) << "data is not exists"; return wxEmptyString; } return wxEmptyString; } wxString HMSQuery::query_print_error_msg(const MachineObject* obj, int print_error) { if (!obj) { return wxEmptyString; } char buf[32]; ::sprintf(buf, "%08X", print_error); std::string lang_code = HMSQuery::hms_language_code(); return _query_error_msg(get_dev_id_type(obj), std::string(buf), lang_code); } wxString HMSQuery::query_print_error_msg(const std::string& dev_id, int print_error) { char buf[32]; ::sprintf(buf, "%08X", print_error); std::string lang_code = HMSQuery::hms_language_code(); return _query_error_msg(dev_id.substr(0, 3), std::string(buf), lang_code); } wxString HMSQuery::query_print_image_action(const MachineObject* obj, int print_error, std::vector& button_action) { if (!obj) { return wxEmptyString; } char buf[32]; ::sprintf(buf, "%08X", print_error); //The first three digits of SN number return _query_error_image_action(get_dev_id_type(obj),std::string(buf), button_action); } wxImage HMSQuery::query_image_from_local(const wxString& image_name) { if (image_name.empty() || image_name.Contains("http")) { return wxImage(); } if (m_hms_local_images.empty()) { const fs::path& local_img_dir = fs::path(Slic3r::data_dir()) / HMS_LOCAL_IMG_PATH; if (fs::exists(local_img_dir)) { for (const auto &entry : fs::directory_iterator(local_img_dir)) { const fs::path& image_path = entry.path(); const fs::path& image_name = fs::relative(image_path, local_img_dir); m_hms_local_images[image_name.string()] = wxImage(wxString::FromUTF8(image_path.string())); } } } auto iter = m_hms_local_images.find(image_name); if (iter != m_hms_local_images.end()) { return iter->second; } return wxImage(); } void HMSQuery::clear_hms_info() { std::unique_lock unique_lock(m_hms_mutex); m_hms_info_jsons.clear(); m_hms_action_jsons.clear(); } void HMSQuery::init_hms_info(const std::string& dev_type_id) { std::unique_lock unique_lock(m_hms_mutex); if (m_hms_info_jsons.count(dev_type_id) != 0) { return; } static unordered_set package_dev_id_types { "094" }; if (package_dev_id_types.count(dev_type_id) != 0) { copy_from_data_dir_to_local();// STUDIO-9512 string dev_type = "094"; m_hms_info_jsons.emplace(dev_type, json()); m_hms_action_jsons.emplace(dev_type, json()); std::string load_version; load_from_local(QUERY_HMS_INFO, dev_type, &m_hms_info_jsons[dev_type], load_version); load_from_local(QUERY_HMS_ACTION, dev_type, &m_hms_action_jsons[dev_type], load_version); } static unordered_set cloud_dev_id_types{ "00M", "00W", "03W", "01P", "01S", "030", "039" }; if (cloud_dev_id_types.count(dev_type_id) != 0) { if (m_hms_info_jsons.count(dev_type_id) == 0) { m_hms_info_jsons.emplace(dev_type_id, json()); } if (m_hms_action_jsons.count(dev_type_id) == 0) { m_hms_action_jsons.emplace(dev_type_id, json()); } download_hms_related(QUERY_HMS_INFO, dev_type_id, &m_hms_info_jsons[dev_type_id]); download_hms_related(QUERY_HMS_ACTION, dev_type_id, &m_hms_action_jsons[dev_type_id]); } } std::string get_hms_wiki_url(std::string error_code) { AppConfig* config = wxGetApp().app_config; if (!config) return ""; std::string hms_host = wxGetApp().app_config->get_hms_host(); std::string lang_code = HMSQuery::hms_language_code(); std::string url = (boost::format("https://%1%/index.php?e=%2%&s=device_hms&lang=%3%") % hms_host % error_code % lang_code).str(); DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return url; MachineObject* obj = dev->get_selected_machine(); if (!obj) return url; if (!obj->dev_id.empty()) { url = (boost::format("https://%1%/index.php?e=%2%&d=%3%&s=device_hms&lang=%4%") % hms_host % error_code % obj->dev_id % lang_code).str(); } return url; } std::string get_error_message(int error_code) { char buf[64]; std::string result_str = ""; std::sprintf(buf,"%08X",error_code); std::string hms_host = wxGetApp().app_config->get_hms_host(); std::string get_lang = wxGetApp().app_config->get_language_code(); std::string url = (boost::format("https://%1%/query.php?lang=%2%&e=%3%") %hms_host %get_lang %buf).str(); Slic3r::Http http = Slic3r::Http::get(url); http.header("accept", "application/json") .timeout_max(10) .on_complete([get_lang, &result_str](std::string body, unsigned status) { try { json j = json::parse(body); if (j.contains("result")) { if (j["result"].get() == 0) { if (j.contains("data")) { json jj = j["data"]; if (jj.contains("device_error")) { if (jj["device_error"].contains(get_lang)) { if (jj["device_error"][get_lang].size() > 0) { if (!jj["device_error"][get_lang][0]["intro"].empty() || !jj["device_error"][get_lang][0]["ecode"].empty()) { std::string error_info = jj["device_error"][get_lang][0]["intro"].get(); std::string error_code = jj["device_error"][get_lang][0]["ecode"].get(); error_code.insert(4, " "); result_str = from_u8(error_info).ToStdString() + "[" + error_code + "]"; } } } } } } } } catch (...) { ; } }) .on_error([](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(trace) << boost::format("[BBL ErrorMessage]: status=%1%, error=%2%, body=%3%") % status % error % body; }).perform_sync(); return result_str; } } }