#include "UserAccount.hpp" #include "UserAccountUtils.hpp" #include "format.hpp" #include "GUI.hpp" #include "libslic3r/Utils.hpp" #include #include #include #include #include namespace pt = boost::property_tree; namespace Slic3r { namespace GUI { UserAccount::UserAccount(wxEvtHandler* evt_handler, AppConfig* app_config, const std::string& instance_hash) : m_communication(std::make_unique(evt_handler, app_config)) , m_instance_hash(instance_hash) { } UserAccount::~UserAccount() {} void UserAccount::set_username(const std::string& username) { m_username = username; m_communication->set_username(username); } void UserAccount::clear() { m_username = {}; m_account_user_data.clear(); m_printer_map.clear(); m_communication->do_clear(); } void UserAccount::set_remember_session(bool remember) { m_communication->set_remember_session(remember); } void UserAccount::toggle_remember_session() { m_communication->set_remember_session(!m_communication->get_remember_session()); } bool UserAccount::get_remember_session() { return m_communication->get_remember_session(); } bool UserAccount::is_logged() { return m_communication->is_logged(); } void UserAccount::do_login() { m_communication->do_login(); } void UserAccount::do_logout() { m_communication->do_logout(); } std::string UserAccount::get_access_token() { return m_communication->get_access_token(); } std::string UserAccount::get_shared_session_key() { return m_communication->get_shared_session_key(); } boost::filesystem::path UserAccount::get_avatar_path(bool logged) const { if (logged) { const std::string filename = "prusaslicer-avatar-" + m_instance_hash + m_avatar_extension; return into_path(wxStandardPaths::Get().GetTempDir()) / filename; } else { return boost::filesystem::path(resources_dir()) / "icons" / "user.svg"; } } void UserAccount::enqueue_connect_printer_models_action() { m_communication->enqueue_connect_printer_models_action(); } void UserAccount::enqueue_connect_status_action() { m_communication->enqueue_connect_status_action(); } void UserAccount::enqueue_avatar_action() { m_communication->enqueue_avatar_action(m_account_user_data["avatar"]); } void UserAccount::enqueue_printer_data_action(const std::string& uuid) { m_communication->enqueue_printer_data_action(uuid); } void UserAccount::request_refresh() { m_communication->request_refresh(); } bool UserAccount::on_login_code_recieved(const std::string& url_message) { m_communication->on_login_code_recieved(url_message); return true; } bool UserAccount::on_user_id_success(const std::string data, std::string& out_username) { boost::property_tree::ptree ptree; try { std::stringstream ss(data); boost::property_tree::read_json(ss, ptree); } catch (const std::exception&) { BOOST_LOG_TRIVIAL(error) << "UserIDUserAction Could not parse server response."; return false; } m_account_user_data.clear(); for (const auto& section : ptree) { const auto opt = ptree.get_optional(section.first); if (opt) { BOOST_LOG_TRIVIAL(debug) << static_cast(section.first) << " " << *opt; m_account_user_data[section.first] = *opt; } } if (m_account_user_data.find("public_username") == m_account_user_data.end()) { BOOST_LOG_TRIVIAL(error) << "User ID message from PrusaAuth did not contain public_username. Login failed. Message data: " << data; return false; } std::string public_username = m_account_user_data["public_username"]; set_username(public_username); out_username = public_username; // enqueue GET with avatar url if (m_account_user_data.find("avatar") != m_account_user_data.end()) { const boost::filesystem::path server_file(m_account_user_data["avatar"]); m_avatar_extension = server_file.extension().string(); enqueue_avatar_action(); } else { BOOST_LOG_TRIVIAL(error) << "User ID message from PrusaAuth did not contain avatar."; } // update printers list enqueue_connect_printer_models_action(); return true; } void UserAccount::on_communication_fail() { m_fail_counter++; if (m_fail_counter > 5) // there is no deeper reason why 5 { m_communication->enqueue_test_connection(); m_fail_counter = 0; } } bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed) { BOOST_LOG_TRIVIAL(debug) << "Prusa Connect printers message: " << data; pt::ptree ptree; try { std::stringstream ss(data); pt::read_json(ss, ptree); } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); return false; } // tree format: /* [{ "printer_uuid": "972d2ce7-0967-4555-bff2-330c7fa0a4e1", "printer_state" : "IDLE" }, { "printer_uuid": "15d160fd-c7e4-4b5a-9748-f0e531c7e0f5", "printer_state" : "OFFLINE" }] */ ConnectPrinterStateMap new_printer_map; for (const auto& printer_tree : ptree) { const auto printer_uuid = printer_tree.second.get_optional("printer_uuid"); if (!printer_uuid) { continue; } const auto printer_state = printer_tree.second.get_optional("printer_state"); if (!printer_state) { continue; } ConnectPrinterState state; if (auto pair = printer_state_table.find(*printer_state); pair != printer_state_table.end()) { state = pair->second; } else { assert(true); // On this assert, printer_state_table needs to be updated with *state_opt and correct ConnectPrinterState continue; } if (m_printer_uuid_map.find(*printer_uuid) == m_printer_uuid_map.end()) { BOOST_LOG_TRIVIAL(error) << "Missing printer model for printer uuid: " << *printer_uuid; continue; } std::pair model_nozzle_pair = m_printer_uuid_map[*printer_uuid]; if (new_printer_map.find(model_nozzle_pair) == new_printer_map.end()) { new_printer_map[model_nozzle_pair].reserve(static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT)); for (size_t i = 0; i < static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) { new_printer_map[model_nozzle_pair].push_back(0); } } new_printer_map[model_nozzle_pair][static_cast(state)] += 1; } // compare new and old printer map and update old map into new out_printers_changed = false; for (const auto& it : new_printer_map) { if (m_printer_map.find(it.first) == m_printer_map.end()) { // printer is not in old map, add it by copying data from new map out_printers_changed = true; m_printer_map[it.first].reserve(static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT)); for (size_t i = 0; i < static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) { m_printer_map[it.first].push_back(new_printer_map[it.first][i]); } } else { // printer is in old map, check state by state for (size_t i = 0; i < static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) { if (m_printer_map[it.first][i] != new_printer_map[it.first][i]) { out_printers_changed = true; m_printer_map[it.first][i] = new_printer_map[it.first][i]; } } } } return true; } bool UserAccount::on_connect_uiid_map_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed) { m_printer_uuid_map.clear(); pt::ptree ptree; try { std::stringstream ss(data); pt::read_json(ss, ptree); } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); return false; } for (const auto& printer_tree : ptree) { const auto printer_uuid = printer_tree.second.get_optional("printer_uuid"); if (!printer_uuid) { continue; } const auto printer_model = printer_tree.second.get_optional("printer_model"); if (!printer_model) { continue; } const auto nozzle_diameter_opt = printer_tree.second.get_optional("nozzle_diameter"); const std::string nozzle_diameter = (nozzle_diameter_opt && *nozzle_diameter_opt != "0.0") ? *nozzle_diameter_opt : std::string(); std::pair model_nozzle_pair = { *printer_model, nozzle_diameter }; m_printer_uuid_map[*printer_uuid] = model_nozzle_pair; } m_communication->on_uuid_map_success(); return on_connect_printers_success(data, app_config, out_printers_changed); } std::string UserAccount::get_current_printer_uuid_from_connect(const std::string &selected_printer_id ) const { if (m_current_printer_data_json_from_connect.empty() || m_current_printer_uuid_from_connect.empty()) { return {}; } pt::ptree ptree; try { std::stringstream ss(m_current_printer_data_json_from_connect); pt::read_json(ss, ptree); } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Could not parse Printer data from Connect. " << e.what(); return {}; } std::string data_uuid = UserAccountUtils::get_keyword_from_json(ptree, "", "uuid"); assert(data_uuid == m_current_printer_uuid_from_connect); //std::string model_name = parse_tree_for_param(ptree, "printer_model"); std::vector compatible_printers; UserAccountUtils::fill_supported_printer_models_from_json(ptree, compatible_printers); if (compatible_printers.empty()) { return {}; } return std::find(compatible_printers.begin(), compatible_printers.end(), selected_printer_id) == compatible_printers.end() ? "" : m_current_printer_uuid_from_connect; } }} // namespace slic3r::GUI