Fix the network plugin OTA update flow

This commit is contained in:
SoftFever
2026-07-17 14:23:39 +08:00
parent 1b722de6e7
commit 5808ae5ab0
3 changed files with 87 additions and 81 deletions

View File

@@ -1241,13 +1241,14 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
// get_url
std::string url = get_plugin_url(name, app_config->get_country_code());
std::string download_url;
std::string online_version;
Slic3r::Http http_url = Slic3r::Http::get(url);
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: check the plugin from " << url;
http_url.timeout_connect(TIMEOUT_CONNECT)
.timeout_max(TIMEOUT_RESPONSE)
.header("X-BBL-OS-Type", os_type)
.on_complete(
[&download_url](std::string body, unsigned status) {
[&download_url, &online_version](std::string body, unsigned status) {
try {
json j = json::parse(body);
std::string message = j["message"].get<std::string>();
@@ -1257,6 +1258,7 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
if (resource.is_array()) {
for (auto iter = resource.begin(); iter != resource.end(); iter++) {
Semver version;
std::string version_str;
std::string url;
std::string type;
std::string vendor;
@@ -1267,7 +1269,8 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: get version of settings's type, " << sub_iter.value();
}
else if (boost::iequals(sub_iter.key(), "version")) {
version = *(Semver::parse(sub_iter.value()));
version_str = sub_iter.value();
version = *(Semver::parse(version_str));
}
else if (boost::iequals(sub_iter.key(), "description")) {
description = sub_iter.value();
@@ -1278,6 +1281,7 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
}
BOOST_LOG_TRIVIAL(info) << "[download_plugin 1]: get type " << type << ", version " << version.to_string() << ", url " << url;
download_url = url;
online_version = version_str;
}
}
}
@@ -1367,6 +1371,26 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
result = -1;
});
http.perform_sync();
// The cloud endpoint serves the newest build of the requested series, which may be
// newer than the configured version. Adopt the actual downloaded version so that
// install_plugin() names the library after what it really contains - otherwise the
// post-load config sync (on_init_network) points at a file name that does not exist
// and the plugin is "lost" on the following launch. Legacy mode is left untouched:
// is_legacy_version() matches exactly and drives the legacy struct layout.
if (result >= 0 && name == "plugins" && !online_version.empty() && !use_legacy_network_plugin()) {
std::string configured = app_config->get_network_plugin_version();
if (configured.empty())
configured = get_latest_network_version();
if (configured != online_version
&& configured.size() >= 8 && online_version.size() >= 8
&& configured.compare(0, 8, online_version, 0, 8) == 0) {
BOOST_LOG_TRIVIAL(info) << "[download_plugin] server returned " << online_version
<< " for configured " << configured << ", adopting it";
app_config->set_network_plugin_version(online_version);
}
}
j["result"] = result < 0 ? "failed" : "success";
j["error_msg"] = err_msg;
return result;
@@ -3270,7 +3294,7 @@ void GUI_App::copy_network_if_available()
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
auto cache_folder = data_dir_path / "ota";
auto cache_folder = data_dir_path / "ota" / "plugins";
std::string changelog_file = cache_folder.string() + "/network_plugins.json";
std::string cached_version;
@@ -3364,8 +3388,13 @@ void GUI_App::copy_network_if_available()
fs::remove(live555_library);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Copying live555 library from " << live555_library << " to " << live555_library_dst << " successfully.";
}
if (boost::filesystem::exists(changelog_file))
fs::remove(changelog_file);
// All cached files consumed - drop the whole ota/plugins cache folder.
try {
if (boost::filesystem::exists(cache_folder))
fs::remove_all(cache_folder);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to remove the plugin cache folder " << cache_folder.string();
}
app_config->set("update_network_plugin", "false");
}

View File

@@ -202,34 +202,45 @@ void UpdatePluginDialog::update_info(std::string json_path)
wxString version;
wxString description;
// Parse defensively: a missing or malformed changelog must never leave the
// dialog blank, so fall back to a generic prompt instead of returning early.
try {
boost::nowide::ifstream ifs(json_path);
json j;
ifs >> j;
version_str = j["version"];
description_str = j["description"];
if (j.contains("version"))
version_str = j["version"];
if (j.contains("description"))
description_str = j["description"];
}
catch (nlohmann::detail::parse_error& err) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << json_path << " got a nlohmann::detail::parse_error, reason = " << err.what();
return;
catch (std::exception& err) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << json_path << " failed, reason = " << err.what();
}
version = from_u8(version_str);
description = from_u8(description_str);
m_text_up_info->SetLabel(wxString::Format(_L("A new Network plug-in (%s) is available. Do you want to install it?"), version));
if (version.IsEmpty())
m_text_up_info->SetLabel(_L("A new Network plug-in is available. Do you want to install it?"));
else
m_text_up_info->SetLabel(wxString::Format(_L("A new Network plug-in (%s) is available. Do you want to install it?"), version));
m_text_up_info->SetMinSize(wxSize(FromDIP(260), -1));
m_text_up_info->SetMaxSize(wxSize(FromDIP(260), -1));
wxBoxSizer* sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
auto m_text_label = new ::Label(m_vebview_release_note, Label::Body_13, description, LB_AUTO_WRAP);
m_text_label->SetMinSize(wxSize(FromDIP(235), -1));
m_text_label->SetMaxSize(wxSize(FromDIP(235), -1));
sizer_text_release_note->Add(m_text_label, 0, wxALL, 5);
m_vebview_release_note->SetSizer(sizer_text_release_note);
m_vebview_release_note->Layout();
m_vebview_release_note->Fit();
if (description.IsEmpty()) {
m_vebview_release_note->Hide();
} else {
wxBoxSizer* sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
auto m_text_label = new ::Label(m_vebview_release_note, Label::Body_13, description, LB_AUTO_WRAP);
m_text_label->SetMinSize(wxSize(FromDIP(235), -1));
m_text_label->SetMaxSize(wxSize(FromDIP(235), -1));
sizer_text_release_note->Add(m_text_label, 0, wxALL, 5);
m_vebview_release_note->SetSizer(sizer_text_release_note);
m_vebview_release_note->Layout();
m_vebview_release_note->Fit();
}
wxGetApp().UpdateDlgDarkUI(this);
Layout();
Fit();

