diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 1b170bf884..da82016a6f 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -853,6 +853,10 @@ std::string AppConfig::load() local_machine.dev_ip = p["dev_ip"].get(); if (p.contains("printer_type")) local_machine.printer_type = p["printer_type"].get(); + if (p.contains("printer_agent_id")) + local_machine.printer_agent_id = p["printer_agent_id"].get(); + if (p.contains("access_code")) + local_machine.access_code = p["access_code"].get(); m_local_machines[local_machine.dev_id] = local_machine; } } else { @@ -1065,6 +1069,8 @@ void AppConfig::save() m_json["dev_name"] = local_machine.second.dev_name; m_json["dev_ip"] = local_machine.second.dev_ip; m_json["printer_type"] = local_machine.second.printer_type; + m_json["printer_agent_id"] = local_machine.second.printer_agent_id; + m_json["access_code"] = local_machine.second.access_code; j["local_machines"][local_machine.first] = m_json; } diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 2c83ebb488..b73ff5eac4 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -61,10 +61,19 @@ struct BBLocalMachine std::string dev_ip; std::string dev_id; /* serial number */ std::string printer_type; /* model_id */ + std::string printer_agent_id; /* id of the IPrinterAgent that discovered/bound this device, e.g. "bbl"; empty for entries persisted before this field existed */ + // Access code, scoped to printer_agent_id above - so a code saved while bound under one + // printer agent isn't treated as valid for a different, independent agent talking to the + // same physical dev_id. Empty for entries persisted before this field existed; those fall + // back to the legacy flat "access_code"/"user_access_code" AppConfig sections (BBL-only, + // since BBL was the only agent when they were saved) - see + // get_access_code_with_legacy_fallback() in DevManager.cpp. + std::string access_code; bool operator==(const BBLocalMachine& other) const { - return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type; + return dev_name == other.dev_name && dev_ip == other.dev_ip && dev_id == other.dev_id && printer_type == other.printer_type && + printer_agent_id == other.printer_agent_id && access_code == other.access_code; } bool operator!=(const BBLocalMachine& other) const { return !operator==(other); } }; diff --git a/src/slic3r/GUI/DeviceCore/DevManager.cpp b/src/slic3r/GUI/DeviceCore/DevManager.cpp index edc958ec53..8844303793 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.cpp +++ b/src/slic3r/GUI/DeviceCore/DevManager.cpp @@ -10,20 +10,36 @@ #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/Utils/NetworkAgentFactory.hpp" #include "libslic3r/Time.hpp" using namespace nlohmann; namespace { - // Orca: access_code and user_access_code used to be separate AppConfig keys before the two - // fields were merged; fall back to the legacy key so existing users' saved codes aren't lost. - std::string get_access_code_with_legacy_fallback(Slic3r::AppConfig* config, const std::string& dev_id) + // Orca: access_code lives on BBLocalMachine::access_code (keyed by dev_id via + // get_local_machines(), scoped by the record's own printer_agent_id field) - so binding a + // printer under one agent doesn't silently appear as already-bound under a different, + // independent agent. This only covers LAN devices (BBLocalMachine's own scope); access_code + // and user_access_code used to be the only, flat dev_id-only AppConfig keys before + // BBLocalMachine::access_code existed, and codes saved back then are still stored flat (no + // agent association at all). Since BBL was the only agent that existed at the time, honor + // those flat legacy keys as implicitly BBL's - but only for the BBL agent, so they aren't + // leaked to other agents that never bound the device themselves. + std::string get_access_code_with_legacy_fallback(Slic3r::AppConfig* config, const std::string& dev_id, const std::string& agent_id) { - std::string code = config->get("access_code", dev_id); - if (code.empty()) - code = config->get("user_access_code", dev_id); - return code; + const auto& machines = config->get_local_machines(); + auto it = machines.find(dev_id); + if (it != machines.end() && it->second.printer_agent_id == agent_id && !it->second.access_code.empty()) + return it->second.access_code; + + if (agent_id == Slic3r::BBL_PRINTER_AGENT_ID || agent_id.empty()) { + std::string code = config->get("access_code", dev_id); + if (code.empty()) + code = config->get("user_access_code", dev_id); + return code; + } + return ""; } } @@ -55,12 +71,13 @@ namespace Slic3r continue; MachineObject* obj = new MachineObject(this, m_agent, m.dev_name, m.dev_id, m.dev_ip); obj->printer_type = m.printer_type; + obj->printer_agent_id = m.printer_agent_id; obj->dev_connection_type = "lan"; obj->bind_state = "free"; obj->bind_sec_link = "secure"; obj->m_is_online = true; obj->last_alive = Slic3r::Utils::get_current_time_utc(); - obj->set_access_code(get_access_code_with_legacy_fallback(config, m.dev_id), false); + obj->set_access_code(get_access_code_with_legacy_fallback(config, m.dev_id, obj->printer_agent_id), false); if (obj->has_access_right()) { localMachineList.insert(std::make_pair(m.dev_id, obj)); } else { @@ -77,10 +94,12 @@ namespace Slic3r if (m.is_lan_mode_printer()) { if (m.has_access_right()) { BBLocalMachine local_machine; - local_machine.dev_id = m.get_dev_id(); - local_machine.dev_name = m.get_dev_name(); - local_machine.dev_ip = m.get_dev_ip(); - local_machine.printer_type = m.printer_type; + local_machine.dev_id = m.get_dev_id(); + local_machine.dev_name = m.get_dev_name(); + local_machine.dev_ip = m.get_dev_ip(); + local_machine.printer_type = m.printer_type; + local_machine.printer_agent_id = m.printer_agent_id; + local_machine.access_code = m.get_access_code(); config->update_local_machine(local_machine); } } else { @@ -143,6 +162,14 @@ namespace Slic3r } } + std::string DeviceManager::get_current_printer_agent_id() const + { + if (!m_agent) + return ""; + auto printer_agent = m_agent->get_printer_agent(); + return printer_agent ? printer_agent->get_agent_info().id : ""; + } + void DeviceManager::EnableMultiMachine(bool enable) { m_agent->enable_multi_machine(enable); @@ -339,6 +366,7 @@ namespace Slic3r /* insert a new machine */ obj = new MachineObject(this, m_agent, dev_name, dev_id, dev_ip); obj->printer_type = _parse_printer_type(printer_type_str); + obj->printer_agent_id = get_current_printer_agent_id(); obj->wifi_signal = printer_signal; obj->dev_connection_type = connect_type; obj->bind_state = bind_state; @@ -350,7 +378,7 @@ namespace Slic3r //load access code AppConfig* config = Slic3r::GUI::wxGetApp().app_config; if (config) { - obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id), false); + obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id, obj->printer_agent_id), false); } localMachineList.insert(std::make_pair(dev_id, obj)); @@ -379,6 +407,7 @@ namespace Slic3r obj = it->second; } else { obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip); + obj->printer_agent_id = get_current_printer_agent_id(); localMachineList.insert(std::make_pair(machine.dev_id, obj)); } if (machine.printer_type.empty()) @@ -505,16 +534,26 @@ namespace Slic3r OnSelectedMachineChanged(previous_selected_machine, selected_machine); } - void DeviceManager::clear_other_devices() + void DeviceManager::clear_other_devices(const std::string& target_agent_id) { // why: on agent swap, keep "My Devices" but drop the transient "Other Devices" // Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own. + // + // Also drop "My Devices" stamped by a different agent than the one we're swapping to + // (target_agent_id, passed by the caller since the live agent hasn't been repointed yet + // at this point): otherwise a device first discovered under agent A survives every swap + // with a stale printer_agent_id, stays hidden from every agent's filtered list, and only + // gets re-tagged if something happens to delete and re-create it (e.g. account logout). + // Dropping it here instead lets the new agent's start_discovery re-insert and re-stamp it + // like any other fresh device. const auto my = get_my_machine_list(); for (auto it = localMachineList.begin(); it != localMachineList.end();) { - if (my.find(it->first) == my.end()) + const bool is_my_device = my.find(it->first) != my.end(); + const bool agent_mismatch = !target_agent_id.empty() && it->second && + it->second->printer_agent_id != target_agent_id; + if (!is_my_device || agent_mismatch) { - // not a "My Device" -> an "Other Device" delete it->second; it = localMachineList.erase(it); } @@ -697,13 +736,16 @@ namespace Slic3r m_agent->add_subscribe(subscribe_list_cache); } - std::map DeviceManager::get_my_machine_list() + std::map DeviceManager::get_my_machine_list(const std::string& agent_id) { std::map result; for (auto it = userMachineList.begin(); it != userMachineList.end(); it++) { - if (it->second && !it->second->is_lan_mode_printer()) + if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id)) + continue; + + if (!it->second->is_lan_mode_printer()) { result.insert(std::make_pair(it->first, it->second)); } @@ -711,7 +753,10 @@ namespace Slic3r for (auto it = localMachineList.begin(); it != localMachineList.end(); it++) { - if (it->second && it->second->has_access_right() && it->second->is_avaliable() && it->second->is_lan_mode_printer()) + if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id)) + continue; + + if (it->second->has_access_right() && it->second->is_avaliable() && it->second->is_lan_mode_printer()) { // remove redundant in userMachineList if (result.find(it->first) == result.end()) @@ -723,12 +768,15 @@ namespace Slic3r return result; } - std::map DeviceManager::get_my_cloud_machine_list() + std::map DeviceManager::get_my_cloud_machine_list(const std::string& agent_id) { std::map result; for (auto it = userMachineList.begin(); it != userMachineList.end(); it++) { - if (it->second && !it->second->is_lan_mode_printer()) { result.emplace(*it); } + if (!it->second || (!agent_id.empty() && it->second->printer_agent_id != agent_id)) + continue; + + if (!it->second->is_lan_mode_printer()) { result.emplace(*it); } } return result; } @@ -801,6 +849,7 @@ namespace Slic3r else { obj = new MachineObject(this, m_agent, "", "", ""); + obj->printer_agent_id = get_current_printer_agent_id(); if (m_agent) { obj->set_bind_status(m_agent->get_user_name(provider)); diff --git a/src/slic3r/GUI/DeviceCore/DevManager.h b/src/slic3r/GUI/DeviceCore/DevManager.h index e3ac0064b9..1f48baba98 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.h +++ b/src/slic3r/GUI/DeviceCore/DevManager.h @@ -74,7 +74,10 @@ public: void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); } void clean_user_info(bool keep_local_selection = false); - void clear_other_devices(); + // target_agent_id: id of the agent being swapped to (empty = no agent-mismatch check, + // just the original "drop Other Devices" behavior). Pass the incoming agent's id, not the + // live one - this runs before the live agent is repointed. + void clear_other_devices(const std::string& target_agent_id = ""); void load_last_machine(); void update_user_machine_list_info(const std::string& provider); @@ -90,10 +93,15 @@ public: /* my machine*/ MachineObject* get_my_machine(std::string dev_id); - std::map get_my_machine_list(); - std::map get_my_cloud_machine_list(); + std::map get_my_machine_list(const std::string& agent_id = ""); + std::map get_my_cloud_machine_list(const std::string& agent_id = ""); void modify_device_name(std::string dev_id, std::string dev_name, const std::string& provider); + // id of the currently live IPrinterAgent (IPrinterAgent::get_agent_info().id), or empty if + // m_agent has no printer agent set yet. Pass to get_my_machine_list()/get_my_cloud_machine_list() + // to scope results to the active agent. + std::string get_current_printer_agent_id() const; + /* create machine or update machine properties */ void on_machine_alive(std::string json_str); int query_bind_status(std::string& msg, const std::string& provider); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index cb29fbe11a..48f3cb60fc 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -3,6 +3,7 @@ #include "libslic3r/Time.hpp" #include "libslic3r/Thread.hpp" #include "slic3r/Utils/NetworkAgent.hpp" +#include "slic3r/Utils/NetworkAgentFactory.hpp" #include "GuiColor.hpp" #include "GUI_App.hpp" @@ -458,11 +459,41 @@ void MachineObject::set_access_code(std::string code, bool only_refresh) if (only_refresh) { AppConfig* config = GUI::wxGetApp().app_config; if (config) { - if (!code.empty()) { - GUI::wxGetApp().app_config->set_str("access_code", get_dev_id(), code); - DeviceManager::update_local_machine(*this); + if (is_lan_mode_printer()) { + // why: LAN codes are scoped via BBLocalMachine::access_code, keyed by dev_id and + // scoped by that record's own printer_agent_id field - see the matching comment + // on get_access_code_with_legacy_fallback() in DevManager.cpp - so binding this + // device under one printer agent doesn't silently read as already-bound under a + // different, independent one. Cloud devices (the else branch below) aren't + // scoped this way: they're never recalled from a stale local cache across a + // session boundary, since parse_user_print_info() always overwrites their code + // fresh from the cloud API's current response, so there's no cross-agent leakage + // risk to guard against there. + if (!code.empty()) { + DeviceManager::update_local_machine(*this); + } else { + // Only patch an existing record's code - don't persist a brand-new + // never-bound entry just because set_access_code("") was called on it. + const auto& machines = config->get_local_machines(); + auto it = machines.find(get_dev_id()); + if (it != machines.end()) { + BBLocalMachine local_machine = it->second; + local_machine.access_code = ""; + config->update_local_machine(local_machine); + } + // Also clear the pre-scoping flat legacy key when unbinding under BBL, so an + // old BBL-era code can't silently "re-bind" this device again via + // get_access_code_with_legacy_fallback()'s legacy fallback. + if (printer_agent_id == BBL_PRINTER_AGENT_ID || printer_agent_id.empty()) { + config->erase("access_code", get_dev_id()); + config->erase("user_access_code", get_dev_id()); + } + } } else { - GUI::wxGetApp().app_config->erase("access_code", get_dev_id()); + if (!code.empty()) + config->set_str("access_code", get_dev_id(), code); + else + config->erase("access_code", get_dev_id()); } } } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 33635fbe6e..914c8f7868 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -229,6 +229,16 @@ public: //PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN; std::string printer_type; /* model_id */ + + // id of the IPrinterAgent that was used to discover or bind this device (IPrinterAgent::get_agent_info().id, + // e.g. "bbl"), stamped at creation time — not derived from get_agent(), since m_agent is a single + // process-wide NetworkAgent shared by every MachineObject and gets repointed on agent swap + // (see DeviceManager::set_agent()), so it can't tell which agent originally found this device. + // We persist this as well so that when the printer agent is swapped, we don't show unrelated devices, + // e.g. if the current printer agent is elegoo, we shouldn't show printers connected by BBL printer agent + // under local machines. + std::string printer_agent_id; + std::string get_show_printer_type() const; PrinterSeries get_printer_series() const; PrinterArch get_printer_arch() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index db51bd9d8e..5faf112db3 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3937,7 +3937,13 @@ void GUI_App::set_live_printer_agent(std::shared_ptr agent) m_agent->set_user_selected_machine(""); // note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer) dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS - dev->clear_other_devices(); // why: drop stale LAN discoveries; keep My Devices + // why: drop stale LAN discoveries; keep My Devices, but only those belonging to the + // agent we're about to swap to, so a device stamped by the outgoing agent doesn't + // linger hidden - the new agent's start_discovery re-inserts and re-stamps it fresh. + // agent is null when clearing the live agent entirely (e.g. plugin unload); there's no + // target to filter against then, so fall back to the original "keep all My Devices" + // behavior rather than guessing. + dev->clear_other_devices(agent ? agent->get_agent_info().id : std::string()); } m_agent->set_printer_agent(agent); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 1ab78fcc11..23f13d1497 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3913,7 +3913,8 @@ _collect_sorted_machines(Slic3r::DeviceManager* dev_manager, }; // collect from user machine list - const auto& user_machine_list = dev_manager->get_my_machine_list();// user machine list + const std::string agent_id = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_agent"); + const auto& user_machine_list = dev_manager->get_my_machine_list(agent_id);// user machine list for (const auto& elem : user_machine_list) { MachineObject* mobj = elem.second; diff --git a/src/slic3r/GUI/SelectMachinePop.cpp b/src/slic3r/GUI/SelectMachinePop.cpp index 96324fb4d8..df0a566917 100644 --- a/src/slic3r/GUI/SelectMachinePop.cpp +++ b/src/slic3r/GUI/SelectMachinePop.cpp @@ -501,6 +501,7 @@ void SelectMachinePopup::update_other_devices() DeviceManager* dev = wxGetApp().getDeviceManager(); if (!dev) return; m_free_machine_list = dev->get_local_machinelist(); + const std::string current_agent_id = dev->get_current_printer_agent_id(); BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices start"; this->Freeze(); @@ -512,6 +513,10 @@ void SelectMachinePopup::update_other_devices() /* do not show printer bind state is empty */ if (!mobj->is_avaliable()) continue; + /* do not show devices discovered/bound by a different printer agent */ + if (mobj->printer_agent_id != current_agent_id) + continue; + if (!wxGetApp().is_user_login(wxGetApp().get_printer_cloud_provider()) && !mobj->is_lan_mode_printer()) continue; @@ -634,7 +639,7 @@ void SelectMachinePopup::update_user_devices() } m_bind_machine_list.clear(); - m_bind_machine_list = dev->get_my_machine_list(); + m_bind_machine_list = dev->get_my_machine_list(dev->get_current_printer_agent_id()); //sort list std::vector> user_machine_list;