2.2.0 pre (#80)

* Recover: Packaging Process

* Update: Flutter 1222

* Fix: crash when recreate GUI

* Fix Crash when using m_profile_json

* Fix NetworkTestDialog crash
This commit is contained in:
xiaoyeliu
2025-12-22 17:55:49 +08:00
committed by GitHub
parent f729c53b20
commit 9a0027035e
4 changed files with 153 additions and 105 deletions

View File

@@ -199,8 +199,8 @@ void initSentryEx()
sentry_options_set_debug(options, 0); sentry_options_set_debug(options, 0);
#endif #endif
sentry_options_set_environment(options, "develop"); // sentry_options_set_environment(options, "develop");
//sentry_options_set_environment(options, "Release"); sentry_options_set_environment(options, "Release");
sentry_options_set_auto_session_tracking(options, 0); sentry_options_set_auto_session_tracking(options, 0);
sentry_options_set_symbolize_stacktraces(options, 1); sentry_options_set_symbolize_stacktraces(options, 1);

View File

@@ -27,6 +27,10 @@ NetworkTestDialog::NetworkTestDialog(wxWindow* parent, wxWindowID id, const wxSt
wxSize(1000, 700), wxSize(1000, 700),
/*wxCAPTION*/wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER) /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER)
{ {
// Create a self-managing shared_ptr for weak_ptr support
// Note: This creates a self-reference, so we need to break it in destructor
self_ptr = std::shared_ptr<NetworkTestDialog>(this, [](NetworkTestDialog*) { /* custom deleter - do nothing, object is stack-allocated */ });
weak_this = self_ptr;
this->SetBackgroundColour(wxColour(255, 255, 255)); this->SetBackgroundColour(wxColour(255, 255, 255));
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
@@ -80,15 +84,21 @@ wxBoxSizer* NetworkTestDialog::create_top_sizer(wxWindow* parent)
btn_clear_log->SetStyle(ButtonStyle::Regular, ButtonType::Window); btn_clear_log->SetStyle(ButtonStyle::Regular, ButtonType::Window);
line_sizer->Add(btn_clear_log, 0, wxALL, 5); line_sizer->Add(btn_clear_log, 0, wxALL, 5);
btn_start->Bind(wxEVT_BUTTON, [this](wxCommandEvent &evt) { btn_start->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent &evt) {
start_all_job(); if (auto self = weak_this.lock()) {
self->start_all_job();
}
}); });
btn_start_sequence->Bind(wxEVT_BUTTON, [this](wxCommandEvent &evt) { btn_start_sequence->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent &evt) {
start_all_job_sequence(); if (auto self = weak_this.lock()) {
self->start_all_job_sequence();
}
}); });
btn_clear_log->Bind(wxEVT_BUTTON, [this](wxCommandEvent &evt) { btn_clear_log->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent &evt) {
if (txt_log) { if (auto self = weak_this.lock()) {
txt_log->Clear(); if (self->txt_log) {
self->txt_log->Clear();
}
} }
}); });
sizer->Add(line_sizer, 0, wxEXPAND, 5); sizer->Add(line_sizer, 0, wxEXPAND, 5);
@@ -228,28 +238,40 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent)
sizer->Add(grid_sizer, 1, wxEXPAND, 5); sizer->Add(grid_sizer, 1, wxEXPAND, 5);
btn_link->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_link->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_github_thread(); if (auto self = weak_this.lock()) {
self->start_test_github_thread();
}
}); });
btn_bing->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_bing->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_bing_thread(); if (auto self = weak_this.lock()) {
self->start_test_bing_thread();
}
}); });
btn_lan_mqtt->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_lan_mqtt->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_lan_mqtt_thread(); if (auto self = weak_this.lock()) {
self->start_test_lan_mqtt_thread();
}
}); });
btn_cloud_mqtt->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_cloud_mqtt->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_cloud_mqtt_thread(); if (auto self = weak_this.lock()) {
self->start_test_cloud_mqtt_thread();
}
}); });
btn_login_api->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_login_api->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_login_api_thread(); if (auto self = weak_this.lock()) {
self->start_test_login_api_thread();
}
}); });
btn_upload_api->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { btn_upload_api->Bind(wxEVT_BUTTON, [weak_this = weak_this](wxCommandEvent& evt) {
start_test_upload_api_thread(); if (auto self = weak_this.lock()) {
self->start_test_upload_api_thread();
}
}); });
return sizer; return sizer;
@@ -271,25 +293,28 @@ NetworkTestDialog::~NetworkTestDialog()
m_closing.store(true); m_closing.store(true);
m_download_cancel = true; m_download_cancel = true;
cleanup_threads(); cleanup_threads();
// Break the self-reference to avoid issues
self_ptr.reset();
} }
void NetworkTestDialog::init_bind() void NetworkTestDialog::init_bind()
{ {
Bind(EVT_UPDATE_RESULT, [this](wxCommandEvent& evt) { Bind(EVT_UPDATE_RESULT, [weak_this = weak_this](wxCommandEvent& evt) {
if (m_closing.load()) return; auto self = weak_this.lock();
if (!self || self->m_closing.load()) return;
if (evt.GetInt() == TEST_ORCA_JOB) { if (evt.GetInt() == TEST_ORCA_JOB) {
text_link_val->SetLabelText(evt.GetString()); self->text_link_val->SetLabelText(evt.GetString());
} else if (evt.GetInt() == TEST_BING_JOB) { } else if (evt.GetInt() == TEST_BING_JOB) {
text_bing_val->SetLabelText(evt.GetString()); self->text_bing_val->SetLabelText(evt.GetString());
} else if (evt.GetInt() == TEST_LAN_MQTT_JOB) { } else if (evt.GetInt() == TEST_LAN_MQTT_JOB) {
text_lan_mqtt_val->SetLabelText(evt.GetString()); self->text_lan_mqtt_val->SetLabelText(evt.GetString());
} else if (evt.GetInt() == TEST_CLOUD_MQTT_JOB) { } else if (evt.GetInt() == TEST_CLOUD_MQTT_JOB) {
text_cloud_mqtt_val->SetLabelText(evt.GetString()); self->text_cloud_mqtt_val->SetLabelText(evt.GetString());
} else if (evt.GetInt() == TEST_LOGIN_API_JOB) { } else if (evt.GetInt() == TEST_LOGIN_API_JOB) {
text_login_api_val->SetLabelText(evt.GetString()); self->text_login_api_val->SetLabelText(evt.GetString());
} else if (evt.GetInt() == TEST_UPLOAD_API_JOB) { } else if (evt.GetInt() == TEST_UPLOAD_API_JOB) {
text_upload_api_val->SetLabelText(evt.GetString()); self->text_upload_api_val->SetLabelText(evt.GetString());
} }
std::time_t t = std::time(0); std::time_t t = std::time(0);
@@ -298,8 +323,8 @@ void NetworkTestDialog::init_bind()
buf << std::put_time(now_time, "%a %b %d %H:%M:%S"); buf << std::put_time(now_time, "%a %b %d %H:%M:%S");
wxString info = wxString(buf.str()) + ": " + evt.GetString() + "\n"; wxString info = wxString(buf.str()) + ": " + evt.GetString() + "\n";
try { try {
if (!m_closing.load() && txt_log) { if (!self->m_closing.load() && self->txt_log) {
txt_log->AppendText(info); self->txt_log->AppendText(info);
} }
} }
catch (std::exception& e) { catch (std::exception& e) {
@@ -360,52 +385,54 @@ void NetworkTestDialog::start_all_job_sequence()
device_ip = dlg.GetValue().Trim(); device_ip = dlg.GetValue().Trim();
} }
m_sequence_job = new boost::thread([this, device_ip] { m_sequence_job = new boost::thread([weak_this = weak_this, device_ip] {
update_status(-1, "========================================"); auto self = weak_this.lock();
update_status(-1, "Start sequence test (single-thread mode)"); if (!self) return;
update_status(-1, "========================================"); self->update_status(-1, "========================================");
update_status(-1, ""); self->update_status(-1, "Start sequence test (single-thread mode)");
self->update_status(-1, "========================================");
self->update_status(-1, "");
start_test_url(TEST_BING_JOB, "Bing", "http://www.bing.com"); self->start_test_url(TEST_BING_JOB, "Bing", "http://www.bing.com");
if (m_closing.load()) return; if (self->m_closing.load()) return;
update_status(-1, ""); self->update_status(-1, "");
start_test_url(TEST_ORCA_JOB, "Snapmaker Orca(GitHub)", "https://github.com/Snapmaker/OrcaSlicer"); self->start_test_url(TEST_ORCA_JOB, "Snapmaker Orca(GitHub)", "https://github.com/Snapmaker/OrcaSlicer");
if (m_closing.load()) return; if (self->m_closing.load()) return;
// 如果用户输入了局域网设备IP则进行测试 // 如果用户输入了局域网设备IP则进行测试
if (!device_ip.IsEmpty()) { if (!device_ip.IsEmpty()) {
update_status(-1, ""); self->update_status(-1, "");
start_test_telnet(TEST_LAN_MQTT_JOB, "LAN Device", device_ip, 1884); self->start_test_telnet(TEST_LAN_MQTT_JOB, "LAN Device", device_ip, 1884);
if (m_closing.load()) return; if (self->m_closing.load()) return;
} }
// 测试云服务器 // 测试云服务器
wxString cloud_server = get_cloud_server_address(); wxString cloud_server = self->get_cloud_server_address();
if (!cloud_server.IsEmpty()) { if (!cloud_server.IsEmpty()) {
update_status(-1, ""); self->update_status(-1, "");
start_test_telnet(TEST_CLOUD_MQTT_JOB, "Cloud Server", cloud_server, 8883); self->start_test_telnet(TEST_CLOUD_MQTT_JOB, "Cloud Server", cloud_server, 8883);
} }
if (m_closing.load()) return; if (self->m_closing.load()) return;
// 测试登录API // 测试登录API
update_status(-1, ""); self->update_status(-1, "");
auto app_config = wxGetApp().app_config; auto app_config = wxGetApp().app_config;
std::string region = app_config->get("region"); std::string region = app_config->get("region");
wxString login_api_url = (region == "Chinese Mainland" || region == "China") ? "https://id.snapmaker.cn" : "https://id.snapmaker.com"; wxString login_api_url = (region == "Chinese Mainland" || region == "China") ? "https://id.snapmaker.cn" : "https://id.snapmaker.com";
start_test_url(TEST_LOGIN_API_JOB, "Login API", login_api_url); self->start_test_url(TEST_LOGIN_API_JOB, "Login API", login_api_url);
if (m_closing.load()) return; if (self->m_closing.load()) return;
// 测试上传API // 测试上传API
update_status(-1, ""); self->update_status(-1, "");
wxString upload_api_url = (region == "Chinese Mainland" || region == "China") ? "https://public.resource.snapmaker.cn" : "https://public.resource.snapmaker.com"; wxString upload_api_url = (region == "Chinese Mainland" || region == "China") ? "https://public.resource.snapmaker.cn" : "https://public.resource.snapmaker.com";
start_test_url(TEST_UPLOAD_API_JOB, "Upload API", upload_api_url); self->start_test_url(TEST_UPLOAD_API_JOB, "Upload API", upload_api_url);
if (m_closing.load()) return; if (self->m_closing.load()) return;
update_status(-1, ""); self->update_status(-1, "");
update_status(-1, "========================================"); self->update_status(-1, "========================================");
update_status(-1, "Sequence test completed"); self->update_status(-1, "Sequence test completed");
update_status(-1, "========================================"); self->update_status(-1, "========================================");
}); });
} }
@@ -424,9 +451,11 @@ void NetworkTestDialog::start_test_url(TestJob job, wxString name, wxString url)
update_status(-1, ""); update_status(-1, "");
int result = -1; int result = -1;
auto weak_self = weak_this;
http.timeout_max(10) http.timeout_max(10)
.on_complete([this, &result, job](std::string body, unsigned status) { .on_complete([weak_self, &result, job](std::string body, unsigned status) {
if (m_closing.load()) return; auto self = weak_self.lock();
if (!self || self->m_closing.load()) return;
try { try {
if (status == 200) { if (status == 200) {
result = 0; result = 0;
@@ -440,21 +469,23 @@ void NetworkTestDialog::start_test_url(TestJob job, wxString name, wxString url)
; ;
} }
}) })
.on_ip_resolve([this,name,job](std::string ip) { .on_ip_resolve([weak_self, name, job](std::string ip) {
if (m_closing.load()) return; auto self = weak_self.lock();
if (!self || self->m_closing.load()) return;
wxString ip_report = "test " + name + " ip resolved = " + wxString::FromUTF8(ip); wxString ip_report = "test " + name + " ip resolved = " + wxString::FromUTF8(ip);
update_status(job, ip_report); self->update_status(job, ip_report);
}) })
.on_error([this,name,job](std::string body, std::string error, unsigned int status) { .on_error([weak_self, name, job](std::string body, std::string error, unsigned int status) {
if (m_closing.load()) return; auto self = weak_self.lock();
if (!self || self->m_closing.load()) return;
// Upload API: 403 is OK (HTTPS resource with permission check) // Upload API: 403 is OK (HTTPS resource with permission check)
if (job == TEST_UPLOAD_API_JOB && status == 403) { if (job == TEST_UPLOAD_API_JOB && status == 403) {
this->update_status(job, "test " + name + " ok (403 - access restricted, but server reachable)"); self->update_status(job, "test " + name + " ok (403 - access restricted, but server reachable)");
return; return;
} }
wxString info = wxString::Format("status=%u, body=", status) + wxString::FromUTF8(body) + ", error=" + wxString::FromUTF8(error); wxString info = wxString::Format("status=%u, body=", status) + wxString::FromUTF8(body) + ", error=" + wxString::FromUTF8(error);
this->update_status(job, "test " + name + " failed"); self->update_status(job, "test " + name + " failed");
this->update_status(-1, info); self->update_status(-1, info);
}).perform_sync(); }).perform_sync();
if (result == 0) { if (result == 0) {
@@ -468,10 +499,12 @@ void NetworkTestDialog::start_test_url(TestJob job, wxString name, wxString url)
void NetworkTestDialog::start_test_ping_thread() void NetworkTestDialog::start_test_ping_thread()
{ {
test_job[TEST_PING_JOB] = new boost::thread([this] { test_job[TEST_PING_JOB] = new boost::thread([weak_this = weak_this] {
m_in_testing[TEST_PING_JOB].store(true); auto self = weak_this.lock();
if (!self) return;
self->m_in_testing[TEST_PING_JOB].store(true);
m_in_testing[TEST_PING_JOB].store(false); self->m_in_testing[TEST_PING_JOB].store(false);
}); });
} }
@@ -859,9 +892,11 @@ void NetworkTestDialog::start_test_lan_mqtt_thread()
test_job[TEST_LAN_MQTT_JOB] = nullptr; test_job[TEST_LAN_MQTT_JOB] = nullptr;
} }
test_job[TEST_LAN_MQTT_JOB] = new boost::thread([this, device_ip] { test_job[TEST_LAN_MQTT_JOB] = new boost::thread([weak_this = weak_this, device_ip] {
auto self = weak_this.lock();
if (!self) return;
// 测试局域网设备 - 端口默认1884 // 测试局域网设备 - 端口默认1884
start_test_telnet(TEST_LAN_MQTT_JOB, "LAN Device", device_ip, 1884); self->start_test_telnet(TEST_LAN_MQTT_JOB, "LAN Device", device_ip, 1884);
}); });
} }
@@ -895,9 +930,11 @@ void NetworkTestDialog::start_test_cloud_mqtt_thread()
test_job[TEST_CLOUD_MQTT_JOB] = nullptr; test_job[TEST_CLOUD_MQTT_JOB] = nullptr;
} }
test_job[TEST_CLOUD_MQTT_JOB] = new boost::thread([this, cloud_server] { test_job[TEST_CLOUD_MQTT_JOB] = new boost::thread([weak_this = weak_this, cloud_server] {
auto self = weak_this.lock();
if (!self) return;
// 测试云服务器 - 使用telnet方式端口8883 // 测试云服务器 - 使用telnet方式端口8883
start_test_telnet(TEST_CLOUD_MQTT_JOB, "Cloud Server", cloud_server, 8883); self->start_test_telnet(TEST_CLOUD_MQTT_JOB, "Cloud Server", cloud_server, 8883);
}); });
} }
void NetworkTestDialog::start_test_github_thread() void NetworkTestDialog::start_test_github_thread()
@@ -911,8 +948,10 @@ void NetworkTestDialog::start_test_github_thread()
test_job[TEST_ORCA_JOB] = nullptr; test_job[TEST_ORCA_JOB] = nullptr;
} }
test_job[TEST_ORCA_JOB] = new boost::thread([this] { test_job[TEST_ORCA_JOB] = new boost::thread([weak_this = weak_this] {
start_test_url(TEST_ORCA_JOB, "Snapmaker Orca(GitHub)", "https://github.com/Snapmaker/OrcaSlicer"); auto self = weak_this.lock();
if (!self) return;
self->start_test_url(TEST_ORCA_JOB, "Snapmaker Orca(GitHub)", "https://github.com/Snapmaker/OrcaSlicer");
}); });
} }
@@ -927,8 +966,10 @@ void NetworkTestDialog::start_test_bing_thread()
test_job[TEST_BING_JOB] = nullptr; test_job[TEST_BING_JOB] = nullptr;
} }
test_job[TEST_BING_JOB] = new boost::thread([this] { test_job[TEST_BING_JOB] = new boost::thread([weak_this = weak_this] {
start_test_url(TEST_BING_JOB, "Bing", "http://www.bing.com"); auto self = weak_this.lock();
if (!self) return;
self->start_test_url(TEST_BING_JOB, "Bing", "http://www.bing.com");
}); });
} }
@@ -943,11 +984,13 @@ void NetworkTestDialog::start_test_login_api_thread()
test_job[TEST_LOGIN_API_JOB] = nullptr; test_job[TEST_LOGIN_API_JOB] = nullptr;
} }
test_job[TEST_LOGIN_API_JOB] = new boost::thread([this] { test_job[TEST_LOGIN_API_JOB] = new boost::thread([weak_this = weak_this] {
auto self = weak_this.lock();
if (!self) return;
auto app_config = wxGetApp().app_config; auto app_config = wxGetApp().app_config;
std::string region = app_config->get("region"); std::string region = app_config->get("region");
wxString login_api_url = (region == "Chinese Mainland") ? "https://id.snapmaker.cn" : "https://id.snapmaker.com"; wxString login_api_url = (region == "Chinese Mainland") ? "https://id.snapmaker.cn" : "https://id.snapmaker.com";
start_test_url(TEST_LOGIN_API_JOB, "Login API", login_api_url); self->start_test_url(TEST_LOGIN_API_JOB, "Login API", login_api_url);
}); });
} }
@@ -962,11 +1005,13 @@ void NetworkTestDialog::start_test_upload_api_thread()
test_job[TEST_UPLOAD_API_JOB] = nullptr; test_job[TEST_UPLOAD_API_JOB] = nullptr;
} }
test_job[TEST_UPLOAD_API_JOB] = new boost::thread([this] { test_job[TEST_UPLOAD_API_JOB] = new boost::thread([weak_this = weak_this] {
auto self = weak_this.lock();
if (!self) return;
auto app_config = wxGetApp().app_config; auto app_config = wxGetApp().app_config;
std::string region = app_config->get("region"); std::string region = app_config->get("region");
wxString upload_api_url = (region == "Chinese Mainland") ? "https://public.resource.snapmaker.cn" : "https://public.resource.snapmaker.com"; wxString upload_api_url = (region == "Chinese Mainland") ? "https://public.resource.snapmaker.cn" : "https://public.resource.snapmaker.com";
start_test_url(TEST_UPLOAD_API_JOB, "Upload API", upload_api_url); self->start_test_url(TEST_UPLOAD_API_JOB, "Upload API", upload_api_url);
}); });
} }

