Allow selecting specific network plugin versions

This commit is contained in:
Maciej Wilczyński 2025-12-14 09:30:11 +01:00
parent 59ad126b48
commit a4d4bfff27
No known key found for this signature in database
GPG key ID: F0883103CBAC95DB
28 changed files with 1388 additions and 77 deletions

View file

@ -1,3 +1,7 @@
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "4.0")
set(CMAKE_POLICY_VERSION_MINIMUM 3.5 CACHE STRING "" FORCE)
endif()
cmake_minimum_required(VERSION 3.13)
# Verify that your CMake version is exactly 3.5 series or higher on windows
@ -571,6 +575,7 @@ endif()
if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()
set(Boost_NO_SYSTEM_PATHS TRUE)
find_package(Boost 1.83.0 REQUIRED COMPONENTS system filesystem thread log log_setup locale regex chrono atomic date_time iostreams program_options nowide)
add_library(boost_libs INTERFACE)
@ -688,6 +693,10 @@ find_package(PNG REQUIRED)
set(OpenGL_GL_PREFERENCE "LEGACY")
find_package(OpenGL REQUIRED)
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(OPENGL_LIBRARIES "-framework OpenGL" CACHE STRING "OpenGL framework" FORCE)
endif()
set(GLEW_ROOT "${CMAKE_PREFIX_PATH}")
message("GLEW_ROOT: ${GLEW_ROOT}")
# Find glew or use bundled version

View file

@ -3,7 +3,7 @@
set -e
set -o pipefail
while getopts ":dpa:snt:xbc:1h" opt; do
while getopts ":dpa:snt:xbc:1Th" opt; do
case "${opt}" in
d )
export BUILD_TARGET="deps"
@ -37,6 +37,9 @@ while getopts ":dpa:snt:xbc:1h" opt; do
1 )
export CMAKE_BUILD_PARALLEL_LEVEL=1
;;
T )
export BUILD_TESTS="1"
;;
h ) echo "Usage: ./build_release_macos.sh [-d]"
echo " -d: Build deps only"
echo " -a: Set ARCHITECTURE (arm64 or x86_64 or universal)"
@ -47,6 +50,7 @@ while getopts ":dpa:snt:xbc:1h" opt; do
echo " -b: Build without reconfiguring CMake"
echo " -c: Set CMake build configuration, default is Release"
echo " -1: Use single job for building"
echo " -T: Build and run tests"
exit 0
;;
* )
@ -85,6 +89,15 @@ if [ -z "$OSX_DEPLOYMENT_TARGET" ]; then
export OSX_DEPLOYMENT_TARGET="11.3"
fi
CMAKE_VERSION=$(cmake --version | head -1 | sed 's/[^0-9]*\([0-9]*\).*/\1/')
if [ "$CMAKE_VERSION" -ge 4 ] 2>/dev/null; then
export CMAKE_POLICY_VERSION_MINIMUM=3.5
export CMAKE_POLICY_COMPAT="-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
echo "Detected CMake 4.x, adding compatibility flag (env + cmake arg)"
else
export CMAKE_POLICY_COMPAT=""
fi
echo "Build params:"
echo " - ARCH: $ARCH"
echo " - BUILD_CONFIG: $BUILD_CONFIG"
@ -133,7 +146,8 @@ function build_deps() {
-G "${DEPS_CMAKE_GENERATOR}" \
-DCMAKE_BUILD_TYPE="$BUILD_CONFIG" \
-DCMAKE_OSX_ARCHITECTURES:STRING="${_ARCH}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}"
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}" \
${CMAKE_POLICY_COMPAT}
fi
cmake --build . --config "$BUILD_CONFIG" --target deps
)
@ -170,13 +184,24 @@ function build_slicer() {
-G "${SLICER_CMAKE_GENERATOR}" \
-DORCA_TOOLS=ON \
${ORCA_UPDATER_SIG_KEY:+-DORCA_UPDATER_SIG_KEY="$ORCA_UPDATER_SIG_KEY"} \
${BUILD_TESTS:+-DBUILD_TESTS=ON} \
-DCMAKE_BUILD_TYPE="$BUILD_CONFIG" \
-DCMAKE_OSX_ARCHITECTURES="${_ARCH}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}"
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}" \
${CMAKE_POLICY_COMPAT}
fi
cmake --build . --config "$BUILD_CONFIG" --target "$SLICER_BUILD_TARGET"
)
if [ "1." == "$BUILD_TESTS". ]; then
echo "Running tests for $_ARCH..."
(
set -x
cd "$PROJECT_BUILD_DIR"
ctest --build-config "$BUILD_CONFIG" --output-on-failure
)
fi
echo "Verify localization with gettext..."
(
cd "$PROJECT_DIR"

View file

@ -223,8 +223,13 @@ if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS)
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
if(APPLE)
set_target_properties(GLEW::glew
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set_target_properties(GLEW::glew
PROPERTIES INTERFACE_LINK_LIBRARIES "-framework OpenGL")
else()
set_target_properties(GLEW::glew
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
endif()
if(GLEW_SHARED_LIBRARY_RELEASE)
@ -258,8 +263,13 @@ elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS)
set_target_properties(GLEW::glew_s PROPERTIES INTERFACE_COMPILE_DEFINITIONS GLEW_STATIC)
if(APPLE)
set_target_properties(GLEW::glew_s
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set_target_properties(GLEW::glew_s
PROPERTIES INTERFACE_LINK_LIBRARIES "-framework OpenGL")
else()
set_target_properties(GLEW::glew_s
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
endif()
if(GLEW_STATIC_LIBRARY_RELEASE)
@ -292,8 +302,13 @@ if(NOT TARGET GLEW::GLEW)
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
if(APPLE)
set_target_properties(GLEW::GLEW
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set_target_properties(GLEW::GLEW
PROPERTIES INTERFACE_LINK_LIBRARIES "-framework OpenGL")
else()
set_target_properties(GLEW::GLEW
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
endif()
if(TARGET GLEW::glew)

6
deps/CMakeLists.txt vendored
View file

@ -1,3 +1,7 @@
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "4.0")
set(CMAKE_POLICY_VERSION_MINIMUM 3.5 CACHE STRING "" FORCE)
endif()
#
# This CMake project downloads, configures and builds OrcaSlicer dependencies on Unix and Windows.
#
@ -177,6 +181,7 @@ if (NOT IS_CROSS_COMPILE OR NOT APPLE)
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
${_gen}
CMAKE_ARGS
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
-DCMAKE_INSTALL_PREFIX:STRING=${DESTDIR}
-DCMAKE_MODULE_PATH:STRING=${PROJECT_SOURCE_DIR}/../cmake/modules
-DCMAKE_PREFIX_PATH:STRING=${DESTDIR}
@ -221,6 +226,7 @@ else()
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
${_gen}
CMAKE_ARGS
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
-DCMAKE_INSTALL_PREFIX:STRING=${DESTDIR}
-DCMAKE_PREFIX_PATH:STRING=${DESTDIR}
-DBUILD_SHARED_LIBS:BOOL=OFF

View file

@ -24,6 +24,14 @@ else ()
set(_wx_edge "-DwxUSE_WEBVIEW_EDGE=OFF")
endif ()
set(_wx_opengl_override "")
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(_wx_opengl_override
-DOPENGL_gl_LIBRARY="-framework OpenGL"
-DOPENGL_glu_LIBRARY="-framework OpenGL"
)
endif()
orcaslicer_add_cmake_project(
wxWidgets
GIT_REPOSITORY "https://github.com/SoftFever/Orca-deps-wxWidgets"
@ -31,6 +39,7 @@ orcaslicer_add_cmake_project(
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} ${JPEG_PKG}
${_wx_flatpak_patch}
CMAKE_ARGS
${_wx_opengl_override}
-DwxBUILD_PRECOMP=ON
${_wx_toolkit}
"-DCMAKE_DEBUG_POSTFIX:STRING=${_wx_debug_postfix}"

View file

@ -12,6 +12,7 @@
#include <utility>
#include <vector>
#include <stdexcept>
#include <sstream>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
@ -1427,6 +1428,82 @@ std::string AppConfig::get_nozzle_volume_types_from_config(const std::string& pr
return nozzle_volume_types;
}
std::string AppConfig::get_network_plugin_version() const
{
return get(SETTING_NETWORK_PLUGIN_VERSION);
}
void AppConfig::set_network_plugin_version(const std::string& version)
{
set(SETTING_NETWORK_PLUGIN_VERSION, version);
}
std::vector<std::string> AppConfig::get_skipped_network_versions() const
{
std::vector<std::string> result;
std::string skipped = get(SETTING_NETWORK_PLUGIN_SKIPPED_VERSIONS);
if (skipped.empty())
return result;
std::stringstream ss(skipped);
std::string version;
while (std::getline(ss, version, ';')) {
if (!version.empty())
result.push_back(version);
}
return result;
}
void AppConfig::add_skipped_network_version(const std::string& version)
{
auto skipped = get_skipped_network_versions();
if (std::find(skipped.begin(), skipped.end(), version) == skipped.end()) {
skipped.push_back(version);
std::string joined;
for (size_t i = 0; i < skipped.size(); ++i) {
if (i > 0) joined += ";";
joined += skipped[i];
}
set(SETTING_NETWORK_PLUGIN_SKIPPED_VERSIONS, joined);
}
}
bool AppConfig::is_network_version_skipped(const std::string& version) const
{
auto skipped = get_skipped_network_versions();
return std::find(skipped.begin(), skipped.end(), version) != skipped.end();
}
void AppConfig::clear_skipped_network_versions()
{
set(SETTING_NETWORK_PLUGIN_SKIPPED_VERSIONS, "");
}
bool AppConfig::is_network_update_prompt_disabled() const
{
return get_bool(SETTING_NETWORK_PLUGIN_UPDATE_DISABLED);
}
void AppConfig::set_network_update_prompt_disabled(bool disabled)
{
set_bool(SETTING_NETWORK_PLUGIN_UPDATE_DISABLED, disabled);
}
bool AppConfig::should_remind_network_update_later() const
{
return get_bool(SETTING_NETWORK_PLUGIN_REMIND_LATER);
}
void AppConfig::set_remind_network_update_later(bool remind)
{
set_bool(SETTING_NETWORK_PLUGIN_REMIND_LATER, remind);
}
void AppConfig::clear_remind_network_update_later()
{
set_bool(SETTING_NETWORK_PLUGIN_REMIND_LATER, false);
}
void AppConfig::reset_selections()
{
auto it = m_storage.find("presets");

View file

@ -24,6 +24,11 @@ using namespace nlohmann;
#define OPTION_PROJECT_LOAD_BEHAVIOUR_ALWAYS_ASK "always_ask"
#define OPTION_PROJECT_LOAD_BEHAVIOUR_LOAD_GEOMETRY "load_geometry_only"
#define SETTING_NETWORK_PLUGIN_VERSION "network_plugin_version"
#define SETTING_NETWORK_PLUGIN_SKIPPED_VERSIONS "network_plugin_skipped_versions"
#define SETTING_NETWORK_PLUGIN_UPDATE_DISABLED "network_plugin_update_prompts_disabled"
#define SETTING_NETWORK_PLUGIN_REMIND_LATER "network_plugin_remind_later"
#define SUPPORT_DARK_MODE
//#define _MSW_DARK_MODE
@ -347,6 +352,21 @@ public:
static const std::string SECTION_MATERIALS;
static const std::string SECTION_EMBOSS_STYLE;
std::string get_network_plugin_version() const;
void set_network_plugin_version(const std::string& version);
std::vector<std::string> get_skipped_network_versions() const;
void add_skipped_network_version(const std::string& version);
bool is_network_version_skipped(const std::string& version) const;
void clear_skipped_network_versions();
bool is_network_update_prompt_disabled() const;
void set_network_update_prompt_disabled(bool disabled);
bool should_remind_network_update_later() const;
void set_remind_network_update_later(bool remind);
void clear_remind_network_update_later();
private:
template<typename T>
bool get_3dmouse_device_numeric_value(const std::string &device_name, const char *parameter_name, T &out) const

View file

@ -456,6 +456,8 @@ set(SLIC3R_GUI_SOURCES
GUI/UnsavedChangesDialog.hpp
GUI/UpdateDialogs.cpp
GUI/UpdateDialogs.hpp
GUI/NetworkPluginDialog.cpp
GUI/NetworkPluginDialog.hpp
GUI/UpgradePanel.cpp
GUI/UpgradePanel.hpp
GUI/UserManager.cpp
@ -703,7 +705,13 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
set(_opengl_link_lib "")
else()
set(_opengl_link_lib OpenGL::GL)
endif()
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW ${_opengl_link_lib} hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib)
@ -721,7 +729,11 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
${CURL_LIBRARIES}
)
elseif (APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} "-framework Security")
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} "-framework Security" "-framework OpenGL")
else()
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} "-framework Security")
endif()
endif()
if (SLIC3R_STATIC)

