From 9d9bb9cdbd647afc2501d0529c2a0d7700fb666b Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 17 Jul 2026 16:25:10 +0800 Subject: [PATCH] Install the OTA plugin update immediately and hot-reload it --- src/slic3r/GUI/GUI_App.cpp | 88 ++++++++++++++++++++++------------ src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/Plater.cpp | 18 ++++++- src/slic3r/GUI/ReleaseNote.cpp | 2 +- 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 36e9bb2a2f..bccb9f073e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3291,6 +3291,22 @@ void GUI_App::copy_network_if_available() if (app_config->get("update_network_plugin") != "true") return; + bool had_cache = false; + bool installed = install_network_plugin_from_ota(had_cache); + // Success consumes the cache and a missing cache leaves nothing to do; only a + // failed copy keeps the flag so the install is retried on the next launch. + if (installed || !had_cache) + app_config->set("update_network_plugin", "false"); +} + +// Installs the OTA-downloaded plug-in files from ota/plugins into the plugins folder +// (network library under its versioned name, and the configured version updated to +// match). Returns true when everything was installed; had_cache reports whether a +// usable download was present at all. +bool GUI_App::install_network_plugin_from_ota(bool& had_cache) +{ + had_cache = false; + std::string data_dir_str = data_dir(); boost::filesystem::path data_dir_path(data_dir_str); auto plugin_folder = data_dir_path / "plugins"; @@ -3312,10 +3328,10 @@ void GUI_App::copy_network_if_available() } if (cached_version.empty()) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no version found in changelog, aborting copy"; - app_config->set("update_network_plugin", "false"); - return; + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no version found in changelog, nothing to install"; + return false; } + had_cache = true; std::string network_library, player_library, live555_library, network_library_dst, player_library_dst, live555_library_dst; #if defined(_MSC_VER) || defined(_WIN32) @@ -3346,17 +3362,41 @@ void GUI_App::copy_network_if_available() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": create directory " << plugin_folder.string(); boost::filesystem::create_directory(plugin_folder); } - std::string error_message; - if (boost::filesystem::exists(network_library)) { - CopyFileResult cfr = copy_file(network_library, network_library_dst, error_message, false); - if (cfr != CopyFileResult::SUCCESS) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": Copying failed(" << cfr << "): " << error_message; - return; - } + // Replace a destination even while the running process still maps it: an in-use + // file cannot be deleted or overwritten on Windows, but it can be renamed aside; + // the stale ".old" copy is swept on the next launch (see on_init_network). + auto install_file = [](const std::string& src, const std::string& dst) -> bool { + boost::system::error_code ec; + if (boost::filesystem::exists(dst, ec)) { + boost::filesystem::remove(dst, ec); + if (ec) { + boost::filesystem::path aside(dst); + aside += ".old"; + boost::system::error_code ec2; + boost::filesystem::remove(aside, ec2); + boost::filesystem::rename(dst, aside, ec2); + if (ec2) { + BOOST_LOG_TRIVIAL(error) << "install_network_plugin_from_ota: cannot replace in-use file " << dst << ": " << ec2.message(); + return false; + } + } + } + std::string error_message; + CopyFileResult cfr = copy_file(src, dst, error_message, false); + if (cfr != CopyFileResult::SUCCESS) { + BOOST_LOG_TRIVIAL(error) << "install_network_plugin_from_ota: copying " << src << " failed(" << cfr << "): " << error_message; + return false; + } static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; - fs::permissions(network_library_dst, perms); - fs::remove(network_library); + fs::permissions(dst, perms); + boost::filesystem::remove(src, ec); + return true; + }; + + if (boost::filesystem::exists(network_library)) { + if (!install_file(network_library, network_library_dst)) + return false; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Copying network library from " << network_library << " to " << network_library_dst << " successfully."; app_config->set_network_plugin_version(cached_version); @@ -3364,28 +3404,14 @@ void GUI_App::copy_network_if_available() } if (boost::filesystem::exists(player_library)) { - CopyFileResult cfr = copy_file(player_library, player_library_dst, error_message, false); - if (cfr != CopyFileResult::SUCCESS) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": Copying failed(" << cfr << "): " << error_message; - return; - } - - static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; - fs::permissions(player_library_dst, perms); - fs::remove(player_library); + if (!install_file(player_library, player_library_dst)) + return false; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Copying player library from " << player_library << " to " << player_library_dst << " successfully."; } if (boost::filesystem::exists(live555_library)) { - CopyFileResult cfr = copy_file(live555_library, live555_library_dst, error_message, false); - if (cfr != CopyFileResult::SUCCESS) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": Copying failed(" << cfr << "): " << error_message; - return; - } - - static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; - fs::permissions(live555_library_dst, perms); - fs::remove(live555_library); + if (!install_file(live555_library, live555_library_dst)) + return false; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Copying live555 library from " << live555_library << " to " << live555_library_dst << " successfully."; } // All cached files consumed - drop the whole ota/plugins cache folder. @@ -3395,7 +3421,7 @@ void GUI_App::copy_network_if_available() } catch (...) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to remove the plugin cache folder " << cache_folder.string(); } - app_config->set("update_network_plugin", "false"); + return true; } bool GUI_App::on_init_network(bool try_backup) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 2260417649..e610d28828 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -751,6 +751,7 @@ public: void show_network_plugin_download_dialog(bool is_update = false); bool hot_reload_network_plugin(); + bool install_network_plugin_from_ota(bool& had_cache); std::string get_latest_network_version() const; bool has_network_update_available() const; // Orca: return the client version to report to Bambu servers. Pinned to diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 45c3098d36..af05759bd9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -11355,7 +11355,23 @@ void Plater::priv::update_plugin_when_launch(wxCommandEvent &event) if (!app_config) return; if (result == wxID_OK) { - app_config->set("update_network_plugin", "true"); + // Apply the downloaded update right away and hot-reload the plug-in, the same + // way a manual version switch in Preferences behaves. When a file is still in + // use and cannot be replaced, fall back to installing on the next launch. + bool had_cache = false; + if (wxGetApp().install_network_plugin_from_ota(had_cache)) { + notification_manager->close_notification_of_type(NotificationType::BBLPluginUpdateAvailable); + app_config->set("update_network_plugin", "false"); + if (wxGetApp().hot_reload_network_plugin()) { + MessageDialog dlg_ok(wxGetApp().mainframe, _L("Network plug-in switched successfully."), _L("Success"), wxOK | wxICON_INFORMATION); + dlg_ok.ShowModal(); + } else { + MessageDialog dlg_fail(wxGetApp().mainframe, _L("Failed to load network plug-in. Please restart the application."), _L("Restart Required"), wxOK | wxICON_WARNING); + dlg_fail.ShowModal(); + } + } else { + app_config->set("update_network_plugin", had_cache ? "true" : "false"); + } } else if (result == wxID_NO) { app_config->set("update_network_plugin", "false"); diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index ef1a7ebe96..22f65f4a60 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -137,7 +137,7 @@ UpdatePluginDialog::UpdatePluginDialog(wxWindow* parent /*= nullptr*/) m_text_up_info->SetForegroundColour(wxColour(0x26, 0x2E, 0x30)); - operation_tips = new ::Label(this, Label::Body_12, _L("Click OK to update the Network plug-in the next time Orca Slicer launches."), LB_AUTO_WRAP); + operation_tips = new ::Label(this, Label::Body_12, _L("Click OK to update the Network plug-in now. If a file is in use, the update will be applied the next time Orca Slicer launches."), LB_AUTO_WRAP); operation_tips->SetMinSize(wxSize(FromDIP(260), -1)); operation_tips->SetMaxSize(wxSize(FromDIP(260), -1));