PrusaSlicer/src/slic3r/GUI/UserAccount.cpp
David Kocik 5ba8f21c77 SPE-2570: Refresh access token if Printables fire accessTokenExpired event
Add fancy loading overlay during refresh period

missing include
2024-11-20 10:08:49 +01:00

307 lines
10 KiB
C++

#include "UserAccount.hpp"
#include "UserAccountUtils.hpp"
#include "format.hpp"
#include "GUI.hpp"
#include "libslic3r/Utils.hpp"
#include <boost/regex.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
#include <wx/stdpaths.h>
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<UserAccountCommunication>(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<std::string>(section.first);
if (opt) {
BOOST_LOG_TRIVIAL(debug) << static_cast<std::string>(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<std::string>("printer_uuid");
if (!printer_uuid) {
continue;
}
const auto printer_state = printer_tree.second.get_optional<std::string>("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<std::string, std::string> 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<size_t>(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT));
for (size_t i = 0; i < static_cast<size_t>(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) {
new_printer_map[model_nozzle_pair].push_back(0);
}
}
new_printer_map[model_nozzle_pair][static_cast<size_t>(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<size_t>(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT));
for (size_t i = 0; i < static_cast<size_t>(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<size_t>(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<std::string>("printer_uuid");
if (!printer_uuid) {
continue;
}
const auto printer_model = printer_tree.second.get_optional<std::string>("printer_model");
if (!printer_model) {
continue;
}
const auto nozzle_diameter_opt = printer_tree.second.get_optional<std::string>("nozzle_diameter");
const std::string nozzle_diameter = (nozzle_diameter_opt && *nozzle_diameter_opt != "0.0") ? *nozzle_diameter_opt : std::string();
std::pair<std::string, std::string> 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<std::string> 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