View file

@ -90,6 +90,25 @@ namespace Slic3r
userMachineList.clear();
}
void DeviceManager::set_agent(NetworkAgent* agent)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": updating agent for "
<< localMachineList.size() << " local and "
<< userMachineList.size() << " user machines";
m_agent = agent;
std::lock_guard<std::mutex> lock(listMutex);
for (auto& it : localMachineList) {
if (it.second) {
it.second->set_agent(agent);
}
}
for (auto& it : userMachineList) {
if (it.second) {
it.second->set_agent(agent);
}
}
}
void DeviceManager::EnableMultiMachine(bool enable)
{

View file

@ -40,7 +40,7 @@ public:
public:
NetworkAgent* get_agent() const { return m_agent; }
void set_agent(NetworkAgent* agent) { m_agent = agent; }
void set_agent(NetworkAgent* agent);
void start_refresher();
void stop_refresher();

View file

@ -135,6 +135,8 @@ public:
MachineObject(DeviceManager* manager, NetworkAgent* agent, std::string name, std::string id, std::string ip);
~MachineObject();
void set_agent(NetworkAgent* agent) { m_agent = agent; }
public:
enum ActiveState {
NotActive,

View file

@ -19,6 +19,7 @@
//#include "ConfigWizard.hpp"
#include "wxExtensions.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/MsgDialog.hpp"
#include "GUI_App.hpp"
#include "Jobs/BoostThreadWorker.hpp"
#include "Jobs/PlaterWorker.hpp"
@ -203,6 +204,16 @@ void DownloadProgressDialog::update_release_note(std::string release_note, std::
std::unique_ptr<UpgradeNetworkJob> DownloadProgressDialog::make_job() { return std::make_unique<UpgradeNetworkJob>(); }
void DownloadProgressDialog::on_finish() { wxGetApp().restart_networking(); }
void DownloadProgressDialog::on_finish()
{
if (wxGetApp().hot_reload_network_plugin()) {
return;
}
MessageDialog dlg(nullptr,
_L("The network plugin was installed but could not be loaded. Please restart the application."),
_L("Restart Required"), wxOK | wxICON_INFORMATION);
dlg.ShowModal();
}
}} // namespace Slic3r::GUI

View file

@ -42,6 +42,7 @@
#include <wx/menuitem.h>
#include <wx/filedlg.h>
#include <wx/progdlg.h>
#include <wx/busyinfo.h>
#include <wx/dir.h>
#include <wx/wupdlock.h>
#include <wx/filefn.h>
@ -98,6 +99,7 @@
#include "UnsavedChangesDialog.hpp"
#include "SavePresetDialog.hpp"
#include "PrintHostDialogs.hpp"
#include "NetworkPluginDialog.hpp"
#include "DesktopIntegrationDialog.hpp"
#include "SendSystemInfoDialog.hpp"
#include "ParamsDialog.hpp"
@ -959,15 +961,7 @@ void GUI_App::post_init()
m_show_gcode_window = app_config->get_bool("show_gcode_window");
if (m_networking_need_update) {
//updating networking
int ret = updating_bambu_networking();
if (!ret) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<<":networking plugin updated successfully";
//restart_networking();
}
else {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<<":networking plugin updated failed";
}
show_network_plugin_download_dialog(false);
}
// Start preset sync after project opened, otherwise we could have preset change during project opening which could cause crash
@ -1177,12 +1171,20 @@ std::string GUI_App::get_plugin_url(std::string name, std::string country_code)
{
std::string url = get_http_url(country_code);
std::string curr_version = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION;
std::string curr_version;
if (NetworkAgent::use_legacy_network) {
curr_version = BAMBU_NETWORK_AGENT_VERSION_LEGACY;
} else if (name == "plugins" && app_config) {
std::string user_version = app_config->get_network_plugin_version();
curr_version = user_version.empty() ? BBL::get_latest_network_version() : user_version;
} else {
curr_version = BBL::get_latest_network_version();
}
std::string using_version = curr_version.substr(0, 9) + "00";
if (name == "cameratools")
using_version = curr_version.substr(0, 6) + "00.00";
url += (boost::format("?slicer/%1%/cloud=%2%") % name % using_version).str();
//url += (boost::format("?slicer/plugins/cloud=%1%") % "01.01.00.00").str();
return url;
}
@ -1413,6 +1415,32 @@ int GUI_App::install_plugin(std::string name, std::string package_name, InstallP
return InstallStatusUnzipFailed;
}
boost::filesystem::path legacy_lib_path, legacy_lib_backup;
bool had_existing_legacy = false;
if (name == "plugins") {
#if defined(_MSC_VER) || defined(_WIN32)
legacy_lib_path = plugin_folder / (std::string(BAMBU_NETWORK_LIBRARY) + ".dll");
#elif defined(__WXMAC__)
legacy_lib_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".dylib");
#else
legacy_lib_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".so");
#endif
legacy_lib_backup = legacy_lib_path;
legacy_lib_backup += ".backup";
if (boost::filesystem::exists(legacy_lib_path)) {
had_existing_legacy = true;
boost::system::error_code ec;
boost::filesystem::rename(legacy_lib_path, legacy_lib_backup, ec);
if (ec) {
BOOST_LOG_TRIVIAL(warning) << "[install_plugin] failed to backup existing legacy library: " << ec.message();
had_existing_legacy = false;
} else {
BOOST_LOG_TRIVIAL(info) << "[install_plugin] backed up existing legacy library";
}
}
}
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
mz_zip_archive_file_stat stat;
BOOST_LOG_TRIVIAL(error) << boost::format("[install_plugin]: %1%, got %2% files")%__LINE__ %num_entries;
@ -1487,6 +1515,38 @@ int GUI_App::install_plugin(std::string name, std::string package_name, InstallP
}
close_zip_reader(&archive);
if (name == "plugins") {
std::string config_version = app_config->get_network_plugin_version();
if (!config_version.empty() && boost::filesystem::exists(legacy_lib_path)) {
#if defined(_MSC_VER) || defined(_WIN32)
auto versioned_lib = plugin_folder / (std::string(BAMBU_NETWORK_LIBRARY) + "_" + config_version + ".dll");
#elif defined(__WXMAC__)
auto versioned_lib = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + "_" + config_version + ".dylib");
#else
auto versioned_lib = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + "_" + config_version + ".so");
#endif
BOOST_LOG_TRIVIAL(info) << "[install_plugin] renaming newly extracted " << legacy_lib_path.string() << " to " << versioned_lib.string();
boost::system::error_code ec;
if (boost::filesystem::exists(versioned_lib)) {
boost::filesystem::remove(versioned_lib, ec);
}
boost::filesystem::rename(legacy_lib_path, versioned_lib, ec);
if (ec) {
BOOST_LOG_TRIVIAL(error) << "[install_plugin] failed to rename to versioned: " << ec.message();
}
}
if (had_existing_legacy && boost::filesystem::exists(legacy_lib_backup)) {
BOOST_LOG_TRIVIAL(info) << "[install_plugin] restoring backed up legacy library";
boost::system::error_code ec;
boost::filesystem::rename(legacy_lib_backup, legacy_lib_path, ec);
if (ec) {
BOOST_LOG_TRIVIAL(warning) << "[install_plugin] failed to restore legacy library backup: " << ec.message();
}
}
}
{
fs::path dir_path(plugin_folder);
if (fs::exists(dir_path) && fs::is_directory(dir_path)) {
@ -1519,6 +1579,8 @@ int GUI_App::install_plugin(std::string name, std::string package_name, InstallP
}
}
}
if (pro_fn)
pro_fn(InstallStatusInstallCompleted, 100, cancel);
if (name == "plugins")
@ -1572,6 +1634,167 @@ void GUI_App::restart_networking()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(" exit, m_agent=%1%")%m_agent;
}
bool GUI_App::hot_reload_network_plugin()
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": starting hot reload";
wxBusyCursor busy;
wxBusyInfo info(_L("Reloading network plugin..."), mainframe);
wxYield();
wxWindowDisabler disabler;
if (mainframe) {
int current_tab = mainframe->m_tabpanel->GetSelection();
if (current_tab == MainFrame::TabPosition::tpMonitor) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": navigating away from Monitor tab before unload";
mainframe->m_tabpanel->SetSelection(MainFrame::TabPosition::tp3DEditor);
}
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": stopping sync thread before unload";
if (m_user_sync_token) {
m_user_sync_token.reset();
}
if (m_sync_update_thread.joinable()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": waiting for sync thread to finish";
m_sync_update_thread.join();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": sync thread finished";
}
if (m_agent) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": clearing callbacks and stopping operations";
m_agent->set_on_ssdp_msg_fn(nullptr);
m_agent->set_on_user_login_fn(nullptr);
m_agent->set_on_printer_connected_fn(nullptr);
m_agent->set_on_server_connected_fn(nullptr);
m_agent->set_on_http_error_fn(nullptr);
m_agent->set_on_subscribe_failure_fn(nullptr);
m_agent->set_on_message_fn(nullptr);
m_agent->set_on_user_message_fn(nullptr);
m_agent->set_on_local_connect_fn(nullptr);
m_agent->set_on_local_message_fn(nullptr);
m_agent->set_queue_on_main_fn(nullptr);
m_agent->start_discovery(false, false);
m_agent->disconnect_printer();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": destroying network agent";
delete m_agent;
m_agent = nullptr;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (Slic3r::NetworkAgent::is_network_module_loaded()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": unloading old module";
int unload_result = Slic3r::NetworkAgent::unload_network_module();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": unload result = " << unload_result;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": calling restart_networking";
restart_networking();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": restart_networking returned";
std::string loaded_version = Slic3r::NetworkAgent::get_version();
bool success = m_agent != nullptr && !loaded_version.empty() && loaded_version != "00.00.00.00";
bool user_logged_in = m_agent && m_agent->is_user_login();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": after restart_networking, is_user_login = " << user_logged_in
<< ", m_agent = " << (m_agent ? "valid" : "null")
<< ", version = " << loaded_version;
if (success && m_agent && m_device_manager) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": connecting to cloud server";
m_agent->connect_server();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": re-subscribing to cloud printers";
m_device_manager->add_user_subscribe();
}
if (mainframe && mainframe->m_monitor) {
mainframe->m_monitor->update_network_version_footer();
mainframe->m_monitor->set_default();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": reset monitor panel";
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": hot reload " << (success ? "successful" : "failed");
return success;
}
std::string GUI_App::get_latest_network_version() const
{
return BBL::get_latest_network_version();
}
bool GUI_App::has_network_update_available() const
{
std::string current = Slic3r::NetworkAgent::get_version();
std::string latest = get_latest_network_version();
if (current.empty() || current == "00.00.00.00")
return false;
return current.substr(0, 8) != latest.substr(0, 8);
}
void GUI_App::show_network_plugin_download_dialog(bool is_update)
{
auto load_error = Slic3r::NetworkAgent::get_load_error();
NetworkPluginDownloadDialog::Mode mode;
if (load_error.has_error) {
mode = NetworkPluginDownloadDialog::Mode::CorruptedPlugin;
} else if (is_update) {
mode = NetworkPluginDownloadDialog::Mode::UpdateAvailable;
} else {
mode = NetworkPluginDownloadDialog::Mode::MissingPlugin;
}
std::string current_version = Slic3r::NetworkAgent::get_version();
NetworkPluginDownloadDialog dlg(mainframe, mode, current_version,
load_error.message, load_error.technical_details);
int result = dlg.ShowModal();
switch (result) {
case NetworkPluginDownloadDialog::RESULT_DOWNLOAD:
{
std::string selected = dlg.get_selected_version();
app_config->set_network_plugin_version(selected);
app_config->save();
DownloadProgressDialog download_dlg(_L("Downloading Network Plugin"));
download_dlg.ShowModal();
}
break;
case NetworkPluginDownloadDialog::RESULT_REMIND_LATER:
app_config->set_remind_network_update_later(true);
app_config->save();
break;
case NetworkPluginDownloadDialog::RESULT_SKIP_VERSION:
{
std::string latest = get_latest_network_version();
app_config->add_skipped_network_version(latest);
app_config->save();
}
break;
case NetworkPluginDownloadDialog::RESULT_DONT_ASK:
app_config->set_network_update_prompt_disabled(true);
app_config->save();
break;
case NetworkPluginDownloadDialog::RESULT_SKIP:
default:
break;
}
}
void GUI_App::remove_old_networking_plugins()
{
std::string data_dir_str = data_dir();
@ -1601,8 +1824,20 @@ bool GUI_App::check_networking_version()
if (!network_ver.empty()) {
BOOST_LOG_TRIVIAL(info) << "get_network_agent_version=" << network_ver;
}
std::string studio_ver = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION;
if (network_ver.length() >= 8) {
std::string studio_ver;
if (NetworkAgent::use_legacy_network) {
studio_ver = BAMBU_NETWORK_AGENT_VERSION_LEGACY;
} else if (app_config) {
std::string user_version = app_config->get_network_plugin_version();
studio_ver = user_version.empty() ? BBL::get_latest_network_version() : user_version;
} else {
studio_ver = BBL::get_latest_network_version();
}
BOOST_LOG_TRIVIAL(info) << "check_networking_version: network_ver=" << network_ver << ", expected=" << studio_ver;
if (network_ver.length() >= 8 && studio_ver.length() >= 8) {
if (network_ver.substr(0,8) == studio_ver.substr(0,8)) {
m_networking_compatible = true;
return true;
@ -2857,78 +3092,103 @@ void GUI_App::copy_network_if_available()
{
if (app_config->get("update_network_plugin") != "true")
return;
std::string network_library, player_library, live555_library, network_library_dst, player_library_dst, live555_library_dst;
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";
std::string changelog_file = cache_folder.string() + "/network_plugins.json";
std::string cached_version;
if (boost::filesystem::exists(changelog_file)) {
try {
boost::nowide::ifstream ifs(changelog_file);
json j;
ifs >> j;
if (j.contains("version"))
cached_version = j["version"];
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": cached_version = " << cached_version;
} catch (nlohmann::detail::parse_error& err) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << changelog_file << " failed: " << err.what();
}
}
if (cached_version.empty()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no version found in changelog, aborting copy";
app_config->set("update_network_plugin", "false");
return;
}
std::string network_library, player_library, live555_library, network_library_dst, player_library_dst, live555_library_dst;
#if defined(_MSC_VER) || defined(_WIN32)
network_library = cache_folder.string() + "/bambu_networking.dll";
player_library = cache_folder.string() + "/BambuSource.dll";
live555_library = cache_folder.string() + "/live555.dll";
network_library_dst = plugin_folder.string() + "/bambu_networking.dll";
player_library_dst = plugin_folder.string() + "/BambuSource.dll";
player_library = cache_folder.string() + "/BambuSource.dll";
live555_library = cache_folder.string() + "/live555.dll";
network_library_dst = plugin_folder.string() + "/" + std::string(BAMBU_NETWORK_LIBRARY) + "_" + cached_version + ".dll";
player_library_dst = plugin_folder.string() + "/BambuSource.dll";
live555_library_dst = plugin_folder.string() + "/live555.dll";
#elif defined(__WXMAC__)
network_library = cache_folder.string() + "/libbambu_networking.dylib";
player_library = cache_folder.string() + "/libBambuSource.dylib";
live555_library = cache_folder.string() + "/liblive555.dylib";
network_library_dst = plugin_folder.string() + "/libbambu_networking.dylib";
network_library_dst = plugin_folder.string() + "/lib" + std::string(BAMBU_NETWORK_LIBRARY) + "_" + cached_version + ".dylib";
player_library_dst = plugin_folder.string() + "/libBambuSource.dylib";
live555_library_dst = plugin_folder.string() + "/liblive555.dylib";
#else
network_library = cache_folder.string() + "/libbambu_networking.so";
player_library = cache_folder.string() + "/libBambuSource.so";
live555_library = cache_folder.string() + "/liblive555.so";
network_library_dst = plugin_folder.string() + "/libbambu_networking.so";
player_library_dst = plugin_folder.string() + "/libBambuSource.so";
player_library = cache_folder.string() + "/libBambuSource.so";
live555_library = cache_folder.string() + "/liblive555.so";
network_library_dst = plugin_folder.string() + "/lib" + std::string(BAMBU_NETWORK_LIBRARY) + "_" + cached_version + ".so";
player_library_dst = plugin_folder.string() + "/libBambuSource.so";
live555_library_dst = plugin_folder.string() + "/liblive555.so";
#endif
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": checking network_library " << network_library << ", player_library " << player_library;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": checking network_library " << network_library << ", player_library " << player_library;
if (!boost::filesystem::exists(plugin_folder)) {
BOOST_LOG_TRIVIAL(info)<< __FUNCTION__ << ": create directory "<<plugin_folder.string();
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;
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(network_library_dst, perms);
fs::remove(network_library);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": Copying network library from" << network_library << " to " << network_library_dst<<" successfully.";
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Copying network library from " << network_library << " to " << network_library_dst << " successfully.";
app_config->set(SETTING_NETWORK_PLUGIN_VERSION, cached_version);
app_config->save();
}
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;
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);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": Copying player library from" << player_library << " to " << player_library_dst<<" successfully.";
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;
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);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": Copying live555 library from" << live555_library << " to " << live555_library_dst<<" successfully.";
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);
@ -2939,13 +3199,39 @@ bool GUI_App::on_init_network(bool try_backup)
{
bool create_network_agent = false;
auto should_load_networking_plugin = app_config->get_bool("installed_networking");
std::string config_version = app_config->get_network_plugin_version();
if (should_load_networking_plugin && Slic3r::NetworkAgent::legacy_library_exists() && config_version.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": migration: legacy library found with no config version, removing and requesting download";
Slic3r::NetworkAgent::remove_legacy_library();
m_networking_need_update = true;
return false;
}
if(!should_load_networking_plugin) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Don't load plugin as installed_networking is false";
} else {
int load_agent_dll = Slic3r::NetworkAgent::initialize_network_module();
if (config_version.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": no version configured, need to download";
m_networking_need_update = true;
return false;
}
int load_agent_dll = Slic3r::NetworkAgent::initialize_network_module(false, config_version);
__retry:
if (!load_agent_dll) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, load dll ok";
std::string loaded_version = Slic3r::NetworkAgent::get_version();
if (app_config && !loaded_version.empty() && loaded_version != "00.00.00.00") {
std::string config_version = app_config->get_network_plugin_version();
if (config_version != loaded_version) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": syncing config version from " << config_version << " to loaded " << loaded_version;
app_config->set(SETTING_NETWORK_PLUGIN_VERSION, loaded_version);
app_config->save();
}
}
if (check_networking_version()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, compatibility version";
auto bambu_source = Slic3r::NetworkAgent::get_bambu_source_entry();
@ -2962,7 +3248,7 @@ __retry:
if (try_backup) {
int result = Slic3r::NetworkAgent::unload_network_module();
BOOST_LOG_TRIVIAL(info) << "on_init_network, version mismatch, unload_network_module, result = " << result;
load_agent_dll = Slic3r::NetworkAgent::initialize_network_module(true);
load_agent_dll = Slic3r::NetworkAgent::initialize_network_module(true, config_version);
try_backup = false;
goto __retry;
}
@ -3041,6 +3327,24 @@ __retry:
m_user_manager = new Slic3r::UserManager();
}
if (create_network_agent && m_networking_compatible && !NetworkAgent::use_legacy_network) {
app_config->clear_remind_network_update_later();
if (has_network_update_available()) {
std::string latest = get_latest_network_version();
bool should_prompt = !app_config->is_network_update_prompt_disabled()
&& !app_config->is_network_version_skipped(latest)
&& !app_config->should_remind_network_update_later();
if (should_prompt) {
CallAfter([this]() {
show_network_plugin_download_dialog(true);
});
}
}
}
return true;
}
@ -4880,6 +5184,17 @@ bool GUI_App::process_network_msg(std::string dev_id, std::string msg)
{
if (dev_id.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << msg;
if (msg == "unsigned_studio") {
BOOST_LOG_TRIVIAL(info) << "process_network_msg, unsigned_studio";
MessageDialog msg_dlg(nullptr,
_L("Bambu Lab has implemented a signature verification check in their network plugin that restricts "
"third-party software from communicating with your printer.\n\n"
"As a result, some printing functions are unavailable in OrcaSlicer."),
_L("Network Plugin Restriction"), wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
return true;
}
}
else if (msg == "device_cert_installed") {
BOOST_LOG_TRIVIAL(info) << "process_network_msg, device_cert_installed";

View file

@ -686,6 +686,11 @@ public:
void restart_networking();
void check_config_updates_from_updater() { check_updates(false); }
void show_network_plugin_download_dialog(bool is_update = false);
bool hot_reload_network_plugin();
std::string get_latest_network_version() const;
bool has_network_update_available() const;
private:
int updating_bambu_networking();
bool on_init_inner();
@ -712,6 +717,7 @@ private:
bool m_init_app_config_from_older { false };
bool m_datadir_redefined { false };
std::string m_older_data_dir_path;
bool m_unsigned_plugin_warning_shown { false };
boost::optional<Semver> m_last_config_version;
bool m_config_corrupted { false };
std::string m_open_method;

View file

@ -195,6 +195,11 @@ void MonitorPanel::init_tabpanel()
m_hms_panel = new HMSPanel(m_tabpanel);
m_tabpanel->AddPage(m_hms_panel, _L("Assistant(HMS)"), "", false);
std::string network_ver = Slic3r::NetworkAgent::get_version();
if (!network_ver.empty()) {
m_tabpanel->SetFooterText(wxString::Format("Network plugin v%s", network_ver));
}
m_initialized = true;
show_status((int)MonitorStatus::MONITOR_NO_PRINTER);
}
@ -407,6 +412,7 @@ bool MonitorPanel::Show(bool show)
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (show) {
start_update();
update_network_version_footer();
m_refresh_timer->Stop();
m_refresh_timer->SetOwner(this);
@ -517,5 +523,13 @@ void MonitorPanel::jump_to_LiveView()
m_status_info_panel->get_media_play_ctrl()->jump_to_play();
}
void MonitorPanel::update_network_version_footer()
{
std::string network_ver = Slic3r::NetworkAgent::get_version();
if (!network_ver.empty()) {
m_tabpanel->SetFooterText(wxString::Format("Network plugin v%s", network_ver));
}
}
} // GUI
} // Slic3r