View File

@@ -29,6 +29,7 @@
#include <time.h> #include <time.h>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <memory>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@@ -47,6 +48,8 @@ enum TestJob {
class NetworkTestDialog : public DPIDialog class NetworkTestDialog : public DPIDialog
{ {
protected: protected:
std::shared_ptr<NetworkTestDialog> self_ptr;
std::weak_ptr<NetworkTestDialog> weak_this;
Button* btn_start; Button* btn_start;
Button* btn_start_sequence; Button* btn_start_sequence;
Button* btn_download_log; Button* btn_download_log;

View File

@@ -684,28 +684,28 @@ int GuideFrame::SaveProfile()
m_appconfig_new.set_vendors(empty_vendor_map); m_appconfig_new.set_vendors(empty_vendor_map);
{ {
std::lock_guard<std::mutex> lock(m_ProfileJson_mutex); std::lock_guard<std::mutex> lock(m_ProfileJson_mutex);
for (auto it = m_ProfileJson["model"].begin(); it != m_ProfileJson["model"].end(); ++it) for (auto it = m_ProfileJson["model"].begin(); it != m_ProfileJson["model"].end(); ++it) {
{ if (it.value().is_object()) {
if (it.value().is_object()) { json temp_model = it.value();
json temp_model = it.value(); std::string model_name = temp_model["model"];
std::string model_name = temp_model["model"]; std::string vendor_name = temp_model["vendor"];
std::string vendor_name = temp_model["vendor"]; std::string selected = temp_model["nozzle_selected"];
std::string selected = temp_model["nozzle_selected"]; boost::trim(selected);
boost::trim(selected); std::string nozzle;
std::string nozzle; while (selected.size() > 0) {
while (selected.size() > 0) { auto pos = selected.find(';');
auto pos = selected.find(';'); if (pos != std::string::npos) {
if (pos != std::string::npos) { nozzle = selected.substr(0, pos);
nozzle = selected.substr(0, pos); m_appconfig_new.set_variant(vendor_name, model_name, nozzle, "true");
m_appconfig_new.set_variant(vendor_name, model_name, nozzle, "true"); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("vendor_name %1%, model_name %2%, nozzle %3% selected")%vendor_name %model_name %nozzle;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("vendor_name %1%, model_name %2%, nozzle %3% selected")%vendor_name %model_name %nozzle; selected = selected.substr(pos + 1);
selected = selected.substr(pos + 1); boost::trim(selected);
boost::trim(selected); }
} else {
else { m_appconfig_new.set_variant(vendor_name, model_name, selected, "true");
m_appconfig_new.set_variant(vendor_name, model_name, selected, "true"); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("vendor_name %1%, model_name %2%, nozzle %3% selected")%vendor_name %model_name %selected;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("vendor_name %1%, model_name %2%, nozzle %3% selected")%vendor_name %model_name %selected; break;
break; }
} }
} }
} }