View File

@@ -782,9 +782,9 @@ void PresetUpdater::priv::sync_tooltip(std::string http_url, std::string languag
// return true means there are plugins files
bool PresetUpdater::priv::get_cached_plugins_version(std::string& cached_version, bool &force)
{
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto cache_folder = data_dir_path / "ota";
// The OTA plugin cache lives in its own ota/plugins subfolder; the update dialog
// (Plater::priv::update_plugin_when_launch) reads the changelog from the same place.
auto cache_folder = cache_path / "plugins";
std::string network_library, player_library, live555_library;
bool has_plugins = false;
@@ -838,6 +838,25 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_
}
std::string curr_version = GUI::wxGetApp().use_legacy_network_plugin() ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : get_latest_network_version();
std::string using_version = curr_version.substr(0, 9) + "00";
auto cache_plugin_folder = cache_path / "plugins";
// Orca: drop leftovers from the old flat ota/ cache layout (pre ota/plugins) so the
// stale files cannot linger forever after this layout migration.
{
#if defined(_MSC_VER) || defined(_WIN32)
const char* legacy_names[] = {"bambu_networking.dll", "BambuSource.dll", "live555.dll", "network_plugins.json"};
#elif defined(__WXMAC__)
const char* legacy_names[] = {"libbambu_networking.dylib", "libBambuSource.dylib", "liblive555.dylib", "network_plugins.json"};
#else
const char* legacy_names[] = {"libbambu_networking.so", "libBambuSource.so", "liblive555.so", "network_plugins.json"};
#endif
for (const char* name : legacy_names) {
boost::system::error_code ec;
auto legacy_file = cache_path / name;
if (boost::filesystem::exists(legacy_file, ec))
boost::filesystem::remove(legacy_file, ec);
}
}
std::string cached_version;
bool force_upgrade = false;
@@ -868,64 +887,11 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_
}
if (need_delete_cache) {
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto cache_folder = data_dir_path / "ota";
#if defined(_MSC_VER) || defined(_WIN32)
auto network_library = cache_folder / "bambu_networking.dll";
auto player_library = cache_folder / "BambuSource.dll";
auto live555_library = cache_folder / "live555.dll";
#elif defined(__WXMAC__)
auto network_library = cache_folder / "libbambu_networking.dylib";
auto player_library = cache_folder / "libBambuSource.dylib";
auto live555_library = cache_folder / "liblive555.dylib";
#else
auto network_library = cache_folder / "libbambu_networking.so";
auto player_library = cache_folder / "libBambuSource.so";
auto live555_library = cache_folder / "liblive555.so";
#endif
auto changelog_file = cache_folder / "network_plugins.json";
if (boost::filesystem::exists(network_library))
{
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the file "<<network_library.string();
try {
fs::remove(network_library);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the plugins file " << network_library.string();
}
}
if (boost::filesystem::exists(player_library))
{
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the file "<<player_library.string();
try {
fs::remove(player_library);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the plugins file " << player_library.string();
}
}
if (boost::filesystem::exists(live555_library))
{
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the file " << live555_library.string();
try {
fs::remove(live555_library);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the plugins file " << live555_library.string();
}
}
if (boost::filesystem::exists(changelog_file))
{
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the file "<<changelog_file.string();
try {
fs::remove(changelog_file);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the plugins file " << changelog_file.string();
}
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the plugins directory " << cache_plugin_folder.string();
try {
fs::remove_all(cache_plugin_folder);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the plugins directory " << cache_plugin_folder.string();
}
}
}
@@ -943,7 +909,7 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_
try {
std::map<std::string, Resource> resources
{
{"slicer/plugins/cloud", { using_version, "", "", false, cache_path.string(), {"plugins"}}}
{"slicer/plugins/cloud", { using_version, "", "", false, cache_plugin_folder.string()}}
};
sync_resources(http_url, resources, true, plugin_version, "network_plugins.json");
}