View file

@ -157,6 +157,7 @@ public:
void jump_to_HMS();
void jump_to_LiveView();
void update_network_version_footer();
};

View file

@ -0,0 +1,371 @@
#include "NetworkPluginDialog.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "MsgDialog.hpp"
#include "Widgets/Label.hpp"
#include "BitmapCache.hpp"
#include "wxExtensions.hpp"
#include "slic3r/Utils/bambu_networking.hpp"
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/collpane.h>
namespace Slic3r {
namespace GUI {
NetworkPluginDownloadDialog::NetworkPluginDownloadDialog(wxWindow* parent, Mode mode,
const std::string& current_version,
const std::string& error_message,
const std::string& error_details)
: DPIDialog(parent, wxID_ANY, mode == Mode::UpdateAvailable ?
_L("Network Plugin Update Available") : _L("Bambu Network Plugin Required"),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
, m_mode(mode)
, m_error_message(error_message)
, m_error_details(error_details)
{
SetBackgroundColour(*wxWHITE);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
main_sizer->Add(m_line_top, 0, wxEXPAND, 0);
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
SetSizer(main_sizer);
if (mode == Mode::UpdateAvailable) {
create_update_available_ui(current_version);
} else {
create_missing_plugin_ui();
}
Layout();
Fit();
CentreOnParent();
wxGetApp().UpdateDlgDarkUI(this);
}
void NetworkPluginDownloadDialog::create_missing_plugin_ui()
{
wxBoxSizer* main_sizer = static_cast<wxBoxSizer*>(GetSizer());
auto* desc = new wxStaticText(this, wxID_ANY,
m_mode == Mode::CorruptedPlugin ?
_L("The Bambu Network Plugin is corrupted or incompatible. Please reinstall it.") :
_L("The Bambu Network Plugin is required for cloud features, printer discovery, and remote printing."));
desc->SetFont(::Label::Body_13);
desc->Wrap(FromDIP(400));
main_sizer->Add(desc, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(15));
if (!m_error_message.empty()) {
auto* error_label = new wxStaticText(this, wxID_ANY,
wxString::Format(_L("Error: %s"), wxString::FromUTF8(m_error_message)));
error_label->SetFont(::Label::Body_13);
error_label->SetForegroundColour(wxColour(208, 93, 93));
error_label->Wrap(FromDIP(400));
main_sizer->Add(error_label, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
if (!m_error_details.empty()) {
m_details_pane = new wxCollapsiblePane(this, wxID_ANY, _L("Show details"));
auto* pane = m_details_pane->GetPane();
auto* pane_sizer = new wxBoxSizer(wxVERTICAL);
auto* details_text = new wxStaticText(pane, wxID_ANY, wxString::FromUTF8(m_error_details));
details_text->SetFont(wxGetApp().code_font());
details_text->Wrap(FromDIP(380));
pane_sizer->Add(details_text, 0, wxALL, FromDIP(10));
pane->SetSizer(pane_sizer);
main_sizer->Add(m_details_pane, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
}
}
auto* version_label = new wxStaticText(this, wxID_ANY, _L("Version to install:"));
version_label->SetFont(::Label::Body_13);
main_sizer->Add(version_label, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5));
setup_version_selector();
main_sizer->Add(m_version_combo, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
auto* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->Add(0, 0, 1, wxEXPAND, 0);
StateColor btn_bg_green(
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor btn_bg_white(
std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
auto* btn_download = new Button(this, _L("Download and Install"));
btn_download->SetBackgroundColor(btn_bg_green);
btn_download->SetBorderColor(*wxWHITE);
btn_download->SetTextColor(*wxWHITE);
btn_download->SetFont(::Label::Body_12);
btn_download->SetMinSize(wxSize(FromDIP(120), FromDIP(24)));
btn_download->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_download, this);
btn_sizer->Add(btn_download, 0, wxRIGHT, FromDIP(10));
auto* btn_skip = new Button(this, _L("Skip for Now"));
btn_skip->SetBackgroundColor(btn_bg_white);
btn_skip->SetBorderColor(wxColour(38, 46, 48));
btn_skip->SetFont(::Label::Body_12);
btn_skip->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_skip->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_skip, this);
btn_sizer->Add(btn_skip, 0, wxRIGHT, FromDIP(10));
main_sizer->Add(btn_sizer, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20));
main_sizer->Add(0, 0, 0, wxBOTTOM, FromDIP(20));
}
void NetworkPluginDownloadDialog::create_update_available_ui(const std::string& current_version)
{
wxBoxSizer* main_sizer = static_cast<wxBoxSizer*>(GetSizer());
auto* desc = new wxStaticText(this, wxID_ANY,
_L("A new version of the Bambu Network Plugin is available."));
desc->SetFont(::Label::Body_13);
desc->Wrap(FromDIP(400));
main_sizer->Add(desc, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(15));
auto* version_text = new wxStaticText(this, wxID_ANY,
wxString::Format(_L("Current version: %s"), wxString::FromUTF8(current_version)));
version_text->SetFont(::Label::Body_13);
main_sizer->Add(version_text, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
auto* update_label = new wxStaticText(this, wxID_ANY, _L("Update to version:"));
update_label->SetFont(::Label::Body_13);
main_sizer->Add(update_label, 0, wxLEFT | wxRIGHT, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5));
setup_version_selector();
main_sizer->Add(m_version_combo, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(25));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
auto* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->Add(0, 0, 1, wxEXPAND, 0);
StateColor btn_bg_green(
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor btn_bg_white(
std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
auto* btn_download = new Button(this, _L("Update Now"));
btn_download->SetBackgroundColor(btn_bg_green);
btn_download->SetBorderColor(*wxWHITE);
btn_download->SetTextColor(*wxWHITE);
btn_download->SetFont(::Label::Body_12);
btn_download->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_download->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_download, this);
btn_sizer->Add(btn_download, 0, wxRIGHT, FromDIP(10));
auto* btn_remind = new Button(this, _L("Remind Later"));
btn_remind->SetBackgroundColor(btn_bg_white);
btn_remind->SetBorderColor(wxColour(38, 46, 48));
btn_remind->SetFont(::Label::Body_12);
btn_remind->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_remind->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_remind_later, this);
btn_sizer->Add(btn_remind, 0, wxRIGHT, FromDIP(10));
auto* btn_skip = new Button(this, _L("Skip Version"));
btn_skip->SetBackgroundColor(btn_bg_white);
btn_skip->SetBorderColor(wxColour(38, 46, 48));
btn_skip->SetFont(::Label::Body_12);
btn_skip->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_skip->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_skip_version, this);
btn_sizer->Add(btn_skip, 0, wxRIGHT, FromDIP(10));
auto* btn_dont_ask = new Button(this, _L("Don't Ask Again"));
btn_dont_ask->SetBackgroundColor(btn_bg_white);
btn_dont_ask->SetBorderColor(wxColour(38, 46, 48));
btn_dont_ask->SetFont(::Label::Body_12);
btn_dont_ask->SetMinSize(wxSize(FromDIP(110), FromDIP(24)));
btn_dont_ask->Bind(wxEVT_BUTTON, &NetworkPluginDownloadDialog::on_dont_ask, this);
btn_sizer->Add(btn_dont_ask, 0, wxRIGHT, FromDIP(10));
main_sizer->Add(btn_sizer, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20));
main_sizer->Add(0, 0, 0, wxBOTTOM, FromDIP(20));
}
void NetworkPluginDownloadDialog::setup_version_selector()
{
m_version_combo = new ComboBox(this, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxSize(FromDIP(380), FromDIP(28)), 0, nullptr, wxCB_READONLY);
m_version_combo->SetFont(::Label::Body_13);
for (size_t i = 0; i < BBL::AVAILABLE_NETWORK_VERSIONS_COUNT; ++i) {
const auto& ver = BBL::AVAILABLE_NETWORK_VERSIONS[i];
wxString label = wxString::FromUTF8(ver.display_name);
if (ver.is_latest) {
label += wxString(" ") + _L("(Latest)");
}
m_version_combo->Append(label);
}
m_version_combo->SetSelection(0);
}
std::string NetworkPluginDownloadDialog::get_selected_version() const
{
if (!m_version_combo) {
return "";
}
int selection = m_version_combo->GetSelection();
if (selection < 0 || selection >= static_cast<int>(BBL::AVAILABLE_NETWORK_VERSIONS_COUNT)) {
return "";
}
return BBL::AVAILABLE_NETWORK_VERSIONS[selection].version;
}
void NetworkPluginDownloadDialog::on_download(wxCommandEvent& evt)
{
int selection = m_version_combo ? m_version_combo->GetSelection() : 0;
if (selection >= 0 && selection < static_cast<int>(BBL::AVAILABLE_NETWORK_VERSIONS_COUNT)) {
const char* warning = BBL::AVAILABLE_NETWORK_VERSIONS[selection].warning;
if (warning) {
MessageDialog warn_dlg(this, wxString::FromUTF8(warning), _L("Warning"), wxOK | wxCANCEL | wxICON_WARNING);
if (warn_dlg.ShowModal() != wxID_OK) {
return;
}
}
}
EndModal(RESULT_DOWNLOAD);
}
void NetworkPluginDownloadDialog::on_skip(wxCommandEvent& evt)
{
EndModal(RESULT_SKIP);
}
void NetworkPluginDownloadDialog::on_remind_later(wxCommandEvent& evt)
{
EndModal(RESULT_REMIND_LATER);
}
void NetworkPluginDownloadDialog::on_skip_version(wxCommandEvent& evt)
{
EndModal(RESULT_SKIP_VERSION);
}
void NetworkPluginDownloadDialog::on_dont_ask(wxCommandEvent& evt)
{
EndModal(RESULT_DONT_ASK);
}
void NetworkPluginDownloadDialog::on_dpi_changed(const wxRect& suggested_rect)
{
Layout();
Fit();
}
NetworkPluginRestartDialog::NetworkPluginRestartDialog(wxWindow* parent)
: DPIDialog(parent, wxID_ANY, _L("Restart Required"),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
{
SetBackgroundColour(*wxWHITE);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
main_sizer->Add(m_line_top, 0, wxEXPAND, 0);
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
auto* icon_sizer = new wxBoxSizer(wxHORIZONTAL);
auto* icon_bitmap = new wxStaticBitmap(this, wxID_ANY,
create_scaled_bitmap("info", nullptr, 64));
icon_sizer->Add(icon_bitmap, 0, wxALL, FromDIP(10));
auto* text_sizer = new wxBoxSizer(wxVERTICAL);
auto* desc = new wxStaticText(this, wxID_ANY,
_L("The Bambu Network Plugin has been installed successfully."));
desc->SetFont(::Label::Body_14);
desc->Wrap(FromDIP(350));
text_sizer->Add(desc, 0, wxTOP, FromDIP(10));
text_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
auto* restart_msg = new wxStaticText(this, wxID_ANY,
_L("A restart is required to load the new plugin. Would you like to restart now?"));
restart_msg->SetFont(::Label::Body_13);
restart_msg->Wrap(FromDIP(350));
text_sizer->Add(restart_msg, 0, wxBOTTOM, FromDIP(10));
icon_sizer->Add(text_sizer, 1, wxEXPAND | wxRIGHT, FromDIP(20));
main_sizer->Add(icon_sizer, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(15));
main_sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
auto* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->Add(0, 0, 1, wxEXPAND, 0);
StateColor btn_bg_green(
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor btn_bg_white(
std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
auto* btn_restart = new Button(this, _L("Restart Now"));
btn_restart->SetBackgroundColor(btn_bg_green);
btn_restart->SetBorderColor(*wxWHITE);
btn_restart->SetTextColor(*wxWHITE);
btn_restart->SetFont(::Label::Body_12);
btn_restart->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_restart->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
m_restart_now = true;
EndModal(wxID_OK);
});
btn_sizer->Add(btn_restart, 0, wxRIGHT, FromDIP(10));
auto* btn_later = new Button(this, _L("Restart Later"));
btn_later->SetBackgroundColor(btn_bg_white);
btn_later->SetBorderColor(wxColour(38, 46, 48));
btn_later->SetFont(::Label::Body_12);
btn_later->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
btn_later->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
m_restart_now = false;
EndModal(wxID_CANCEL);
});
btn_sizer->Add(btn_later, 0, wxRIGHT, FromDIP(10));
main_sizer->Add(btn_sizer, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20));
main_sizer->Add(0, 0, 0, wxBOTTOM, FromDIP(20));
SetSizer(main_sizer);
Layout();
Fit();
CentreOnParent();
wxGetApp().UpdateDlgDarkUI(this);
}
void NetworkPluginRestartDialog::on_dpi_changed(const wxRect& suggested_rect)
{
Layout();
Fit();
}
}
}

