From b05d438fc67fd657a07ceae824e066c49c8f746e Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 22 Apr 2024 16:01:05 +0200 Subject: [PATCH] Changes in Connect Printer Status. First use endpoint PrinterModels to get uuid to model map, than get statuses for uuids from Status endpoint. Lang code trimmed to 2 chars. --- src/slic3r/GUI/Plater.cpp | 15 ++- src/slic3r/GUI/UserAccount.cpp | 114 ++++++++++++-------- src/slic3r/GUI/UserAccount.hpp | 6 +- src/slic3r/GUI/UserAccountCommunication.cpp | 19 +++- src/slic3r/GUI/UserAccountCommunication.hpp | 3 +- src/slic3r/GUI/UserAccountSession.cpp | 3 +- src/slic3r/GUI/UserAccountSession.hpp | 7 +- src/slic3r/GUI/WebViewDialog.cpp | 3 +- 8 files changed, 116 insertions(+), 54 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5bc5e0916b..172f6e0f5b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -937,7 +937,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) BOOST_LOG_TRIVIAL(error) << "Failed communication with Prusa Account: " << evt.data; user_account->on_communication_fail(); }); - this->q->Bind(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, [this](UserAccountSuccessEvent& evt) { + this->q->Bind(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, [this](UserAccountSuccessEvent& evt) { std::string text; bool printers_changed = false; if (user_account->on_connect_printers_success(evt.data, wxGetApp().app_config, printers_changed)) { @@ -949,6 +949,19 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) user_account->on_communication_fail(); } }); + this->q->Bind(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, [this](UserAccountSuccessEvent& evt) { + std::string text; + bool printers_changed = false; + if (user_account->on_connect_uiid_map_success(evt.data, wxGetApp().app_config, printers_changed)) { + if (printers_changed) { + sidebar->update_printer_presets_combobox(); + } + } + else { + // message was corrupt, procceed like EVT_UA_FAIL + user_account->on_communication_fail(); + } + }); this->q->Bind(EVT_UA_AVATAR_SUCCESS, [this](UserAccountSuccessEvent& evt) { boost::filesystem::path path = user_account->get_avatar_path(true); FILE* file; diff --git a/src/slic3r/GUI/UserAccount.cpp b/src/slic3r/GUI/UserAccount.cpp index 2a3c0e2c3e..33099c91cb 100644 --- a/src/slic3r/GUI/UserAccount.cpp +++ b/src/slic3r/GUI/UserAccount.cpp @@ -84,10 +84,13 @@ boost::filesystem::path UserAccount::get_avatar_path(bool logged) const } } - -void UserAccount::enqueue_connect_printers_action() +void UserAccount::enqueue_connect_printer_models_action() { - m_communication->enqueue_connect_printers_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() { @@ -137,7 +140,7 @@ bool UserAccount::on_user_id_success(const std::string data, std::string& out_us BOOST_LOG_TRIVIAL(error) << "User ID message from PrusaAuth did not contain avatar."; } // update printers list - enqueue_connect_printers_action(); + enqueue_connect_printer_models_action(); return true; } @@ -149,6 +152,10 @@ void UserAccount::on_communication_fail() m_communication->enqueue_test_connection(); m_fail_counter = 0; } + // Printer models are called only after login, if it fails, it should repeat + if (m_printer_uuid_map.empty()) { + enqueue_connect_printer_models_action(); + } } namespace { @@ -204,51 +211,45 @@ bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); return false; } - // fill m_printer_map with data from ptree - // tree string is in format {"result": [{"printer_type": "1.2.3", "states": [{"printer_state": "OFFLINE", "count": 1}, ...]}, {..}]} - + // 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; - - assert(ptree.front().first == "result"); - for (const auto& printer_tree : ptree.front().second) { - // printer_tree is {"printer_type": "1.2.3", "states": [..]} - std::string name; - ConnectPrinterState state; - - const auto type_opt = printer_tree.second.get_optional("printer_model"); - if (!type_opt) { + for (const auto& printer_tree : ptree) { + const auto printer_uuid = printer_tree.second.get_optional("printer_uuid"); + if (!printer_uuid) { continue; } - // printer_type is actually printer_name for now - name = *type_opt; - // printer should not appear twice - assert(new_printer_map.find(name) == new_printer_map.end()); - // prepare all states on 0 - new_printer_map[name].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[name].push_back(0); + const auto printer_state = printer_tree.second.get_optional("printer_state"); + if (!printer_state) { + continue; } - - for (const auto& section : printer_tree.second) { - // section is "printer_type": "1.2.3" OR "states": [..]} - if (section.first == "states") { - for (const auto& subsection : section.second) { - // subsection is {"printer_state": "OFFLINE", "count": 1} - const auto state_opt = subsection.second.get_optional("printer_state"); - const auto count_opt = subsection.second.get_optional("count"); - if (!state_opt || ! count_opt) { - continue; - } - if (auto pair = printer_state_table.find(*state_opt); 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; - } - new_printer_map[name][static_cast(state)] = *count_opt; - } + 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; + } + const std::string printer_model = m_printer_uuid_map[*printer_uuid]; + if (new_printer_map.find(printer_model) == new_printer_map.end()) { + new_printer_map[printer_model].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[printer_model].push_back(0); } } + new_printer_map[printer_model][static_cast(state)] += 1; } // compare new and old printer map and update old map into new @@ -274,6 +275,33 @@ bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig 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; + } + m_printer_uuid_map[*printer_uuid] = *printer_model; + } + return on_connect_printers_success(data, app_config, out_printers_changed); +} + std::string UserAccount::get_model_from_json(const std::string& message) const { std::string out; diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp index 485396dea2..a948a552a2 100644 --- a/src/slic3r/GUI/UserAccount.hpp +++ b/src/slic3r/GUI/UserAccount.hpp @@ -26,6 +26,7 @@ enum class ConnectPrinterState { }; typedef std::map> ConnectPrinterStateMap; +typedef std::map ConnectUUIDToModelMap; // Class UserAccount should handle every request for entities outside PrusaSlicer like PrusaAuth or PrusaConnect. // Outside communication is implemented in class UserAccountCommunication that runs separate thread. Results come back in events to Plater. // All incoming data shoud be stored in UserAccount. @@ -41,7 +42,8 @@ public: void set_remember_session(bool remember); void toggle_remember_session(); bool get_remember_session(); - void enqueue_connect_printers_action(); + void enqueue_connect_status_action(); + void enqueue_connect_printer_models_action(); void enqueue_avatar_action(); // Clears all data and connections, called on logout or EVT_UA_RESET @@ -54,6 +56,7 @@ public: // Called on EVT_UA_FAIL, triggers test after several calls void on_communication_fail(); bool on_connect_printers_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed); + bool on_connect_uiid_map_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed); std::string get_username() const { return m_username; } std::string get_access_token(); @@ -80,6 +83,7 @@ private: std::unique_ptr m_communication; ConnectPrinterStateMap m_printer_map; + ConnectUUIDToModelMap m_printer_uuid_map; std::map m_account_user_data; std::string m_username; size_t m_fail_counter { 0 }; diff --git a/src/slic3r/GUI/UserAccountCommunication.cpp b/src/slic3r/GUI/UserAccountCommunication.cpp index f31c8eab9f..fabc1b8e4a 100644 --- a/src/slic3r/GUI/UserAccountCommunication.cpp +++ b/src/slic3r/GUI/UserAccountCommunication.cpp @@ -275,14 +275,25 @@ void UserAccountCommunication::on_login_code_recieved(const std::string& url_mes wakeup_session_thread(); } - - -void UserAccountCommunication::enqueue_connect_printers_action() +void UserAccountCommunication::enqueue_connect_printer_models_action() { { std::lock_guard lock(m_session_mutex); if (!m_session->is_initialized()) { - BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in."; + BOOST_LOG_TRIVIAL(error) << "Connect Printer Models connection failed - Not Logged in."; + return; + } + m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS, nullptr, nullptr, {}); + } + wakeup_session_thread(); +} + +void UserAccountCommunication::enqueue_connect_status_action() +{ + { + std::lock_guard lock(m_session_mutex); + if (!m_session->is_initialized()) { + BOOST_LOG_TRIVIAL(error) << "Connect Status endpoint connection failed - Not Logged in."; return; } m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS, nullptr, nullptr, {}); diff --git a/src/slic3r/GUI/UserAccountCommunication.hpp b/src/slic3r/GUI/UserAccountCommunication.hpp index 408861f85d..0dcd3864d2 100644 --- a/src/slic3r/GUI/UserAccountCommunication.hpp +++ b/src/slic3r/GUI/UserAccountCommunication.hpp @@ -39,7 +39,8 @@ public: void do_logout(); void do_clear(); // Trigger function starts various remote operations - void enqueue_connect_printers_action(); + void enqueue_connect_status_action(); + void enqueue_connect_printer_models_action(); void enqueue_avatar_action(const std::string& url); void enqueue_test_connection(); diff --git a/src/slic3r/GUI/UserAccountSession.cpp b/src/slic3r/GUI/UserAccountSession.cpp index d5839a6648..9c2b588179 100644 --- a/src/slic3r/GUI/UserAccountSession.cpp +++ b/src/slic3r/GUI/UserAccountSession.cpp @@ -22,7 +22,8 @@ wxDEFINE_EVENT(EVT_OPEN_PRUSAAUTH, OpenPrusaAuthEvent); wxDEFINE_EVENT(EVT_UA_LOGGEDOUT, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_ID_USER_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent); -wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, UserAccountSuccessEvent); +wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, UserAccountSuccessEvent); +wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_FAIL, UserAccountFailEvent); wxDEFINE_EVENT(EVT_UA_RESET, UserAccountFailEvent); diff --git a/src/slic3r/GUI/UserAccountSession.hpp b/src/slic3r/GUI/UserAccountSession.hpp index f28f195e13..b40ab54f19 100644 --- a/src/slic3r/GUI/UserAccountSession.hpp +++ b/src/slic3r/GUI/UserAccountSession.hpp @@ -20,7 +20,8 @@ wxDECLARE_EVENT(EVT_OPEN_PRUSAAUTH, OpenPrusaAuthEvent); wxDECLARE_EVENT(EVT_UA_LOGGEDOUT, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_ID_USER_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent); -wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, UserAccountSuccessEvent); +wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, UserAccountSuccessEvent); +wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_FAIL, UserAccountFailEvent); // Soft fail - clears only after some number of fails wxDECLARE_EVENT(EVT_UA_RESET, UserAccountFailEvent); // Hard fail - clears all @@ -38,6 +39,7 @@ enum class UserAccountActionID { USER_ACCOUNT_ACTION_TEST_ACCESS_TOKEN, USER_ACCOUNT_ACTION_TEST_CONNECTION, USER_ACCOUNT_ACTION_CONNECT_STATUS, // status of all printers + USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS, USER_ACCOUNT_ACTION_AVATAR, }; class UserAction @@ -110,7 +112,8 @@ public: m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_USER_ID] = std::make_unique("USER_ID", "https://account.prusa3d.com/api/v1/me/", EVT_UA_ID_USER_SUCCESS, EVT_UA_RESET); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_ACCESS_TOKEN] = std::make_unique("TEST_ACCESS_TOKEN", "https://account.prusa3d.com/api/v1/me/", EVT_UA_ID_USER_SUCCESS, EVT_UA_FAIL); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION] = std::make_unique("TEST_CONNECTION", "https://account.prusa3d.com/api/v1/me/", wxEVT_NULL, EVT_UA_RESET); - m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS] = std::make_unique("CONNECT_STATUS", "https://connect.prusa3d.com/slicer/status", EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, EVT_UA_FAIL); + m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS] = std::make_unique("CONNECT_STATUS", "https://connect.prusa3d.com/slicer/status", EVT_UA_PRUSACONNECT_STATUS_SUCCESS, EVT_UA_FAIL); + m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS] = std::make_unique("CONNECT_PRINTER_MODELS", "https://connect.prusa3d.com/slicer/printer_list", EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, EVT_UA_FAIL); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_AVATAR] = std::make_unique("AVATAR", "https://media.printables.com/media/", EVT_UA_AVATAR_SUCCESS, EVT_UA_FAIL); } ~UserAccountSession() diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 603e78a78e..847f7e7313 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -538,7 +538,8 @@ void ConnectRequestHandler::on_request_config() const std::string token = wxGetApp().plater()->get_user_account()->get_access_token(); //const std::string sesh = wxGetApp().plater()->get_user_account()->get_shared_session_key(); const std::string dark_mode = wxGetApp().dark_mode() ? "DARK" : "LIGHT"; - const wxString language = GUI::wxGetApp().current_language_code(); + wxString language = GUI::wxGetApp().current_language_code(); + language = language.SubString(0, 1); const std::string init_options = GUI::format("{\"accessToken\": \"%1%\" , \"clientVersion\": \"%2%\", \"colorMode\": \"%3%\", \"language\": \"%4%\"}", token, SLIC3R_VERSION, dark_mode, language); wxString script = GUI::format_wxstr("window._prusaConnect_v1.init(%1%)", init_options); run_script_bridge(script);