View file

@ -0,0 +1,74 @@
#ifndef slic3r_GUI_NetworkPluginDialog_hpp_
#define slic3r_GUI_NetworkPluginDialog_hpp_
#include "GUI_Utils.hpp"
#include "MsgDialog.hpp"
#include "Widgets/ComboBox.hpp"
#include "Widgets/Button.hpp"
#include <wx/collpane.h>
namespace Slic3r {
namespace GUI {
class NetworkPluginDownloadDialog : public DPIDialog
{
public:
enum class Mode {
MissingPlugin,
UpdateAvailable,
CorruptedPlugin
};
NetworkPluginDownloadDialog(wxWindow* parent, Mode mode,
const std::string& current_version = "",
const std::string& error_message = "",
const std::string& error_details = "");
std::string get_selected_version() const;
enum ResultCode {
RESULT_DOWNLOAD = wxID_OK,
RESULT_SKIP = wxID_CANCEL,
RESULT_REMIND_LATER = wxID_APPLY,
RESULT_SKIP_VERSION = wxID_IGNORE,
RESULT_DONT_ASK = wxID_ABORT
};
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
private:
void create_missing_plugin_ui();
void create_update_available_ui(const std::string& current_version);
void setup_version_selector();
void on_download(wxCommandEvent& evt);
void on_skip(wxCommandEvent& evt);
void on_remind_later(wxCommandEvent& evt);
void on_skip_version(wxCommandEvent& evt);
void on_dont_ask(wxCommandEvent& evt);
Mode m_mode;
ComboBox* m_version_combo{nullptr};
wxCollapsiblePane* m_details_pane{nullptr};
std::string m_error_message;
std::string m_error_details;
};
class NetworkPluginRestartDialog : public DPIDialog
{
public:
NetworkPluginRestartDialog(wxWindow* parent);
bool should_restart_now() const { return m_restart_now; }
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
private:
bool m_restart_now{false};
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GUI_NetworkPluginDialog_hpp_

View file

@ -14,6 +14,8 @@
#include "NetworkTestDialog.hpp"
#include "Widgets/StaticLine.hpp"
#include "Widgets/RadioGroup.hpp"
#include "slic3r/Utils/bambu_networking.hpp"
#include "DownloadProgressDialog.hpp"
#ifdef __WINDOWS__
#ifdef _MSW_DARK_MODE
@ -842,7 +844,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
if (param == "enable_high_low_temp_mixed_printing") {
if (checkbox->GetValue()) {
const wxString warning_title = _L("Bed Temperature Difference Warning");
const wxString warning_message =
const wxString warning_message =
_L("Using filaments with significantly different temperatures may cause:\n"
"• Extruder clogging\n"
"• Nozzle damage\n"
@ -876,6 +878,14 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
}
}
if (param == "legacy_networking") {
bool legacy_mode = checkbox->GetValue();
if (m_network_version_sizer != nullptr) {
m_network_version_sizer->Show(!legacy_mode);
m_parent->Layout();
}
}
e.Skip();
});
@ -1344,6 +1354,92 @@ void PreferencesDialog::create_items()
auto item_legacy_network = create_item_checkbox(_L("Use legacy network plugin"), _L("Disable to use latest network plugin that supports new BambuLab firmwares."), "legacy_networking", _L("(Requires restart)"));
g_sizer->Add(item_legacy_network);
m_network_version_sizer = new wxBoxSizer(wxHORIZONTAL);
m_network_version_sizer->AddSpacer(FromDIP(DESIGN_LEFT_MARGIN));
auto version_title = new wxStaticText(m_parent, wxID_ANY, _L("Network plugin version"), wxDefaultPosition, DESIGN_TITLE_SIZE, wxST_NO_AUTORESIZE);
version_title->SetForegroundColour(DESIGN_GRAY900_COLOR);
version_title->SetFont(::Label::Body_14);
version_title->SetToolTip(_L("Select the network plugin version to use"));
version_title->Wrap(DESIGN_TITLE_SIZE.x);
m_network_version_sizer->Add(version_title, 0, wxALIGN_CENTER);
m_network_version_combo = new ::ComboBox(m_parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(180), -1), 0, nullptr, wxCB_READONLY);
m_network_version_combo->SetFont(::Label::Body_14);
m_network_version_combo->GetDropDown().SetFont(::Label::Body_14);
std::string current_version = app_config->get("network_plugin_version");
int current_selection = 0;
for (size_t i = 0; i < BBL::AVAILABLE_NETWORK_VERSIONS_COUNT; i++) {
wxString label = wxString::FromUTF8(BBL::AVAILABLE_NETWORK_VERSIONS[i].display_name);
if (BBL::AVAILABLE_NETWORK_VERSIONS[i].is_latest) {
label += " " + _L("(Latest)");
}
m_network_version_combo->Append(label);
if (current_version == BBL::AVAILABLE_NETWORK_VERSIONS[i].version) {
current_selection = i;
}
}
m_network_version_combo->SetSelection(current_selection);
m_network_version_sizer->Add(m_network_version_combo, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5));
m_network_version_combo->GetDropDown().Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& e) {
int selection = e.GetSelection();
if (selection >= 0 && selection < (int)BBL::AVAILABLE_NETWORK_VERSIONS_COUNT) {
std::string new_version = BBL::AVAILABLE_NETWORK_VERSIONS[selection].version;
std::string old_version = app_config->get_network_plugin_version();
if (old_version.empty()) {
old_version = BBL::get_latest_network_version();
}
app_config->set(SETTING_NETWORK_PLUGIN_VERSION, new_version);
app_config->save();
if (new_version != old_version) {
BOOST_LOG_TRIVIAL(info) << "Network plugin version changed from " << old_version << " to " << new_version;
const char* warning = BBL::AVAILABLE_NETWORK_VERSIONS[selection].warning;
if (warning) {
MessageDialog warn_dlg(this, wxString::FromUTF8(warning), _L("Warning"), wxOK | wxCANCEL | wxICON_WARNING);
if (warn_dlg.ShowModal() != wxID_OK) {
app_config->set(SETTING_NETWORK_PLUGIN_VERSION, old_version);
app_config->save();
e.Skip();
return;
}
}
if (Slic3r::NetworkAgent::versioned_library_exists(new_version)) {
BOOST_LOG_TRIVIAL(info) << "Version " << new_version << " already exists on disk, triggering hot reload";
if (wxGetApp().hot_reload_network_plugin()) {
MessageDialog dlg(this, _L("Network plugin switched successfully."), _L("Success"), wxOK | wxICON_INFORMATION);
dlg.ShowModal();
} else {
MessageDialog dlg(this, _L("Failed to load network plugin. Please restart the application."), _L("Restart Required"), wxOK | wxICON_WARNING);
dlg.ShowModal();
}
} else {
wxString msg = wxString::Format(
_L("You've selected network plugin version %s.\n\nWould you like to download and install this version now?\n\nNote: The application may need to restart after installation."),
wxString::FromUTF8(new_version));
MessageDialog dlg(this, msg, _L("Download Network Plugin"), wxYES_NO | wxICON_QUESTION);
if (dlg.ShowModal() == wxID_YES) {
DownloadProgressDialog progress_dlg(_L("Downloading Network Plugin"));
progress_dlg.ShowModal();
}
}
}
}
e.Skip();
});
bool legacy_mode = app_config->get_bool("legacy_networking");
m_network_version_sizer->Show(!legacy_mode);
g_sizer->Add(m_network_version_sizer);
g_sizer->AddSpacer(FromDIP(10));
sizer_page->Add(g_sizer, 0, wxEXPAND);
@ -1413,6 +1509,18 @@ void PreferencesDialog::create_items()
auto loglevel_combox = create_item_loglevel_combobox(_L("Log Level"), _L("Log Level"), log_level_list);
g_sizer->Add(loglevel_combox);
g_sizer->Add(create_item_title(_L("Network Plugin")), 1, wxEXPAND);
auto item_reload_plugin = create_item_button(_L("Network plugin"), _L("Reload"), _L("Reload the network plugin without restarting the application"), "", [this]() {
if (wxGetApp().hot_reload_network_plugin()) {
MessageDialog dlg(this, _L("Network plugin reloaded successfully."), _L("Reload"), wxOK | wxICON_INFORMATION);
dlg.ShowModal();
} else {
MessageDialog dlg(this, _L("Failed to reload network plugin. Please restart the application."), _L("Reload Failed"), wxOK | wxICON_ERROR);
dlg.ShowModal();
}
});
g_sizer->Add(item_reload_plugin);
//// DEVELOPER > Debug
#if !BBL_RELEASE_TO_PUBLIC
g_sizer->Add(create_item_title(_L("Debug")), 1, wxEXPAND);
@ -1613,7 +1721,7 @@ wxBoxSizer* PreferencesDialog::create_debug_page()
bSizer->Add(enable_ssl_for_mqtt, 0, wxTOP, FromDIP(3));
bSizer->Add(enable_ssl_for_ftp, 0, wxTOP, FromDIP(3));
bSizer->Add(item_internal_developer, 0, wxTOP, FromDIP(3));
bSizer->Add(title_host, 0, wxEXPAND);
bSizer->Add(title_host, 0, wxEXPAND | wxTOP, FromDIP(10));
bSizer->Add(radio_group, 0, wxEXPAND | wxLEFT, FromDIP(DESIGN_LEFT_MARGIN));
bSizer->Add(debug_button, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(15));

View file

@ -68,6 +68,8 @@ public:
::CheckBox * m_dark_mode_ckeckbox = {nullptr};
::TextInput *m_backup_interval_textinput = {nullptr};
::CheckBox * m_legacy_networking_ckeckbox = {nullptr};
::ComboBox * m_network_version_combo = {nullptr};
wxBoxSizer * m_network_version_sizer = {nullptr};
wxString m_developer_mode_def;
wxString m_internal_developer_mode_def;

View file

@ -197,6 +197,20 @@ void TabButtonsListCtrl::SetPaddingSize(const wxSize& size) {
}
}
void TabButtonsListCtrl::SetFooterText(const wxString& text)
{
if (!m_footer_text) {
m_footer_text = new wxStaticText(this, wxID_ANY, text);
m_footer_text->SetForegroundColour(wxColour(128, 128, 128));
m_footer_text->SetFont(Label::Body_10);
int em = em_unit(this);
m_sizer->Add(m_footer_text, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, em / 2);
} else {
m_footer_text->SetLabel(text);
}
m_sizer->Layout();
}
//#endif // _WIN32

View file

@ -32,6 +32,7 @@ public:
wxString GetPageText(size_t n) const;
const wxSize& GetPaddingSize(size_t n);
void SetPaddingSize(const wxSize& size);
void SetFooterText(const wxString& text);
TabButton* pageButton;
private:
@ -43,6 +44,7 @@ private:
int m_selection {-1};
int m_btn_margin;
int m_line_margin;
wxStaticText* m_footer_text {nullptr};
};
class Tabbook: public wxBookCtrlBase
@ -261,6 +263,11 @@ public:
GetBtnsListCtrl()->Rescale();
}
void SetFooterText(const wxString& text)
{
GetBtnsListCtrl()->SetFooterText(text);
}
void OnNavigationKey(wxNavigationKeyEvent& event)
{
if (event.IsWindowChange()) {

View file

@ -27,6 +27,7 @@ static void* source_module = NULL;
#endif
bool NetworkAgent::use_legacy_network = true;
NetworkLibraryLoadError NetworkAgent::s_load_error = {};
typedef int (*func_start_print_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
typedef int (*func_start_local_print_with_record_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
@ -219,10 +220,72 @@ std::string NetworkAgent::get_libpath_in_current_directory(std::string library_n
return lib_path;
}
int NetworkAgent::initialize_network_module(bool using_backup)
std::string NetworkAgent::get_versioned_library_path(const std::string& version)
{
//int ret = -1;
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
#if defined(_MSC_VER) || defined(_WIN32)
return (plugin_folder / (std::string(BAMBU_NETWORK_LIBRARY) + "_" + version + ".dll")).string();
#elif defined(__WXMAC__)
return (plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + "_" + version + ".dylib")).string();
#else
return (plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + "_" + version + ".so")).string();
#endif
}
bool NetworkAgent::versioned_library_exists(const std::string& version)
{
if (version.empty()) return false;
std::string path = get_versioned_library_path(version);
return boost::filesystem::exists(path);
}
bool NetworkAgent::legacy_library_exists()
{
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
#if defined(_MSC_VER) || defined(_WIN32)
auto legacy_path = plugin_folder / (std::string(BAMBU_NETWORK_LIBRARY) + ".dll");
#elif defined(__WXMAC__)
auto legacy_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".dylib");
#else
auto legacy_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".so");
#endif
return boost::filesystem::exists(legacy_path);
}
void NetworkAgent::remove_legacy_library()
{
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
#if defined(_MSC_VER) || defined(_WIN32)
auto legacy_path = plugin_folder / (std::string(BAMBU_NETWORK_LIBRARY) + ".dll");
#elif defined(__WXMAC__)
auto legacy_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".dylib");
#else
auto legacy_path = plugin_folder / (std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".so");
#endif
if (boost::filesystem::exists(legacy_path)) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": removing legacy library at " << legacy_path.string();
boost::system::error_code ec;
boost::filesystem::remove(legacy_path, ec);
if (ec) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to remove legacy library: " << ec.message();
}
}
}
int NetworkAgent::initialize_network_module(bool using_backup, const std::string& version)
{
clear_load_error();
std::string library;
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
@ -232,25 +295,33 @@ int NetworkAgent::initialize_network_module(bool using_backup)
plugin_folder = plugin_folder/"backup";
}
//first load the library
if (version.empty()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": version is required but not provided";
set_load_error(
"Network library version not specified",
"A version must be specified to load the network library",
""
);
return -1;
}
#if defined(_MSC_VER) || defined(_WIN32)
library = plugin_folder.string() + "\\" + std::string(BAMBU_NETWORK_LIBRARY) + ".dll";
wchar_t lib_wstr[128];
library = plugin_folder.string() + "\\" + std::string(BAMBU_NETWORK_LIBRARY) + "_" + version + ".dll";
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": loading versioned library at " << library;
wchar_t lib_wstr[256];
memset(lib_wstr, 0, sizeof(lib_wstr));
::MultiByteToWideChar(CP_UTF8, NULL, library.c_str(), strlen(library.c_str())+1, lib_wstr, sizeof(lib_wstr) / sizeof(lib_wstr[0]));
netwoking_module = LoadLibrary(lib_wstr);
/*if (!netwoking_module) {
library = std::string(BAMBU_NETWORK_LIBRARY) + ".dll";
memset(lib_wstr, 0, sizeof(lib_wstr));
::MultiByteToWideChar(CP_UTF8, NULL, library.c_str(), strlen(library.c_str()) + 1, lib_wstr, sizeof(lib_wstr) / sizeof(lib_wstr[0]));
netwoking_module = LoadLibrary(lib_wstr);
}*/
if (!netwoking_module) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", try load library directly from current directory");
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": versioned library not found, trying current directory";
std::string library_path = get_libpath_in_current_directory(std::string(BAMBU_NETWORK_LIBRARY));
if (library_path.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", can not get path in current directory for %1%") % BAMBU_NETWORK_LIBRARY;
set_load_error(
"Network library not found",
"Could not locate versioned library: " + library,
library
);
return -1;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", current path %1%")%library_path;
@ -260,28 +331,36 @@ int NetworkAgent::initialize_network_module(bool using_backup)
}
#else
#if defined(__WXMAC__)
library = plugin_folder.string() + "/" + std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".dylib";
std::string lib_ext = ".dylib";
#else
library = plugin_folder.string() + "/" + std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + ".so";
std::string lib_ext = ".so";
#endif
printf("loading network module at %s\n", library.c_str());
netwoking_module = dlopen( library.c_str(), RTLD_LAZY);
library = plugin_folder.string() + "/" + std::string("lib") + std::string(BAMBU_NETWORK_LIBRARY) + "_" + version + lib_ext;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": loading versioned library at " << library;
netwoking_module = dlopen(library.c_str(), RTLD_LAZY);
if (!netwoking_module) {
/*#if defined(__WXMAC__)
library = std::string("lib") + BAMBU_NETWORK_LIBRARY + ".dylib";
#else
library = std::string("lib") + BAMBU_NETWORK_LIBRARY + ".so";
#endif*/
//netwoking_module = dlopen( library.c_str(), RTLD_LAZY);
char* dll_error = dlerror();
printf("error, dlerror is %s\n", dll_error);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", error, dlerror is %1%")%dll_error;
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": dlopen failed: " << (dll_error ? dll_error : "unknown error");
set_load_error(
"Failed to load network library",
dll_error ? std::string(dll_error) : "Unknown dlopen error",
library
);
}
printf("after dlopen, network_module is %p\n", netwoking_module);
#endif
if (!netwoking_module) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", can not Load Library for %1%")%library;
if (!s_load_error.has_error) {
set_load_error(
"Network library failed to load",
"LoadLibrary/dlopen returned null",
library
);
}
return -1;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", successfully loaded library %1%, module %2%")%library %netwoking_module;
@ -391,6 +470,12 @@ int NetworkAgent::initialize_network_module(bool using_backup)
get_mw_user_preference_ptr = reinterpret_cast<func_get_mw_user_preference>(get_network_function("bambu_network_get_mw_user_preference"));
get_mw_user_4ulist_ptr = reinterpret_cast<func_get_mw_user_4ulist>(get_network_function("bambu_network_get_mw_user_4ulist"));
if (get_version_ptr) {
std::string version = get_version_ptr();
printf("network plugin version: %s\n", version.c_str());
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": network plugin version = " << version;
}
return 0;
}
@ -515,6 +600,11 @@ int NetworkAgent::unload_network_module()
return 0;
}
bool NetworkAgent::is_network_module_loaded()
{
return netwoking_module != nullptr;
}
#if defined(_MSC_VER) || defined(_WIN32)
HMODULE NetworkAgent::get_bambu_source_entry()
#else
@ -610,6 +700,24 @@ std::string NetworkAgent::get_version()
return "00.00.00.00";
}
NetworkLibraryLoadError NetworkAgent::get_load_error()
{
return s_load_error;
}
void NetworkAgent::clear_load_error()
{
s_load_error = NetworkLibraryLoadError{};
}
void NetworkAgent::set_load_error(const std::string& message, const std::string& technical_details, const std::string& attempted_path)
{
s_load_error.has_error = true;
s_load_error.message = message;
s_load_error.technical_details = technical_details;
s_load_error.attempted_path = attempted_path;
}
int NetworkAgent::init_log()
{
int ret = 0;

View file

@ -116,8 +116,13 @@ class NetworkAgent
public:
static std::string get_libpath_in_current_directory(std::string library_name);
static int initialize_network_module(bool using_backup = false);
static std::string get_versioned_library_path(const std::string& version);
static bool versioned_library_exists(const std::string& version);
static bool legacy_library_exists();
static void remove_legacy_library();
static int initialize_network_module(bool using_backup = false, const std::string& version = "");
static int unload_network_module();
static bool is_network_module_loaded();
#if defined(_MSC_VER) || defined(_WIN32)
static HMODULE get_bambu_source_entry();
#else
@ -126,6 +131,10 @@ public:
static std::string get_version();
static void* get_network_function(const char* name);
static bool use_legacy_network;
static NetworkLibraryLoadError get_load_error();
static void clear_load_error();
static void set_load_error(const std::string& message, const std::string& technical_details, const std::string& attempted_path);
NetworkAgent(std::string log_dir);
~NetworkAgent();
@ -232,6 +241,8 @@ private:
bool enable_track = false;
void* network_agent { nullptr };
static NetworkLibraryLoadError s_load_error;
static func_check_debug_consistent check_debug_consistent_ptr;
static func_get_version get_version_ptr;
static func_create_agent create_agent_ptr;

View file

@ -849,7 +849,7 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_
BOOST_LOG_TRIVIAL(info) << "non need to sync plugins for there is no plugins currently.";
return;
}
std::string curr_version = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION;
std::string curr_version = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BBL::get_latest_network_version();
std::string using_version = curr_version.substr(0, 9) + "00";
std::string cached_version;

View file

@ -98,7 +98,6 @@ namespace BBL {
#define BAMBU_NETWORK_AGENT_NAME "bambu_network_agent"
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.01"
#define BAMBU_NETWORK_AGENT_VERSION "02.03.00.62"
//iot preset type strings
#define IOT_PRINTER_TYPE_STRING "printer"
@ -306,6 +305,36 @@ struct CertificateInformation {
std::string serial_number;
};
struct NetworkLibraryVersion {
const char* version;
const char* display_name;
const char* url_override;
bool is_latest;
const char* warning;
};
static const NetworkLibraryVersion AVAILABLE_NETWORK_VERSIONS[] = {
{"02.03.00.62", "02.03.00.62", nullptr, true, nullptr},
{"02.01.01.52", "02.01.01.52", nullptr, false, nullptr},
{"02.00.02.50", "02.00.02.50", nullptr, false, "This version may crash on startup due to Bambu Lab's signature verification."},
};
static const size_t AVAILABLE_NETWORK_VERSIONS_COUNT = sizeof(AVAILABLE_NETWORK_VERSIONS) / sizeof(AVAILABLE_NETWORK_VERSIONS[0]);
inline const char* get_latest_network_version() {
for (size_t i = 0; i < AVAILABLE_NETWORK_VERSIONS_COUNT; ++i) {
if (AVAILABLE_NETWORK_VERSIONS[i].is_latest)
return AVAILABLE_NETWORK_VERSIONS[i].version;
}
return AVAILABLE_NETWORK_VERSIONS[0].version;
}
struct NetworkLibraryLoadError {
bool has_error = false;
std::string message;
std::string technical_details;
std::string attempted_path;
};
enum class MessageFlag : int
{

View file

@ -4,6 +4,7 @@ add_executable(${_TEST_NAME}_tests
${_TEST_NAME}_tests.cpp
test_3mf.cpp
test_aabbindirect.cpp
test_appconfig.cpp
test_clipper_offset.cpp
test_clipper_utils.cpp
test_config.cpp

View file

@ -0,0 +1,45 @@
#include <catch2/catch_all.hpp>
#include "libslic3r/AppConfig.hpp"
using namespace Slic3r;
TEST_CASE("AppConfig network version helpers", "[AppConfig]") {
AppConfig config;
SECTION("skipped versions starts empty") {
auto skipped = config.get_skipped_network_versions();
REQUIRE(skipped.empty());
}
SECTION("add and check skipped version") {
config.add_skipped_network_version("02.01.01.52");
REQUIRE(config.is_network_version_skipped("02.01.01.52"));
REQUIRE_FALSE(config.is_network_version_skipped("02.03.00.62"));
}
SECTION("multiple skipped versions") {
config.add_skipped_network_version("02.01.01.52");
config.add_skipped_network_version("02.00.02.50");
auto skipped = config.get_skipped_network_versions();
REQUIRE(skipped.size() == 2);
REQUIRE(config.is_network_version_skipped("02.01.01.52"));
REQUIRE(config.is_network_version_skipped("02.00.02.50"));
}
SECTION("clear skipped versions") {
config.add_skipped_network_version("02.01.01.52");
config.clear_skipped_network_versions();
REQUIRE_FALSE(config.is_network_version_skipped("02.01.01.52"));
}
SECTION("duplicate add is idempotent") {
config.add_skipped_network_version("02.01.01.52");
config.add_skipped_network_version("02.01.01.52");
auto skipped = config.get_skipped_network_versions();
REQUIRE(skipped.size() == 1);
REQUIRE(config.is_network_version_skipped("02.01.01.52"));
}
}