// Implementation of Moonraker printer host communication #include "MoonRaker.hpp" #include "MQTT.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/format.hpp" #include "Http.hpp" #include "libslic3r/AppConfig.hpp" #include "Bonjour.hpp" #include "slic3r/GUI/BonjourDialog.hpp" #include "slic3r/GUI/WebPreprintDialog.hpp" #include "slic3r/GUI/SSWCP.hpp" #include "sentry_wrapper/SentryWrapper.hpp" #ifdef _WIN32 #include #include #else #include #include #include #include #endif namespace fs = boost::filesystem; namespace pt = boost::property_tree; namespace Slic3r { namespace { #ifdef WIN32 // Helper function to extract host and port from URL std::string get_host_from_url(const std::string& url_in) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始解析URL获取主机信息: " << url_in; wcp_loger.add_log("开始解析URL获取主机信息: " + url_in, false, "", "Moonraker_Mqtt", "info"); std::string url = url_in; // Add http:// if there is no scheme size_t double_slash = url.find("//"); if (double_slash == std::string::npos) { url = "http://" + url; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 添加默认协议前缀,修改后的URL: " << url; wcp_loger.add_log("添加默认协议前缀,修改后的URL: " + url, false, "", "Moonraker_Mqtt", "info"); } std::string out = url; CURLU* hurl = curl_url(); if (hurl) { // Parse the input URL CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, url.c_str(), 0); if (rc == CURLUE_OK) { // Extract host and port char* host; rc = curl_url_get(hurl, CURLUPART_HOST, &host, 0); if (rc == CURLUE_OK) { char* port; rc = curl_url_get(hurl, CURLUPART_PORT, &port, 0); if (rc == CURLUE_OK && port != nullptr) { out = std::string(host) + ":" + port; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 成功提取主机和端口: " << out; wcp_loger.add_log("成功提取主机和端口 " + out, false, "", "Moonraker_Mqtt", "info"); curl_free(port); } else { out = host; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 成功提取主机(无端口): " << out; wcp_loger.add_log("成功提取主机(无端口): " + out, false, "", "Moonraker_Mqtt", "info"); curl_free(host); } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 从URL获取主机失败: " << url; wcp_loger.add_log("从url获取主机失败: " + url, false, "", "Moonraker_Mqtt", "error"); } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 解析URL失败: " << url; wcp_loger.add_log("解析URL失败: " + url, false, "", "Moonraker_Mqtt", "error"); } curl_url_cleanup(hurl); } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 分配curl_url失败"; wcp_loger.add_log("分配Curlurl失败", false, "", "Moonraker_Mqtt", "error"); } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] URL解析完成,返回结果: " << out; wcp_loger.add_log("URL解析完成,返回结果: " + out, false, "", "Moonraker_Mqtt", "info"); return out; } // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. std::string substitute_host(const std::string& orig_addr, std::string sub_addr) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始替换主机地址,原地址: " << orig_addr << ", 新地址: " << sub_addr; wcp_loger.add_log("开始替换主机地址,原地址: " + orig_addr + ", 新地址: " + sub_addr, false, "", "Moonraker_Mqtt", "info"); // put ipv6 into [] brackets if (sub_addr.find(':') != std::string::npos && sub_addr.at(0) != '[') { sub_addr = "[" + sub_addr + "]"; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 检测到IPv6地址,添加方括号: " << sub_addr; wcp_loger.add_log("检测到IPv6地址,添加方括号: " + sub_addr, false, "", "Moonraker_Mqtt", "info"); } #if 0 //URI = scheme ":"["//"[userinfo "@"] host [":" port]] path["?" query]["#" fragment] std::string final_addr = orig_addr; // http size_t double_dash = orig_addr.find("//"); size_t host_start = (double_dash == std::string::npos ? 0 : double_dash + 2); // userinfo size_t at = orig_addr.find("@"); host_start = (at != std::string::npos && at > host_start ? at + 1 : host_start); // end of host, could be port(:), subpath(/) (could be query(?) or fragment(#)?) // or it will be ']' if address is ipv6 ) size_t potencial_host_end = orig_addr.find_first_of(":/", host_start); // if there are more ':' it must be ipv6 if (potencial_host_end != std::string::npos && orig_addr[potencial_host_end] == ':' && orig_addr.rfind(':') != potencial_host_end) { size_t ipv6_end = orig_addr.find(']', host_start); // DK: Uncomment and replace orig_addr.length() if we want to allow subpath after ipv6 without [] parentheses. potencial_host_end = (ipv6_end != std::string::npos ? ipv6_end + 1 : orig_addr.length()); //orig_addr.find('/', host_start)); } size_t host_end = (potencial_host_end != std::string::npos ? potencial_host_end : orig_addr.length()); // now host_start and host_end should mark where to put resolved addr // check host_start. if its nonsense, lets just use original addr (or resolved addr?) if (host_start >= orig_addr.length()) { return final_addr; } final_addr.replace(host_start, host_end - host_start, sub_addr); return final_addr; #else // Using the new CURL API for handling URL. https://everything.curl.dev/libcurl/url // If anything fails, return the input unchanged. std::string out = orig_addr; CURLU* hurl = curl_url(); if (hurl) { // Parse the input URL. CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, orig_addr.c_str(), 0); if (rc == CURLUE_OK) { // Replace the address. rc = curl_url_set(hurl, CURLUPART_HOST, sub_addr.c_str(), 0); if (rc == CURLUE_OK) { // Extract a string fromt the CURL URL handle. char* url; rc = curl_url_get(hurl, CURLUPART_URL, &url, 0); if (rc == CURLUE_OK) { out = url; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 主机地址替换成功: " << out; wcp_loger.add_log("主机地址替换成功: " + out, false, "", "Moonraker_Mqtt", "info"); curl_free(url); } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 替换后提取URL失败"; wcp_loger.add_log("替换后提取URL失败", false, "", "Moonraker_Mqtt", "error"); } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 替换主机失败,主机: " << sub_addr << ", URL: " << orig_addr; wcp_loger.add_log("替换主机失败,主机: " + sub_addr, false, "", "Moonraker_Mqtt", "error"); } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 解析原始URL失败: " << orig_addr; wcp_loger.add_log("解析原始URL失败: " + orig_addr, false, "", "Moonraker_Mqtt", "error"); } curl_url_cleanup(hurl); } else{ BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 分配curl_url失败"; wcp_loger.add_log("分配curl_url失败", false, "", "Moonraker_Mqtt", "error"); } return out; #endif } #endif // WIN32 // Helper function to URL encode a string std::string escape_string(const std::string& unescaped) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 开始URL编码字符串,长度: " << unescaped.size(); wcp_loger.add_log("开始URL编码字符串,长度: " + std::to_string(unescaped.size()), false, "", "Moonraker_Mqtt", "info"); std::string ret_val; CURL* curl = curl_easy_init(); if (curl) { char* decoded = curl_easy_escape(curl, unescaped.c_str(), unescaped.size()); if (decoded) { ret_val = std::string(decoded); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] URL编码成功"; wcp_loger.add_log("URL编码成功: ", false, "", "Moonraker_Mqtt", "info"); curl_free(decoded); } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] URL编码失败"; wcp_loger.add_log("URL编码失败", false, "", "Moonraker_Mqtt", "error"); } curl_easy_cleanup(curl); } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 初始化CURL失败"; wcp_loger.add_log("初始化CURL失败", false, "", "Moonraker_Mqtt", "error"); } return ret_val; } // Helper function to URL encode each element of a filesystem path std::string escape_path_by_element(const boost::filesystem::path& path) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 开始路径元素编码: " << path.string(); wcp_loger.add_log("开始路径元素编码: " + path.string(), false, "", "Moonraker_Mqtt", "info"); std::string ret_val = escape_string(path.filename().string()); boost::filesystem::path parent(path.parent_path()); while (!parent.empty() && parent.string() != "/") // "/" check is for case "/file.gcode" was inserted. Then boost takes "/" as parent_path. { ret_val = escape_string(parent.filename().string()) + "/" + ret_val; parent = parent.parent_path(); } BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 路径编码完成: " << ret_val; wcp_loger.add_log("路径编码完成: " + ret_val, false, "", "Moonraker_Mqtt", "info"); return ret_val; } } // namespace Moonraker::Moonraker(DynamicPrintConfig* config) : m_host(config->opt_string("print_host")) , m_apikey(config->opt_string("printhost_apikey")) , m_cafile(config->opt_string("printhost_cafile")) , m_ssl_revoke_best_effort(config->opt_bool("printhost_ssl_ignore_revoke")) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 初始化Moonraker实例,主机: " << m_host; wcp_loger.add_log("初始化Moonraker实例,主机: " + m_host, false, "", "Moonraker_Mqtt", "info"); } // Return the name of this print host type const char* Moonraker::get_name() const { return "Moonraker"; } #ifdef WIN32 bool Moonraker::test_with_resolved_ip(wxString& msg) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始使用解析的IP进行测试"; wcp_loger.add_log("开始使用解析的IP进行测试", false, "", "Moonraker_Mqtt", "info"); // Since the request is performed synchronously here, // it is ok to refer to `msg` from within the closure const char* name = get_name(); bool res = true; // Msg contains ip string. auto url = substitute_host(make_url("api/version"), GUI::into_u8(msg)); msg.Clear(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息,URL: %2%") % name % url; wcp_loger.add_log(name + std::string(": 获取版本信息,URL: ") + url, false, "", "Moonraker_Mqtt", "info"); std::string host = get_host_from_url(m_host); auto http = Http::get(url); // std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy // is used (issue #9734). Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // https://www.rfc-editor.org/rfc/rfc7230#section-5.4 http.header("Host", host); set_auth(http); http.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息出错,URL: %2%, 错误: %3%, HTTP状态: %4%, 响应体: `%5%`") % name % url % error % status % body; wcp_loger.add_log(std::string(name) + "ddd" + url + ", 错误: " + error + ", HTTP状态: " + std::to_string(status) + ", 响应体: " + body, false, "", "Moonraker_Mqtt", "error"); res = false; msg = format_error(body, error, status); }) .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息成功: %2%") % name % body; wcp_loger.add_log(std::string(name) + ": 获取版本信息成功: " + body, false, "", "Moonraker_Mqtt", "info"); try { std::stringstream ss(body); pt::ptree ptree; pt::read_json(ss, ptree); if (!ptree.get_optional("api")) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 响应中未找到API字段"; wcp_loger.add_log("响应中未找到API字段", false, "", "Moonraker_Mqtt", "error"); res = false; return; } const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (!res) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 版本文本验证失败"; wcp_loger.add_log("版本文本验证失败", false, "", "Moonraker_Mqtt", "error"); msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : name)); } else { BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 版本验证成功"; wcp_loger.add_log("版本验证成功", false, "", "Moonraker_Mqtt", "info"); } } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 解析服务器响应失败: " << e.what(); wcp_loger.add_log("解析服务器响应失败: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); res = false; msg = "Could not parse server response."; } }) .ssl_revoke_best_effort(m_ssl_revoke_best_effort) .perform_sync(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] IP测试完成,结果: " << (res ? "成功" : "失败"); wcp_loger.add_log("IP测试完成,结果: " + std::string(res ? "成功" : "失败"), false, "", "Moonraker_Mqtt", "info"); return res; } #endif // WIN32 bool Moonraker::get_machine_info(const std::vector>>& targets, json& response) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取机器信息,目标数量: " << targets.size(); wcp_loger.add_log("开始获取机器信息,目标数量: " + std::to_string(targets.size()), false, "", "Moonraker_Mqtt", "info"); bool res = true; auto url = make_url("printer/objects/query"); auto http = Http::post(std::move(url)); for (const auto pair : targets) { std::string value = ""; for (size_t i = 0; i < pair.second.size(); ++i) { if (i != 0) { value += ","; } value += pair.second[i]; } http.form_add(pair.first, value); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 添加查询参数: " << pair.first << " = " << value; wcp_loger.add_log("添加查询参数: " + pair.first + " = " + value, false, "", "Moonraker_Mqtt", "info"); } http.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 获取机器信息失败,错误: " << error << ", HTTP状态: " << status; wcp_loger.add_log("获取机器信息失败,错误: " + error + ", HTTP状态: " + std::to_string(status), false, "", "Moonraker_Mqtt", "error"); res = false; try{ response = json::parse(body); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 解析错误响应失败: " << e.what(); wcp_loger.add_log("解析错误响应失败: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } }) .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 获取机器信息成功"; wcp_loger.add_log("获取机器信息成功", false, "", "Moonraker_Mqtt", "info"); try { response = json::parse(body); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 解析机器信息响应失败: " << e.what(); wcp_loger.add_log("解析机器信息响应失败: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } }) .perform_sync(); return res; } bool Moonraker::send_gcodes(const std::vector& codes, std::string& extraInfo) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始发送G代码,数量: " << codes.size(); wcp_loger.add_log("开始发送G代码,数量: " + std::to_string(codes.size()), false, "", "Moonraker_Mqtt", "info"); bool res = true; std::string param = "?script="; for (const auto code : codes) { param += "\n"; param += code; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 添加G代码: " << code; wcp_loger.add_log("添加G代码: " + code, false, "", "Moonraker_Mqtt", "info"); } auto url = make_url("printer/gcode/script"); auto http = Http::post(std::move(url)); http.form_add("script", param) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送G代码失败,错误: " << error << ", HTTP状态: " << status; wcp_loger.add_log("发送G代码失败,错误: " + error + ", HTTP状态: " + std::to_string(status), false, "", "Moonraker_Mqtt", "error"); res = false; }) .on_complete([&](std::string body, unsigned){ BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] G代码发送成功"; wcp_loger.add_log("G代码发送成功", false, "", "Moonraker_Mqtt", "info"); res = true; }) .perform_sync(); return res; } bool Moonraker::test(wxString& msg) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始连接测试"; wcp_loger.add_log("开始连接测试", false, "", "Moonraker_Mqtt", "info"); //// test //MqttClient* mqttClient = new MqttClient("mqtt://172.18.0.9:1883", "OrcaClient", false); //mqttClient->SetMessageCallback([](const std::string& topic, const std::string& payload) { // int a = 0; // int b = 0; //}); //mqttClient->Connect(); //mqttClient->Subscribe("9BD4E436F33D0B56/response", 2); //mqttClient->Subscribe("9BD4E436F33D0B56/status", 2); //mqttClient->Publish("9BD4E436F33D0B56/request", "{\"jsonrpc\": \"2.0\",\"method\": \"server.info\",\"id\": 9546}", 1); // Since the request is performed synchronously here, // it is ok to refer to `msg` from within the closure const char* name = get_name(); bool res = true; auto url = make_url("printer/info"); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息,URL: %2%") % name % url; wcp_loger.add_log(name + std::string(": 获取版本信息,URL: ") + url, false, "", "Moonraker_Mqtt", "info"); // Here we do not have to add custom "Host" header - the url contains host filled by user and libCurl will set the header by itself. auto http = Http::get(std::move(url)); set_auth(http); http.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息出错: %2%, HTTP状态: %3%, 响应体: `%4%`") % name % error % status % body; wcp_loger.add_log(name + std::string(": 获取版本信息出错: ") + error + ", HTTP状态: " + std::to_string(status) + ", 响应体: " + body, false, "", "Moonraker_Mqtt", "error"); res = false; msg = format_error(body, error, status); }) .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 获取版本信息成功: %2%") % name % body; wcp_loger.add_log(name + std::string(": 获取版本信息成功: ") + body, false, "", "Moonraker_Mqtt", "info"); //try { // std::stringstream ss(body); // pt::ptree ptree; // pt::read_json(ss, ptree); // if (!ptree.get_optional("api")) { // res = false; // return; // } // const auto text = ptree.get_optional("text"); // // test // //res = validate_version_text(text); // res = true; // if (!res) { // msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : name)); // } //} catch (const std::exception&) { // res = false; // msg = "Could not parse server response"; //} }) #ifdef WIN32 .ssl_revoke_best_effort(m_ssl_revoke_best_effort) .on_ip_resolve([&](std::string address) { // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. // Remember resolved address to be reused at successive REST API call. BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] IP解析成功: " << address; wcp_loger.add_log("IP解析成功: " + address, false, "", "Moonraker_Mqtt", "info"); msg = GUI::from_u8(address); }) #endif // WIN32 .perform_sync(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 连接测试完成,结果: " << (res ? "成功" : "失败"); wcp_loger.add_log("连接测试完成,结果: " + std::string((res ? "成功" : "失败")), false, "", "Moonraker_Mqtt", "info"); return res; } // Return success message for connection test wxString Moonraker::get_test_ok_msg() const { return _(L("Connection to Moonraker works correctly.")); } // Return formatted error message for failed connection test wxString Moonraker::get_test_failed_msg(wxString& msg) const { return GUI::format_wxstr("%s: %s\n\n%s", _L("Could not connect to Moonraker"), msg, _L("Note: Moonraker version at least 1.1.0 is required.")); } // Upload a file to the printer bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始文件上传,源文件: " << upload_data.source_path.string() << ", 目标路径: " << upload_data.upload_path.string(); wcp_loger.add_log("开始文件上传,源文件: " + upload_data.source_path.string() + ", 目标路径: " + upload_data.upload_path.string(), false, "", "Moonraker_Mqtt", "info"); // 依赖flutter,先放开 if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 上传后需要开始打印,显示预打印对话框"; wcp_loger.add_log("上传后需要开始打印,显示预打印对话框", false, "", "Moonraker_Mqtt", "info"); // 创建 promise 和 future 用于线程同步 std::promise promise; auto future = promise.get_future(); // 使用 CallAfter 切换到主线程 wxTheApp->CallAfter([this, &promise, upload_data, &wcp_loger]() { GUI::WebPreprintDialog dialog; dialog.set_gcode_file_name(upload_data.source_path.string()); dialog.set_display_file_name(upload_data.upload_path.string()); bool res = dialog.run(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 预打印对话框结果: " << (res ? "确认" : "取消"); wcp_loger.add_log("预打印对话框结果: " + std::string((res ? "确认" : "取消")), false, "", "Moonraker_Mqtt", "info"); // 设置结果 promise.set_value(res); }); // 等待主线程完成 bool flag = future.get(); if (!flag) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 用户取消了打印,终止上传"; wcp_loger.add_log("用户取消了打印,终止上传", false, "", "Moonraker_Mqtt", "info"); Http::Progress progress(0, 0, 0, 0, ""); bool cancel = true; prorgess_fn(progress, cancel); return false; } } #ifndef WIN32 BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用主机名上传(非Windows)"; wcp_loger.add_log("使用主机名上传(非Windows)", false, "", "Moonraker_Mqtt", "info"); return upload_inner_with_host(std::move(upload_data), prorgess_fn, error_fn, info_fn); #else BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] Windows平台,开始IP解析流程"; wcp_loger.add_log("Windows平台,开始IP解析流程", false, "", "Moonraker_Mqtt", "info"); std::string host = get_host_from_url(m_host); // decide what to do based on m_host - resolve hostname or upload to ip std::vector resolved_addr; boost::system::error_code ec; boost::asio::ip::address host_ip = boost::asio::ip::make_address(host, ec); if (!ec) { BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 主机已是IP地址: " << host_ip.to_string(); wcp_loger.add_log("主机已是IP地址: " + host_ip.to_string(), false, "", "Moonraker_Mqtt", "info"); resolved_addr.push_back(host_ip); } else if (GUI::get_app_config()->get_bool("allow_ip_resolve") && boost::algorithm::ends_with(host, ".local")) { BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 开始解析.local域名: " << host; wcp_loger.add_log("开始解析.local域名: " + host, false, "", "Moonraker_Mqtt", "info"); Bonjour("Moonraker") .set_hostname(host) .set_retries(5) // number of rounds of queries send .set_timeout(1) // after each timeout, if there is any answer, the resolving will stop .on_resolve([&ra = resolved_addr, &wcp_loger](const std::vector& replies) { for (const auto& rpl : replies) { boost::asio::ip::address ip(rpl.ip); ra.emplace_back(ip); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 解析到IP地址: " << rpl.ip; wcp_loger.add_log("解析到IP地址: " + rpl.ip.to_string(), false, "", "Moonraker_Mqtt", "info"); } }) .resolve_sync(); } // Handle different resolution scenarios if (resolved_addr.empty()) { // no resolved addresses - try system resolving BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 无法解析主机名 " << m_host << " 到IP地址,使用系统解析进行上传"; wcp_loger.add_log("无法解析主机名 " + m_host + " 到IP地址,使用系统解析进行上传", false, "", "Moonraker_Mqtt", "error"); return upload_inner_with_host(std::move(upload_data), prorgess_fn, error_fn, info_fn); } else if (resolved_addr.size() == 1) { // one address resolved - upload there BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 解析到单个地址,开始上传: " << resolved_addr.front().to_string(); wcp_loger.add_log("解析到单个地址,开始上传: " + resolved_addr.front().to_string(), false, "", "Moonraker_Mqtt", "info"); return upload_inner_with_resolved_ip(std::move(upload_data), prorgess_fn, error_fn, info_fn, resolved_addr.front()); } else if (resolved_addr.size() == 2 && resolved_addr[0].is_v4() != resolved_addr[1].is_v4()) { // there are just 2 addresses and 1 is ip_v4 and other is ip_v6 // try sending to both. (Then if both fail, show both error msg after second try) BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 解析到IPv4和IPv6地址,依次尝试上传"; wcp_loger.add_log("解析到IPv4和IPv6地址,依次尝试上传", false, "", "Moonraker_Mqtt", "info"); wxString error_message; if (!upload_inner_with_resolved_ip( std::move(upload_data), prorgess_fn, [&msg = error_message, resolved_addr, &wcp_loger](wxString error) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 第一个IP上传失败: " << resolved_addr.front().to_string(); wcp_loger.add_log("第一个IP上传失败: " + resolved_addr.front().to_string(), false, "", "Moonraker_Mqtt", "warning"); msg = GUI::format_wxstr("%1%: %2%", resolved_addr.front(), error); }, info_fn, resolved_addr.front()) && !upload_inner_with_resolved_ip( std::move(upload_data), prorgess_fn, [&msg = error_message, resolved_addr, &wcp_loger](wxString error) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 第二个IP上传失败: " << resolved_addr.back().to_string(); wcp_loger.add_log("第二个IP上传失败: " + resolved_addr.back().to_string(), false, "", "Moonraker_Mqtt", "warning"); msg += GUI::format_wxstr("\n%1%: %2%", resolved_addr.back(), error); }, info_fn, resolved_addr.back())) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 所有IP地址上传均失败"; wcp_loger.add_log("所有IP地址上传均失败", false, "", "Moonraker_Mqtt", "error"); error_fn(error_message); return false; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 至少一个IP地址上传成功"; wcp_loger.add_log("至少一个IP地址上传成功", false, "", "Moonraker_Mqtt", "info"); return true; } else { // There are multiple addresses - user needs to choose which to use. BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 解析到多个地址(" << resolved_addr.size() << "个),需要用户选择"; wcp_loger.add_log("解析到多个地址(" + std::to_string(resolved_addr.size()) + "个),需要用户选择", false, "", "Moonraker_Mqtt", "info"); size_t selected_index = resolved_addr.size(); IPListDialog dialog(nullptr, boost::nowide::widen(m_host), resolved_addr, selected_index); if (dialog.ShowModal() == wxID_OK && selected_index < resolved_addr.size()) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 用户选择IP地址: " << resolved_addr[selected_index].to_string(); wcp_loger.add_log("用户选择IP地址: " + resolved_addr[selected_index].to_string(), false, "", "Moonraker_Mqtt", "info"); return upload_inner_with_resolved_ip(std::move(upload_data), prorgess_fn, error_fn, info_fn, resolved_addr[selected_index]); } else { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 用户取消IP选择"; wcp_loger.add_log("用户取消IP选择", false, "", "Moonraker_Mqtt", "info"); } } return false; #endif // WIN32 } #ifdef WIN32 // Upload file using resolved IP address bool Moonraker::upload_inner_with_resolved_ip(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn, const boost::asio::ip::address& resolved_addr) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用解析的IP地址上传: " << resolved_addr.to_string(); wcp_loger.add_log("使用解析的IP地址上传: " + resolved_addr.to_string(), false, "", "Moonraker_Mqtt", "info"); info_fn(L"resolve", boost::nowide::widen(resolved_addr.to_string())); // If test fails, test_msg_or_host_ip contains the error message. // Otherwise on Windows it contains the resolved IP address of the host. // Test_msg already contains resolved ip and will be cleared on start of test(). wxString test_msg_or_host_ip = GUI::from_u8(resolved_addr.to_string()); if (/* !test_with_resolved_ip(test_msg_or_host_ip)*/ false) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] IP测试失败"; wcp_loger.add_log("IP测试失败", false, "", "Moonraker_Mqtt", "error"); error_fn(std::move(test_msg_or_host_ip)); return false; } const char* name = get_name(); const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); std::string url = substitute_host(make_url("server/files/upload"), resolved_addr.to_string()); bool result = true; info_fn(L"resolve", boost::nowide::widen(url)); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 上传文件 %2% 到 %3%, 文件名: %4%, 路径: %5%, 打印: %6%") % name % upload_data.source_path % url % upload_filename.string() % upload_parent_path.string() % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "是" : "否"); wcp_loger.add_log(name + std::string(": 上传文件 ") + upload_data.source_path.string() + " 到 " + url + ", 文件名: " + upload_filename.string() + ", 路径: " + upload_parent_path.string() + ", 打印: " + (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "是" : "否"), false, "", "Moonraker_Mqtt", "info"); std::string host = get_host_from_url(m_host); auto http = Http::post(url); // std::move(url)); // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // And when creating Http object above, libcurl automatically includes "Host" header from address it got. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy // is used (issue #9734). https://www.rfc-editor.org/rfc/rfc7230#section-5.4 http.header("Host", host); set_auth(http); http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? .form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 文件上传成功: HTTP %2%: %3%") % name % status % body; wcp_loger.add_log(name + std::string(": 文件上传成功: HTTP ") + std::to_string(status) + ": " + body, false, "", "Moonraker_Mqtt", "info"); }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 上传文件到 %2% 失败: %3%, HTTP %4%, 响应体: `%5%`") % name % url % error % status % body; wcp_loger.add_log(name + std::string(": 上传文件到 ") + url + " 失败: " + error + ", HTTP " + std::to_string(status) + ", 响应体: `" + body + "`", false, "", "Moonraker_Mqtt", "error"); // 尝试8080端口 BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 尝试使用8080端口重新上传"; wcp_loger.add_log("尝试使用8080端口重新上传", false, "", "Moonraker_Mqtt", "info"); url = substitute_host(make_url_8080("server/files/upload"), GUI::into_u8(test_msg_or_host_ip)); auto http_8080 = Http::post(std::move(url)); http_8080.header("host", host); set_auth(http_8080); http_8080.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? .form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 8080端口文件上传成功: HTTP %2%: %3%") % name % status % body; wcp_loger.add_log(name + std::string(": 8080端口文件上传成功: HTTP ") + std::to_string(status) + ": " + body, false, "", "Moonraker_Mqtt", "info"); }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 8080端口上传失败: %2%, HTTP %3%, 响应体: `%4%`") % name % error % status % body; wcp_loger.add_log(name + std::string(": 8080端口上传失败: ") + error + ", HTTP " + std::to_string(status) + ", 响应体: `" + body + "`", false, "", "Moonraker_Mqtt", "error"); error_fn(format_error(body, error, status)); result = false; }) .on_progress([&](Http::Progress progress, bool& cancel) { prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << name << ": 8080端口上传被取消"; wcp_loger.add_log(name + std::string(": 8080端口上传被取消"), false, "", "Moonraker_Mqtt", "info"); result = false; } }) #ifdef WIN32 .ssl_revoke_best_effort(m_ssl_revoke_best_effort) #endif .perform_sync(); }) .on_progress([&](Http::Progress progress, bool& cancel) { prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << name << ": 上传被取消"; wcp_loger.add_log(name + std::string(": 上传被取消"), false, "", "Moonraker_Mqtt", "info"); result = false; } }) .ssl_revoke_best_effort(m_ssl_revoke_best_effort) .perform_sync(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] IP地址上传完成,结果: " << (result ? "成功" : "失败"); wcp_loger.add_log("IP地址上传完成,结果: " + std::string((result ? "成功" : "失败")), false, "", "Moonraker_Mqtt", "info"); return result; } #endif // WIN32 // Upload file using hostname bool Moonraker::upload_inner_with_host(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用主机名上传文件"; wcp_loger.add_log("使用主机名上传文件", false, "", "Moonraker_Mqtt", "info"); const char* name = get_name(); const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); // If test fails, test_msg_or_host_ip contains the error message. // Otherwise on Windows it contains the resolved IP address of the host. wxString test_msg_or_host_ip; /* if (!test(test_msg_or_host_ip)) { error_fn(std::move(test_msg_or_host_ip)); return false; } */ std::string url; bool res = true; #ifdef WIN32 // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. if (m_host.find("https://") == 0 || test_msg_or_host_ip.empty() || !GUI::get_app_config()->get_bool("allow_ip_resolve")) #endif // _WIN32 { // If https is entered we assume signed ceritificate is being used // IP resolving will not happen - it could resolve into address not being specified in cert BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用HTTPS或禁用IP解析,直接使用主机名"; wcp_loger.add_log("使用HTTPS或禁用IP解析,直接使用主机名", false, "", "Moonraker_Mqtt", "info"); url = make_url("server/files/upload"); } #ifdef WIN32 else { // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. // Curl uses easy_getinfo to get ip address of last successful transaction. // If it got the address use it instead of the stored in "host" variable. // This new address returns in "test_msg_or_host_ip" variable. // Solves troubles of uploades failing with name address. // in original address (m_host) replace host for resolved ip BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用IP解析workaround"; wcp_loger.add_log("使用IP解析workaround", false, "", "Moonraker_Mqtt", "info"); info_fn(L"resolve", test_msg_or_host_ip); url = substitute_host(make_url("server/files/upload"), GUI::into_u8(test_msg_or_host_ip)); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] IP解析后的上传地址: " << url; wcp_loger.add_log("IP解析后的上传地址: " + url, false, "", "Moonraker_Mqtt", "info"); } #endif // _WIN32 BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 上传文件 %2% 到 %3%, 文件名: %4%, 路径: %5%, 打印: %6%") % name % upload_data.source_path % url % upload_filename.string() % upload_parent_path.string() % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "是" : "否"); wcp_loger.add_log(name + std::string(": 上传文件 ") + upload_data.source_path.string() + " 到 " + url + ", 文件名: " + upload_filename.string() + ", 路径: " + upload_parent_path.string() + ", 打印: " + (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "是" : "否"), false, "", "Moonraker_Mqtt", "info"); auto http = Http::post(std::move(url)); #ifdef WIN32 // "Host" header is necessary here. In the workaround above (two mDNS..) we have got IP address from test connection and subsituted it // into "url" variable. And when creating Http object above, libcurl automatically includes "Host" header from address it got. Thus "Host" // is set to the resolved IP instead of host filled by user. We need to change it back. Not changing the host would work on the most cases // (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). Also when allow_ip_resolve = // 0, this is not needed, but it should not break anything if it stays. https://www.rfc-editor.org/rfc/rfc7230#section-5.4 std::string host = get_host_from_url(m_host); http.header("Host", host); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 设置Host头: " << host; wcp_loger.add_log("设置Host头: " + host, false, "", "Moonraker_Mqtt", "info"); #endif // _WIN32 set_auth(http); http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? .form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 文件上传成功: HTTP %2%: %3%") % name % status % body; wcp_loger.add_log(name + std::string(": 文件上传成功: HTTP ") + std::to_string(status) + ": " + body, false, "", "Moonraker_Mqtt", "info"); }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 上传文件失败: %2%, HTTP %3%, 响应体: `%4%`") % name % error % status % body; wcp_loger.add_log(name + std::string(": 上传文件失败: ") + error + ", HTTP " + std::to_string(status) + ", 响应体: `" + body + "`", false, "", "Moonraker_Mqtt", "error"); // 尝试8080端口 BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 尝试使用8080端口重新上传"; wcp_loger.add_log("尝试使用8080端口重新上传", false, "", "Moonraker_Mqtt", "info"); url = make_url_8080("server/files/upload"); auto http_8080 = Http::post(std::move(url)); set_auth(http_8080); http_8080.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? .form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << boost::format("%1%: 8080端口文件上传成功: HTTP %2%: %3%") % name % status % body; wcp_loger.add_log(name + std::string(": 8080端口文件上传成功: HTTP ") + std::to_string(status) + ": " + body, false, "", "Moonraker_Mqtt", "info"); }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] " << boost::format("%1%: 8080端口上传失败: %2%, HTTP %3%, 响应体: `%4%`") % name % error % status % body; wcp_loger.add_log(name + std::string(": 8080端口上传失败: ") + error + ", HTTP " + std::to_string(status) + ", 响应体: `" + body + "`", false, "", "Moonraker_Mqtt", "error"); error_fn(format_error(body, error, status)); res = false; }) .on_progress([&](Http::Progress progress, bool& cancel) { prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << name << ": 8080端口上传被取消"; wcp_loger.add_log(name + std::string(": 8080端口上传被取消"), false, "", "Moonraker_Mqtt", "info"); res = false; } }) #ifdef WIN32 .ssl_revoke_best_effort(m_ssl_revoke_best_effort) #endif .perform_sync(); }) .on_progress([&](Http::Progress progress, bool& cancel) { prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] " << name << ": 上传被取消"; wcp_loger.add_log(name + std::string(": 上传被取消"), false, "", "Moonraker_Mqtt", "info"); res = false; } }) #ifdef WIN32 .ssl_revoke_best_effort(m_ssl_revoke_best_effort) #endif .perform_sync(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 主机名上传完成,结果: " << (res ? "成功" : "失败"); wcp_loger.add_log("主机名上传完成,结果: " + std::string((res ? "成功" : "失败")), false, "", "Moonraker_Mqtt", "info"); return res; } // Validate version text to confirm printer type bool Moonraker::validate_version_text(const boost::optional& version_text) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); bool result = version_text ? boost::starts_with(*version_text, "Moonraker") : true; BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 版本文本验证: " << (version_text ? *version_text : "空") << ", 结果: " << (result ? "通过" : "失败"); wcp_loger.add_log("版本文本验证: " + (version_text ? *version_text : "空") + ", 结果: " + (result ? "通过" : "失败"), false, "", "Moonraker_Mqtt", "info"); return result; } // Set authentication headers for HTTP requests void Moonraker::set_auth(Http& http) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 设置认证头,API密钥长度: " << m_apikey.length(); wcp_loger.add_log("设置认证头,API密钥长度: " + std::to_string(m_apikey.length()), false, "", "Moonraker_Mqtt", "info"); http.header("X-Api-Key", m_apikey); if (!m_cafile.empty()) { BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 设置CA文件: " << m_cafile; wcp_loger.add_log("设置CA文件: " + m_cafile, false, "", "Moonraker_Mqtt", "info"); http.ca_file(m_cafile); } } std::string Moonraker::make_url_8080(const std::string& path) const { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 构建8080端口URL,路径: " << path; wcp_loger.add_log("构建8080端口URL,路径: " + path, false, "", "Moonraker_Mqtt", "info"); size_t pos = m_host.find(":"); std::string target_host = m_host; if (pos != std::string::npos && pos != std::string("http:").length() - 1 && std::string("https:").length() - 1) { target_host = target_host.substr(0, pos); BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 移除端口号,目标主机: " << target_host; wcp_loger.add_log("移除端口号,目标主机: " + target_host, false, "", "Moonraker_Mqtt", "info"); } std::string result; if (target_host.find("http://") == 0 || target_host.find("https://") == 0) { if (target_host.back() == '/') { target_host = target_host.substr(0, target_host.length() - 1); result = (boost::format("%1%:8080/%2%") % target_host % path).str(); } else { result = (boost::format("%1%:8080/%2%") % target_host % path).str(); } } else { result = (boost::format("http://%1%:8080/%2%") % target_host % path).str(); } BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] 8080端口URL构建完成: " << result; wcp_loger.add_log("8080端口URL构建完成: " + result, false, "", "Moonraker_Mqtt", "info"); return result; } // Construct full URL for API endpoint std::string Moonraker::make_url(const std::string& path) const { if (m_host.find("http://") == 0 || m_host.find("https://") == 0) { if (m_host.back() == '/') { return (boost::format("%1%%2%") % m_host % path).str(); } else { return (boost::format("%1%/%2%") % m_host % path).str(); } } else { if (m_host.find(":1884") != std::string::npos) { std::string http_host = m_host.substr(0, m_host.find(":1884")); return (boost::format("http://%1%/%2%") % http_host % path).str(); } if (m_host.find(":8883") != std::string::npos) { std::string http_host = m_host.substr(0, m_host.find(":8883")); return (boost::format("http://%1%/%2%") % http_host % path).str(); } return (boost::format("http://%1%/%2%") % m_host % path).str(); } } // Basic connect implementation bool Moonraker::connect(wxString& msg, const nlohmann::json& params) { return test(msg); } // Moonraker_mqtt std::shared_ptr Moonraker_Mqtt::m_mqtt_client = nullptr; std::shared_ptr Moonraker_Mqtt::m_mqtt_client_tls = nullptr; TimeoutMap Moonraker_Mqtt::m_request_cb_map; std::string Moonraker_Mqtt::m_response_topic = "/response"; std::string Moonraker_Mqtt::m_status_topic = "/status"; std::string Moonraker_Mqtt::m_notification_topic = "/notification"; std::string Moonraker_Mqtt::m_request_topic = "/request"; std::string Moonraker_Mqtt::m_sn = ""; std::mutex Moonraker_Mqtt::m_sn_mtx; std::string Moonraker_Mqtt::m_auth_topic = "/config/response"; std::string Moonraker_Mqtt::m_auth_req_topic = "/config/request"; nlohmann::json Moonraker_Mqtt::m_auth_info = nlohmann::json::object(); std::unordered_map> Moonraker_Mqtt::m_status_cbs; std::unordered_map> Moonraker_Mqtt::m_notification_cbs; Moonraker_Mqtt::Moonraker_Mqtt(DynamicPrintConfig* config, bool change_engine) : Moonraker(config) { std::string host_info = config->option("print_host")->value; auto& wcp_loger = GUI::WCP_Logger::getInstance(); if (change_engine) { // 获取本地IP std::string local_ip; try { #ifdef _WIN32 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { throw std::runtime_error("Failed to create socket"); } #else int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { throw std::runtime_error("Failed to create socket"); } #endif // 连接到一个外部地址(这里使用Google的DNS服务器) struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(53); inet_pton(AF_INET, "8.8.8.8", &addr.sin_addr); if (::connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { #ifdef _WIN32 closesocket(sock); #else close(sock); #endif throw std::runtime_error("Failed to connect"); } // 获取本地地址 struct sockaddr_in local_addr; socklen_t len = sizeof(local_addr); if (getsockname(sock, (struct sockaddr*)&local_addr, &len) < 0) { #ifdef _WIN32 closesocket(sock); #else close(sock); #endif throw std::runtime_error("Failed to get local address"); } // 转换为字符串 char ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &local_addr.sin_addr, ip_str, INET_ADDRSTRLEN); local_ip = ip_str; #ifdef _WIN32 closesocket(sock); #else close(sock); #endif } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Error getting local IP: " << e.what(); wcp_loger.add_log("获取本地IP失败: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); local_ip = "0.0.0.0"; // 失败时使用默认IP } m_mqtt_client.reset(new MqttClient("mqtt://" + host_info, local_ip, "", "", true)); m_mqtt_client_tls.reset(); BOOST_LOG_TRIVIAL(error) << "本地ip" << local_ip; wcp_loger.add_log("本地ip: " + local_ip, false, "", "Moonraker_Mqtt", "error"); } } // set auth info void Moonraker_Mqtt::set_auth_info(const nlohmann::json& info) { m_auth_info = info; } nlohmann::json Moonraker_Mqtt::get_auth_info() { json authinfo; authinfo["user"] = m_user_name; authinfo["password"] = m_password; authinfo["ca"] = m_ca; authinfo["cert"] = m_cert; authinfo["key"] = m_key; authinfo["clientId"] = m_client_id; authinfo["port"] = m_port; return authinfo; } bool Moonraker_Mqtt::set_engine(const std::shared_ptr& engine, std::string& msg) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 开始设置MQTT引擎 id: " << std::to_string(int64_t(engine.get())); if (!engine) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 引擎指针为空,无法设置"; msg = "engine is null"; return false; } BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 检查新引擎连接状态..."; if (!engine->CheckConnected()) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 新引擎连接检查失败"; msg = "engine connection failed"; return false; } BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 新引擎连接状态正常"; if (m_mqtt_client_tls) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 检查旧引擎连接状态..."; if (m_mqtt_client_tls->CheckConnected()) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 旧引擎仍处于连接状态,开始断开..."; std::string dis_msg = "success"; bool disconnect_result = m_mqtt_client_tls->Disconnect(dis_msg); if (disconnect_result) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 旧引擎断开成功: " << dis_msg; } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 旧引擎断开失败: " << dis_msg; } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 旧引擎已处于断开状态"; } } else { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 没有旧的引擎需要断开"; } BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 设置新引擎指针"; m_mqtt_client_tls = engine; BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 设置消息回调函数"; m_mqtt_client_tls->SetMessageCallback([this](const std::string& topic, const std::string& payload) { this->on_mqtt_tls_message_arrived(topic, payload); }); BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 引擎设置完成"; msg = "success"; return true; } // Ask for TLS info bool Moonraker_Mqtt::ask_for_tls_info(const nlohmann::json& cn_params) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); if (!m_mqtt_client) { return false; } if(m_mqtt_client->CheckConnected()) { std::string dc_msg = ""; m_mqtt_client->Disconnect(dc_msg); } m_sn_mtx.lock(); m_sn = ""; m_sn_mtx.unlock(); std::string connection_msg = ""; bool is_connect = m_mqtt_client->Connect(connection_msg); if(!is_connect || !cn_params.count("code") || cn_params["code"].get() == "") { return false; } std::string auth_code = cn_params["code"].get(); std::string sub_msg = "success"; bool response_subscribed = m_mqtt_client->Subscribe(auth_code + m_auth_topic, 1, sub_msg); if (!response_subscribed) { return false; } m_mqtt_client->SetMessageCallback([this](const std::string& topic, const std::string& payload) { this->on_mqtt_message_arrived(topic, payload); }); json body; body["jsonrpc"] = "2.0"; body["method"] = "server.request_key"; json params; std::string clientid; try { clientid = m_mqtt_client->get_client_id(); } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Error getting local IP: " << e.what(); wcp_loger.add_log("获取本地IP失败: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); clientid = "0.0.0.0"; // 失败时使用默认IP } if(clientid == "0.0.0.0") { return false; } params["clientid"] = clientid; body["params"] = params; int64_t seq_id = m_seq_generator.generate_seq_id(); // 同步等待 std::promise auth_promise; std::future auth_future = auth_promise.get_future(); auto callback = [this, &auth_promise](const nlohmann::json& res) { try{ json result = res; std::string state = result["state"].get(); if (state != "success") { auth_promise.set_value(false); return; } // sn m_sn_mtx.lock(); m_sn = result["sn"].get(); m_sn_mtx.unlock(); m_client_id = result["clientid"].get(); m_user_name = ""; m_password = ""; m_ca = result["ca"].get(); m_cert = result["cert"].get(); m_key = result["key"].get(); m_port = result["port"].get(); auth_promise.set_value(true); } catch(std::exception& e){ auth_promise.set_value(false); } }; auto timeout_callback = [this, &auth_promise]() { // 待调整 auth_promise.set_value(false); }; if (!add_response_target(seq_id, callback, timeout_callback, std::chrono::seconds(60))) { return false; } body["id"] = seq_id; std::string pub_msg = ""; if(!m_mqtt_client->Publish(auth_code + m_auth_req_topic, body.dump(), 1, pub_msg)){ return false; } // 等待response auto status = auth_future.wait_for(std::chrono::seconds(70)); if(status == std::future_status::timeout){ return false; } return auth_future.get(); } // Connect to MQTT broker bool Moonraker_Mqtt::connect(wxString& msg, const nlohmann::json& params) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始MQTT连接流程"; wcp_loger.add_log("开始MQTT连接流程", false, "", "Moonraker_Mqtt", "info"); // 在创建新连接前检查参数 if(!params.count("ca") || !params.count("cert") || !params.count("key") || !params.count("port") || !params.count("clientId") || !params.count("sn")){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 缺少TLS参数,尝试获取认证信息"; wcp_loger.add_log("缺少TLS参数,尝试获取认证信息", false, "", "Moonraker_Mqtt", "info"); bool flag = ask_for_tls_info(params); if (!flag) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 获取TLS认证信息失败"; wcp_loger.add_log("获取TLS认证信息失败", false, "", "Moonraker_Mqtt", "error"); return false; } }else{ BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用提供的TLS参数"; wcp_loger.add_log("使用提供的TLS参数", false, "", "Moonraker_Mqtt", "info"); m_user_name = params.count("user") ? params["user"].get() : ""; m_password = params.count("password") ? params["password"].get() : ""; m_ca = params["ca"].get(); m_cert = params["cert"].get(); m_key = params["key"].get(); m_port = params["port"].get(); m_client_id = params["clientId"].get(); m_sn_mtx.lock(); m_sn = params["sn"].get(); m_sn_mtx.unlock(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 设置SN: " << m_sn; wcp_loger.add_log("设置SN: " + m_sn, false, "", "Moonraker_Mqtt", "info"); if (m_ca == "" || m_cert == "" || m_key == "") { bool flag = ask_for_tls_info(params); if (!flag) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 获取TLS认证信息失败"; wcp_loger.add_log("获取TLS认证信息失败", false, "", "Moonraker_Mqtt", "error"); return false; } } } // 验证证书格式 if (!m_ca.empty()) { if (m_ca.find("-----BEGIN CERTIFICATE-----") == std::string::npos) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] CA证书格式不正确"; wcp_loger.add_log("CA证书格式不正确", false, "", "Moonraker_Mqtt", "error"); return false; } BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] CA证书格式验证通过"; wcp_loger.add_log("CA证书格式验证通过", false, "", "Moonraker_Mqtt", "info"); } if (!m_cert.empty()) { if (m_cert.find("-----BEGIN CERTIFICATE-----") == std::string::npos) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 客户端证书格式不正确"; wcp_loger.add_log("客户端证书格式不正确", false, "", "Moonraker_Mqtt", "error"); return false; } BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 客户端证书格式验证通过"; wcp_loger.add_log("客户端证书格式验证通过", false, "", "Moonraker_Mqtt", "info"); } if (!m_key.empty()) { if (m_key.find("-----BEGIN PRIVATE KEY-----") == std::string::npos && m_key.find("-----BEGIN RSA PRIVATE KEY-----") == std::string::npos) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 私钥格式不正确"; wcp_loger.add_log("私钥格式不正确", false, "", "Moonraker_Mqtt", "error"); return false; } BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 私钥格式验证通过"; wcp_loger.add_log("私钥格式验证通过", false, "", "Moonraker_Mqtt", "info"); } // 检查端口号 if (m_port <= 0 || m_port > 65535) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 无效的端口号: " << m_port; wcp_loger.add_log("无效的端口号: " + std::to_string(m_port), false, "", "Moonraker_Mqtt", "error"); return false; } // 记录连接参数(不记录敏感信息的具体内容) BOOST_LOG_TRIVIAL(debug) << "[Moonraker_Mqtt] MQTTS连接参数:" << "\n - 主机: " << m_host << "\n - 端口: " << m_port << "\n - 客户端ID: " << m_client_id << "\n - CA证书是否存在: " << (!m_ca.empty() ? "是" : "否") << "\n - 客户端证书是否存在: " << (!m_cert.empty() ? "是" : "否") << "\n - 私钥是否存在: " << (!m_key.empty() ? "是" : "否"); wcp_loger.add_log("MQTTS连接参数: " + m_host + ":" + std::to_string(m_port) + ", 客户端ID: " + m_client_id + ", CA证书是否存在: " + (!m_ca.empty() ? "是" : "否") + ", 客户端证书是否存在: " + (!m_cert.empty() ? "是" : "否") + ", 私钥是否存在: " + (!m_key.empty() ? "是" : "否"), false, "", "Moonraker_Mqtt", "info"); // 在创建新连接前,确保旧连接已断开 if (m_mqtt_client) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 断开旧的MQTT客户端连接"; wcp_loger.add_log("断开旧的MQTT客户端连接", false, "", "Moonraker_Mqtt", "info"); std::string dc_msg = "success"; m_mqtt_client->Disconnect(dc_msg); std::this_thread::sleep_for(std::chrono::milliseconds(500)); m_mqtt_client.reset(); } if (m_mqtt_client_tls) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 断开旧的MQTTS客户端连接"; wcp_loger.add_log("断开旧的MQTTS客户端连接", false, "", "Moonraker_Mqtt", "info"); std::string dc_msg = "success"; m_mqtt_client_tls->Disconnect(dc_msg); std::this_thread::sleep_for(std::chrono::milliseconds(500)); m_mqtt_client_tls.reset(); } // 创建新的 MQTTS 连接 std::string host_ip = m_host; size_t pos = host_ip.find(":"); if (pos != std::string::npos) { host_ip = host_ip.substr(0, pos); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 提取主机IP: " << host_ip; wcp_loger.add_log("提取主机IP: " + host_ip, false, "", "Moonraker_Mqtt", "info"); } std::string mqtts_url = "mqtts://" + host_ip + ":" + std::to_string(m_port); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 创建MQTTS客户端,URL: " << mqtts_url << ", 客户端ID: " << m_client_id; wcp_loger.add_log("创建MQTTS客户端,URL: " + mqtts_url + ", 客户端ID: " + m_client_id, false, "", "Moonraker_Mqtt", "info"); m_mqtt_client_tls.reset(new MqttClient(mqtts_url, m_client_id, m_ca, m_cert, m_key)); if (!m_mqtt_client_tls) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] MQTT客户端创建失败"; wcp_loger.add_log("MQTT客户端创建失败", false, "", "Moonraker_Mqtt", "error"); return false; } std::string connection_msg = ""; bool is_connect = m_mqtt_client_tls->Connect(connection_msg); msg = connection_msg; if (!is_connect) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] MQTT连接失败"; wcp_loger.add_log("MQTT连接失败", false, "", "Moonraker_Mqtt", "error"); return false; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] MQTTS连接成功"; wcp_loger.add_log("MQTTS连接成功", false, "", "Moonraker_Mqtt", "info"); m_sn_mtx.lock(); std::string tmp_sn = m_sn; m_sn_mtx.unlock(); if(tmp_sn == ""){ BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] SN为空,无法订阅主题"; wcp_loger.add_log("SN为空,无法订阅主题", false, "", "Moonraker_Mqtt", "error"); return false; } std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::string no_sub_msg = "success"; bool notification_subscribed = m_mqtt_client_tls->Subscribe(tmp_sn + m_notification_topic, 1, no_sub_msg); std::string res_sub_msg = "success"; bool response_subscribed = m_mqtt_client_tls->Subscribe(tmp_sn + m_response_topic, 1, res_sub_msg); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 订阅主题结果 - 通知主题: " << (notification_subscribed ? "成功" : "失败") << ", 响应主题: " << (response_subscribed ? "成功" : "失败"); wcp_loger.add_log("订阅主题结果 - 通知主题: " + std::string((notification_subscribed ? "成功" : "失败")) + ", 响应主题: " + (response_subscribed ? "成功" : "失败"), false, "", "Moonraker_Mqtt", "info"); m_mqtt_client_tls->SetMessageCallback([this](const std::string& topic, const std::string& payload) { this->on_mqtt_tls_message_arrived(topic, payload); }); bool result = is_connect && notification_subscribed && response_subscribed; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] MQTT连接流程完成,结果: " << (result ? "成功" : "失败"); wcp_loger.add_log("MQTT连接流程完成,结果: " + std::string((result ? "成功" : "失败")), false, "", "Moonraker_Mqtt", "info"); return result; } // Disconnect from MQTT broker bool Moonraker_Mqtt::disconnect(wxString& msg, const nlohmann::json& params) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始断开MQTT连接"; wcp_loger.add_log("开始断开MQTT连接", false, "", "Moonraker_Mqtt", "info"); if (!m_mqtt_client_tls) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] MQTTS客户端不存在,无需断开"; wcp_loger.add_log("MQTTS客户端不存在,无需断开", false, "", "Moonraker_Mqtt", "info"); return false; } std::string dc_msg = "success"; bool flag = m_mqtt_client_tls->Disconnect(dc_msg); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] MQTTS断开连接结果: " << (flag ? "成功" : "失败"); wcp_loger.add_log("MQTTS断开连接结果: " + std::string((flag ? "成功" : "失败")), false, "", "Moonraker_Mqtt", "info"); if (flag) { m_status_cbs.clear(); m_notification_cbs.clear(); } m_sn_mtx.lock(); m_sn = ""; m_sn_mtx.unlock(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 重置SN"; wcp_loger.add_log("重置SN", false, "", "Moonraker_Mqtt", "info"); // 等待一段时间让MQTT客户端完成清理,避免内存访问问题 std::this_thread::sleep_for(std::chrono::milliseconds(100)); m_mqtt_client_tls.reset(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] MQTTS客户端已重置"; wcp_loger.add_log("MQTTS客户端已重置", false, "", "Moonraker_Mqtt", "info"); return flag; } // Subscribe to printer status updates void Moonraker_Mqtt::async_subscribe_machine_info(const std::string& hash, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始订阅机器状态信息"; wcp_loger.add_log("开始订阅机器状态信息", false, "", "Moonraker_Mqtt", "info"); if (m_status_cbs.empty()) { std::string main_layer = "+"; m_sn_mtx.lock(); main_layer = m_sn; m_sn_mtx.unlock(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 使用SN主题: " << main_layer; wcp_loger.add_log("使用SN主题: " + main_layer, false, "", "Moonraker_Mqtt", "info"); std::string sub_msg = "success"; bool res_status = m_mqtt_client_tls ? m_mqtt_client_tls->Subscribe(main_layer + m_status_topic, 1, sub_msg) : false; bool res_notification = m_mqtt_client_tls ? m_mqtt_client_tls->Subscribe(main_layer + m_notification_topic, 1, sub_msg) : false; if (!res_status || !res_notification) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 订阅状态主题失败"; wcp_loger.add_log("订阅状态主题失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); return; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 成功订阅状态主题: " << main_layer + m_status_topic; wcp_loger.add_log("成功订阅状态主题: " + main_layer + m_status_topic, false, "", "Moonraker_Mqtt", "info"); } m_status_cbs.insert({hash, callback}); m_notification_cbs.insert({hash, callback}); callback(json::object()); } // start print job void Moonraker_Mqtt::async_start_print_job(const std::string& filename, std::function cb) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始启动打印任务,文件名: " << filename; wcp_loger.add_log("开始启动打印任务,文件名: " + filename, false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.print.start"; json params = json::object(); params["filename"] = filename; if (!send_to_request(method, params, true, cb, [cb, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 启动打印任务超时"; wcp_loger.add_log("启动打印任务超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; cb(res); }) && cb) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送启动打印请求失败"; wcp_loger.add_log("发送启动打印请求失败", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); } } void Moonraker_Mqtt::async_pause_print_job(std::function cb) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始暂停打印任务"; wcp_loger.add_log("开始暂停打印任务", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.print.pause"; json params = json::object(); if (!send_to_request(method, params, true, cb, [cb, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 暂停打印任务超时"; wcp_loger.add_log("暂停打印任务超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; cb(res); }) && cb) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送暂停打印请求失败"; wcp_loger.add_log("发送暂停打印请求失败", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); } } void Moonraker_Mqtt::async_resume_print_job(std::function cb) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始恢复打印任务"; wcp_loger.add_log("开始恢复打印任务", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.print.resume"; json params = json::object(); if (!send_to_request(method, params, true, cb, [cb, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 恢复打印任务超时"; wcp_loger.add_log("恢复打印任务超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; cb(res); }) && cb) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送恢复打印请求失败"; wcp_loger.add_log("发送恢复打印请求失败", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); } } void Moonraker_Mqtt::test_async_wcp_mqtt_moonraker(const nlohmann::json& mqtt_request_params, std::function cb) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始测试MQTT Moonraker异步请求"; wcp_loger.add_log("开始测试MQTT Moonraker异步请求", false, "", "Moonraker_Mqtt", "info"); int64_t id = -1; if (!mqtt_request_params.count("id") || !mqtt_request_params[id].is_number()) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 测试请求缺少有效ID"; wcp_loger.add_log("测试请求缺少有效ID", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); return; } id = mqtt_request_params["id"].get(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 测试请求ID: " << id; wcp_loger.add_log("测试请求ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "info"); if (id == -1) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 无效的请求ID"; wcp_loger.add_log("无效的请求ID", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); return; } if (!add_response_target(id, cb, [cb, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 测试请求超时"; wcp_loger.add_log("测试请求超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; cb(res); })){ BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 添加响应目标失败"; wcp_loger.add_log("添加响应目标失败", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); } if (m_mqtt_client_tls) { std::string main_layer = "+"; if (wait_for_sn()) { m_sn_mtx.lock(); main_layer = m_sn; m_sn_mtx.unlock(); if (main_layer == "+" || main_layer == "") { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] SN无效,删除响应目标"; wcp_loger.add_log("SN无效,删除响应目标", false, "", "Moonraker_Mqtt", "error"); delete_response_target(id); cb(json::value_t::null); return; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 发布测试请求到主题: " << main_layer + m_request_topic; wcp_loger.add_log("发布测试请求到主题: " + main_layer + m_request_topic, false, "", "Moonraker_Mqtt", "info"); std::string pub_msg = "success"; bool res = m_mqtt_client_tls->Publish(main_layer + m_request_topic, mqtt_request_params.dump(), 1, pub_msg); if (!res) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发布测试请求失败"; wcp_loger.add_log("发布测试请求失败", false, "", "Moonraker_Mqtt", "error"); delete_response_target(id); } else { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 测试请求发布成功"; wcp_loger.add_log("测试请求发布成功", false, "", "Moonraker_Mqtt", "info"); } return; } } } void Moonraker_Mqtt::async_cancel_print_job(std::function cb) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始取消打印任务"; wcp_loger.add_log("开始取消打印任务", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.print.cancel"; json params = json::object(); if (!send_to_request(method, params, true, cb, [cb, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 取消打印任务超时"; wcp_loger.add_log("取消打印任务超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; cb(res); }) && cb) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送取消打印请求失败"; wcp_loger.add_log("发送取消打印请求失败", false, "", "Moonraker_Mqtt", "error"); cb(json::value_t::null); } } // Get printer info void Moonraker_Mqtt::async_get_printer_info(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取打印机信息"; wcp_loger.add_log("开始获取打印机信息", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.info"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取打印机信息超时"; wcp_loger.add_log("获取打印机信息超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取打印机信息请求失败"; wcp_loger.add_log("发送获取打印机信息请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Send G-code commands to printer void Moonraker_Mqtt::async_send_gcodes(const std::vector& scripts, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始发送G代码,数量: " << scripts.size(); wcp_loger.add_log("开始发送G代码,数量: " + std::to_string(scripts.size()), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.gcode.script"; std::string str_scripts = ""; for (size_t i = 0; i < scripts.size(); ++i) { if (i != 0) { str_scripts += "\n"; } str_scripts += scripts[i]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 添加G代码: " << scripts[i]; wcp_loger.add_log("添加G代码: " + scripts[i], false, "", "Moonraker_Mqtt", "info"); } json params; params["script"] = str_scripts; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger](){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 发送G代码超时"; wcp_loger.add_log("发送G代码超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送G代码请求失败"; wcp_loger.add_log("发送G代码请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Unsubscribe from printer status updates void Moonraker_Mqtt::async_unsubscribe_machine_info(const std::string& hash, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始取消订阅机器状态信息"; wcp_loger.add_log("开始取消订阅机器状态信息", false, "", "Moonraker_Mqtt", "info"); if (m_status_cbs.count(hash)) m_status_cbs.erase(hash); if (m_notification_cbs.count(hash)) m_notification_cbs.erase(hash); if (m_status_cbs.empty()) { std::string main_layer = "+"; m_sn_mtx.lock(); main_layer = m_sn; m_sn_mtx.unlock(); std::string un_sub_msg = "success"; bool res = m_mqtt_client_tls ? m_mqtt_client_tls->Unsubscribe(main_layer + m_status_topic, un_sub_msg) : false; if (!res) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 取消订阅状态主题失败"; wcp_loger.add_log("取消订阅状态主题失败", false, "", "Moonraker_Mqtt", "error"); if (callback) { callback(json::value_t::null); } return; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 成功取消订阅状态主题: " << main_layer + m_status_topic; wcp_loger.add_log("成功取消订阅状态主题: " + main_layer + m_status_topic, false, "", "Moonraker_Mqtt", "info"); callback(json::object()); } else { callback(json::object()); } } // Set filters for printer status subscription void Moonraker_Mqtt::async_set_machine_subscribe_filter( const std::vector>>& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始设置机器订阅过滤器,目标数量: " << targets.size(); wcp_loger.add_log("开始设置机器订阅过滤器,目标数量: " + std::to_string(targets.size()), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.objects.subscribe"; json params; params["objects"] = json::object(); for (size_t i = 0; i < targets.size(); ++i) { if (targets[i].second.size() == 0) { params["objects"][targets[i].first] = json::value_t::null; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 添加过滤器(全部): " << targets[i].first; wcp_loger.add_log("添加过滤器(全部): " + targets[i].first, false, "", "Moonraker_Mqtt", "info"); } else { params["objects"][targets[i].first] = json::array(); for (const auto& key : targets[i].second) { params["objects"][targets[i].first].push_back(key); } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 添加过滤器: " << targets[i].first << ", 字段数量: " << targets[i].second.size(); wcp_loger.add_log("添加过滤器: " + targets[i].first + ", 字段数量: " + std::to_string(targets[i].second.size()), false, "", "Moonraker_Mqtt", "info"); } } if (!send_to_request(method, params, true, callback, [callback, &wcp_loger](){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 设置订阅过滤器超时"; wcp_loger.add_log("设置订阅过滤器超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送设置订阅过滤器请求失败"; wcp_loger.add_log("发送设置订阅过滤器请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_machine_files_roots(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取文件系统根目录"; wcp_loger.add_log("开始获取文件系统根目录", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.roots"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取文件系统根目录超时"; wcp_loger.add_log("获取文件系统根目录超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取文件系统根目录请求失败"; wcp_loger.add_log("发送获取文件系统根目录请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_machine_files_metadata(const std::string& filename, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取文件元数据,文件名: " << filename; wcp_loger.add_log("开始获取文件元数据,文件名: " + filename, false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.metadata"; json params; params["filename"] = filename; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取文件元数据超时"; wcp_loger.add_log("获取文件元数据超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取文件元数据请求失败"; wcp_loger.add_log("发送获取文件元数据请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_set_device_name(const std::string& device_name, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始设置设备名称,名称: " << device_name; wcp_loger.add_log("开始设置设备名称,名称: " + device_name, false, "", "Moonraker_Mqtt", "info"); std::string method = "machine.set_device_name"; json params; params["name"] = device_name; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 设置设备名称超时"; wcp_loger.add_log("设置设备名称超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送设置设备名称请求失败"; wcp_loger.add_log("发送设置设备名称请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_led(const std::string& name, int white, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制LED,名称: " << name << ", 白色亮度: " << white; wcp_loger.add_log("开始控制LED,名称: " + name + ", 白色亮度: " + std::to_string(white), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.led"; json params; params["name"] = name; params["white"] = white; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制LED超时"; wcp_loger.add_log("控制LED超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制LED请求失败"; wcp_loger.add_log("发送控制LED请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_print_speed(int percentage, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制打印速度,百分比: " << percentage; wcp_loger.add_log("开始控制打印速度,百分比: " + std::to_string(percentage), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.print_speed"; json params; params["percentage"] = percentage; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制打印速度超时"; wcp_loger.add_log("控制打印速度超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制打印速度请求失败"; wcp_loger.add_log("发送控制打印速度请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_bedmesh_abort_probe_mesh(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始中止热床调平"; wcp_loger.add_log("开始中止热床调平 ", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.bed_mesh.abort_probe_mesh"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 中止热床调平"; wcp_loger.add_log("中止热床调平", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送中止热床调平请求失败"; wcp_loger.add_log("发送中止热床调平请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_controlPurifier(int fan_speed, int delay_time, int work_time, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制空气净化器,风速: " << fan_speed << ", 延时: " << delay_time << ", 工作时间: " << work_time; wcp_loger.add_log("开始控制空气净化器,风速: " + std::to_string(fan_speed) + ", 延时: " + std::to_string(delay_time) + ", 工作时间: " + std::to_string(work_time), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.purifier"; json params; if (fan_speed != -1) params["fan_speed"] = fan_speed; if (delay_time != -1) params["delay_time"] = delay_time; if (work_time != -1) params["work_time"] = work_time; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制空气净化器超时"; wcp_loger.add_log("控制空气净化器超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制空气净化器请求失败"; wcp_loger.add_log("发送控制空气净化器请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_main_fan(int speed, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制主风扇,速度: " << speed; wcp_loger.add_log("开始控制主风扇,速度: " + std::to_string(speed), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.main_fan"; json params; params["speed"] = speed; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制主风扇超时"; wcp_loger.add_log("控制主风扇超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制主风扇请求失败"; wcp_loger.add_log("发送控制主风扇请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_generic_fan(const std::string& name, int speed, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制通用风扇,名称: " << name << ", 速度: " << speed; wcp_loger.add_log("开始控制通用风扇,名称: " + name + ", 速度: " + std::to_string(speed), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.generic_fan"; json params; params["name"] = name; params["speed"] = speed; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制通用风扇超时"; wcp_loger.add_log("控制通用风扇超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制通用风扇请求失败"; wcp_loger.add_log("发送控制通用风扇请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_bed_temp(int temp, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制热床温度,目标温度: " << temp; wcp_loger.add_log("开始控制热床温度,目标温度: " + std::to_string(temp), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.bed_temp"; json params; params["temp"] = temp; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制热床温度超时"; wcp_loger.add_log("控制热床温度超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制热床温度请求失败"; wcp_loger.add_log("发送控制热床温度请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_control_extruder_temp(int temp, int index, int map, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始控制挤出机温度,目标温度: " << temp << ", 挤出机索引: " << index; wcp_loger.add_log("开始控制挤出机温度,目标温度: " + std::to_string(temp) + ", 挤出机索引: " + std::to_string(index), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.control.extruder_temp"; json params; params["temp"] = temp; if (index != -1) params["index"] = index; if (map != -1) params["map"] = map; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 控制挤出机温度超时"; wcp_loger.add_log("控制挤出机温度超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送控制挤出机温度请求失败"; wcp_loger.add_log("发送控制挤出机温度请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_files_thumbnails_base64(const std::string& path, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取文件缩略图,路径: " << path; wcp_loger.add_log("开始获取文件缩略图,路径: " + path, false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.thumbnails_base64"; json params; params["path"] = path; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取文件缩略图超时"; wcp_loger.add_log("获取文件缩略图超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取文件缩略图请求失败"; wcp_loger.add_log("发送获取文件缩略图请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_get_file_page_list(const std::string& root, int files_per_page, int page_number, std::function callback){ auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始按页获取文件"; wcp_loger.add_log("开始按页获取文件", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.list_page"; json params; params["root"] = root; params["files_per_page"] = files_per_page; params["page_number"] = page_number; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 按页获取文件超时"; wcp_loger.add_log("按页获取文件超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 按页获取文件失败"; wcp_loger.add_log("按页获取文件失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_exception_query(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始查询异常状态"; wcp_loger.add_log("开始查询异常状态", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.exception.query"; json params; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 查询异常状态超时"; wcp_loger.add_log("查询异常状态超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 查询异常状态失败"; wcp_loger.add_log("查询异常状态失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_server_client_manager_set_userinfo(const nlohmann::json& user, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始设置已绑定用户信息"; wcp_loger.add_log("开始设置已绑定用户信息", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.client_manager.set_userinfo"; if (!user.count("auther") || !user["auther"].count("id") || !user["auther"].count("nickname")) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 设置已绑定用户信息失败,id或nickname不存在"; wcp_loger.add_log("设置已绑定用户信息失败,id或nickname不存在", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); return; } json params = user; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 设置已绑定用户信息超时"; wcp_loger.add_log("设置已绑定用户信息超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送设置已绑定用户信息请求失败"; wcp_loger.add_log("发送设置已绑定用户信息请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_machine_files_thumbnails(const std::string& filename, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取文件缩略图,文件名: " << filename; wcp_loger.add_log("开始获取文件缩略图,文件名: " + filename, false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.thumbnails"; json params; params["filename"] = filename; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取文件缩略图超时"; wcp_loger.add_log("获取文件缩略图超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取文件缩略图请求失败"; wcp_loger.add_log("发送获取文件缩略图请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_machine_files_directory(const std::string& path, bool extend, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取目录内容,路径: " << path << ", 扩展信息: " << extend; wcp_loger.add_log("开始获取目录内容,路径: " + path + ", 扩展信息: " + std::to_string(extend), false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.get_directory"; json params; params["path"] = path; params["extended"] = extend; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取目录内容超时"; wcp_loger.add_log("获取目录内容超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取目录内容请求失败"; wcp_loger.add_log("发送获取目录内容请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_camera_start(const std::string& domain, int interval, bool expect_pw, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始启动摄像头监控,域名: " << domain; wcp_loger.add_log("开始启动摄像头监控,域名: " + domain, false, "", "Moonraker_Mqtt", "info"); std::string method = "camera.start_monitor"; json params; params["domain"] = domain; params["interval"] = interval; params["expect_pw"] = expect_pw; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 启动摄像头监控超时"; wcp_loger.add_log("启动摄像头监控超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送启动摄像头监控请求失败"; wcp_loger.add_log("发送启动摄像头监控请求失败", false, "", "Moonraker_Mqtt", "error"); sentryReportLog(SENTRY_LOG_TRACE, "bury_point_open video cmd error", BP_VIDEO_ABNORMAL); callback(json::value_t::null); } } void Moonraker_Mqtt::async_delete_machine_file(const std::string& path, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始删除文件,路径: " << path; wcp_loger.add_log("开始删除文件,路径: " + path, false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.delete_file"; json params; params["path"] = path; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 删除文件超时"; wcp_loger.add_log("删除文件超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送删除文件请求失败"; wcp_loger.add_log("发送删除文件请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_canmera_stop(const std::string& domain, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始停止摄像头监控,域名: " << domain; wcp_loger.add_log("开始停止摄像头监控,域名: " + domain, false, "", "Moonraker_Mqtt", "info"); std::string method = "camera.stop_monitor"; json params; params["domain"] = domain; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 停止摄像头监控超时"; wcp_loger.add_log("停止摄像头监控超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送停止摄像头监控请求失败"; wcp_loger.add_log("发送停止摄像头监控请求失败", false, "", "Moonraker_Mqtt", "error"); sentryReportLog(SENTRY_LOG_TRACE, "bury_point_stop video cmd error", BP_VIDEO_ABNORMAL); callback(json::value_t::null); } } // 请求上传延时摄影文件 void Moonraker_Mqtt::async_upload_camera_timelapse(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求上传延时摄影文件"; wcp_loger.add_log("开始请求上传延时摄影文件", false, "", "Moonraker_Mqtt", "info"); std::string method = "camera.upload_timelapse_instance"; json params = json::object(); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求上传延时摄影文件超时"; wcp_loger.add_log("请求上传延时摄影文件超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求上传延时摄影文件失败"; wcp_loger.add_log("发送请求上传延时摄影文件失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // 获取延时摄影列表 void Moonraker_Mqtt::async_get_timelapse_instance(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求获取延时摄影文件列表"; wcp_loger.add_log("开始请求获取延时摄影文件列表", false, "", "Moonraker_Mqtt", "info"); std::string method = "camera.get_timelapse_instance"; json params = json::object(); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求获取延时摄影文件列表超时"; wcp_loger.add_log("请求获取延时摄影文件列表超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求获取延时摄影文件列表失败"; wcp_loger.add_log("发送请求获取延时摄影文件列表失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // 请求删除延时摄影文件 void Moonraker_Mqtt::async_delete_camera_timelapse(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求删除延时摄影文件"; wcp_loger.add_log("开始请求删除延时摄影文件", false, "", "Moonraker_Mqtt", "info"); std::string method = "camera.delete_timelapse_instance"; json params = json::object(); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求删除延时摄影文件超时"; wcp_loger.add_log("请求删除延时摄影文件超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求删除延时摄影文件失败"; wcp_loger.add_log("发送请求删除延时摄影文件失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // 请求缺陷检测配置 void Moonraker_Mqtt::async_defect_detaction_config(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求缺陷检测配置"; wcp_loger.add_log("开始请求缺陷检测配置", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.defect_detection.config"; json params = json::object(); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求缺陷检测配置超时"; wcp_loger.add_log("请求缺陷检测配置超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求缺陷检测配置失败"; wcp_loger.add_log("发送请求缺陷检测配置失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // 请求设备下载云文件并打印 void Moonraker_Mqtt::async_start_cloud_print(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求设备开始云打印"; wcp_loger.add_log("开始请求设备云打印", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.start_cloud_print"; json params = json::object(); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求设备云打印超时"; wcp_loger.add_log("请求设备云打印超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求设备开启云打印失败"; wcp_loger.add_log("发送请求设备开启云打印失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // 请求设备开启云打印 void Moonraker_Mqtt::async_pull_cloud_file(const nlohmann::json& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始请求设备下载云文件"; wcp_loger.add_log("开始请求设备下载云文件", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.pull"; json params = json::object(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 添加云文件下载目标, 属性数量: " << targets.size(); wcp_loger.add_log("添加云文件下载目标, 属性数量: " + std::to_string(targets.size()), false, "", "Moonraker_Mqtt", "info"); params = targets; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求设备下载文件超时"; wcp_loger.add_log("请求设备下载文件超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送请求设备下载文件超时请求失败"; wcp_loger.add_log("发送请求设备下载文件超时请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } void Moonraker_Mqtt::async_cancel_pull_cloud_file(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 请求设备取消上传"; wcp_loger.add_log("请求设备取消上传", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.cancel_pull"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 请求设备取消上传超时"; wcp_loger.add_log("请求设备取消上传超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送设备取消上传请求失败"; wcp_loger.add_log("发送设备取消上传请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Query device information (firmware version) // Query printer information void Moonraker_Mqtt::async_get_device_info(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始查询固件信息"; wcp_loger.add_log("开始查询固件信息", false, "", "Moonraker_Mqtt", "info"); std::string method = "system.get_device_info"; json params; if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 查询固件信息超时"; wcp_loger.add_log("查询固件信息超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送查询固件信息请求失败"; wcp_loger.add_log("发送查询固件信息请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Query printer information void Moonraker_Mqtt::async_get_machine_info( const std::vector>>& targets, std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始查询打印机信息,目标数量: " << targets.size(); wcp_loger.add_log("开始查询打印机信息,目标数量: " + std::to_string(targets.size()), false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.objects.query"; json params; params["objects"] = json::object(); for (size_t i = 0; i < targets.size(); ++i) { if (targets[i].second.size() == 0) { params["objects"][targets[i].first] = json::value_t::null; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 查询对象(全部属性): " << targets[i].first; wcp_loger.add_log("查询对象(全部属性): " + targets[i].first, false, "", "Moonraker_Mqtt", "info"); } else { params["objects"][targets[i].first] = json::array(); for (const auto& key : targets[i].second) { params["objects"][targets[i].first].push_back(key); } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 查询对象: " << targets[i].first << ", 属性数量: " << targets[i].second.size(); wcp_loger.add_log("查询对象: " + targets[i].first + ", 属性数量: " + std::to_string(targets[i].second.size()), false, "", "Moonraker_Mqtt", "info"); } } if (!send_to_request(method, params, true, callback, [callback, &wcp_loger](){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 查询打印机信息超时"; wcp_loger.add_log("查询打印机信息超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送查询打印机信息请求失败"; wcp_loger.add_log("发送查询打印机信息请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Get File state void Moonraker_Mqtt::async_server_files_get_status(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取系统文件状态"; wcp_loger.add_log("开始获取系统文件状态信息", false, "", "Moonraker_Mqtt", "info"); std::string method = "server.files.get_status"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger]() { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取系统文件状态超时"; wcp_loger.add_log("获取系统文件状态超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取系统文件状态请求失败"; wcp_loger.add_log("发送获取系统文件状态请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Get system info of the machine void Moonraker_Mqtt::async_get_system_info(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取系统信息"; wcp_loger.add_log("开始获取系统信息", false, "", "Moonraker_Mqtt", "info"); std::string method = "machine.system_info"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger](){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取系统信息超时"; wcp_loger.add_log("获取系统信息超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取系统信息请求失败"; wcp_loger.add_log("发送获取系统信息请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Get list of available printer objects void Moonraker_Mqtt::async_get_machine_objects(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 开始获取可用打印机对象列表"; wcp_loger.add_log("开始获取可用打印机对象列表", false, "", "Moonraker_Mqtt", "info"); std::string method = "printer.objects.list"; json params = json::object(); if (!send_to_request(method, params, true, callback, [callback, &wcp_loger](){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 获取打印机对象列表超时"; wcp_loger.add_log("获取打印机对象列表超时", false, "", "Moonraker_Mqtt", "warning"); json res; res["error"] = "timeout"; callback(res); }) && callback) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发送获取打印机对象列表请求失败"; wcp_loger.add_log("发送获取打印机对象列表请求失败", false, "", "Moonraker_Mqtt", "error"); callback(json::value_t::null); } } // Send request to printer via MQTT bool Moonraker_Mqtt::send_to_request( const std::string& method, const json& params, bool need_response, std::function callback, std::function timeout_callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 发送请求,方法: " << method << ", 需要响应: " << need_response; wcp_loger.add_log("发送请求,方法: " + method + ", 需要响应: " + std::to_string(need_response), false, "", "Moonraker_Mqtt", "info"); json body; body["jsonrpc"] = "2.0"; body["method"] = method; if (!params.empty()) { body["params"] = params; } int64_t seq_id = m_seq_generator.generate_seq_id(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 生成序列ID: " << seq_id; wcp_loger.add_log("生成序列ID: " + std::to_string(seq_id), false, "", "Moonraker_Mqtt", "info"); if (need_response) { if (!add_response_target(seq_id, callback, timeout_callback)) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 添加响应目标失败"; wcp_loger.add_log("添加响应目标失败", false, "", "Moonraker_Mqtt", "error"); return false; } body["id"] = seq_id; } if (m_mqtt_client_tls) { std::string main_layer = "+"; m_sn_mtx.lock(); main_layer = m_sn; m_sn_mtx.unlock(); if (main_layer == "+" || main_layer == "") { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] SN无效,删除响应目标"; wcp_loger.add_log("SN无效,删除响应目标", false, "", "Moonraker_Mqtt", "error"); delete_response_target(seq_id); return false; } std::string topic = main_layer + m_request_topic; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 发布到主题: " << topic; wcp_loger.add_log("发布到主题: " + topic, false, "", "Moonraker_Mqtt", "info"); std::string pub_msg = "success"; bool res = m_mqtt_client_tls->Publish(topic, body.dump(), 1, pub_msg); if (!res) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 发布请求失败,方法: " << method; wcp_loger.add_log("发布请求失败,方法: " + method, false, "", "Moonraker_Mqtt", "error"); delete_response_target(seq_id); } else { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 请求发布成功,方法: " << method; wcp_loger.add_log("请求发布成功,方法: " + method, false, "", "Moonraker_Mqtt", "info"); } return res; } BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] MQTTS客户端不可用"; wcp_loger.add_log("MQTTS客户端不可用", false, "", "Moonraker_Mqtt", "error"); return false; } // Register callback for response to a request bool Moonraker_Mqtt::add_response_target( int64_t id, std::function callback, std::function timeout_callback, std::chrono::milliseconds timeout) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 注册响应回调,ID: " << id << ", 超时: " << timeout.count() << "ms"; wcp_loger.add_log("注册响应回调,ID: " + std::to_string(id) + ", 超时: " + std::to_string(timeout.count()) + "ms", false, "", "Moonraker_Mqtt", "info"); return m_request_cb_map.add( id, RequestCallback(std::move(callback), std::move(timeout_callback)), timeout ); } // Remove registered callback void Moonraker_Mqtt::delete_response_target(int64_t id) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 删除响应目标,ID: " << id; wcp_loger.add_log("删除响应目标,ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "info"); m_request_cb_map.remove(id); } bool Moonraker_Mqtt::check_sn_arrived() { auto& wcp_loger = GUI::WCP_Logger::getInstance(); bool result = wait_for_sn(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 检查SN到达状态: " << (result ? "已到达" : "未到达"); wcp_loger.add_log("检查SN到达状态: " + std::string((result ? "已到达" : "未到达")), false, "", "Moonraker_Mqtt", "info"); return result; } // Get and remove callback for a request std::function Moonraker_Mqtt::get_request_callback(int64_t id) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 获取并移除请求回调,ID: " << id; wcp_loger.add_log("获取并移除请求回调,ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "info"); auto request_cb = m_request_cb_map.get_and_remove(id); return request_cb ? request_cb->success_cb : nullptr; } // Handle incoming MQTTs messages void Moonraker_Mqtt::on_mqtt_tls_message_arrived(const std::string& topic, const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 收到MQTTS消息,主题: " << topic << ", 载荷长度: " << payload.length(); wcp_loger.add_log("收到MQTTS消息,主题: " + topic + ", 载荷长度: " + std::to_string(payload.length()), false, "", "Moonraker_Mqtt", "info"); try { if (topic.find(m_response_topic) != std::string::npos) { size_t pos = topic.find("/response"); if (pos != std::string::npos) { std::string sn = topic.substr(0, pos); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 从响应主题提取SN: " << sn; wcp_loger.add_log("从响应主题提取SN: " + sn, false, "", "Moonraker_Mqtt", "info"); m_sn_mtx.lock(); m_sn = sn; m_sn_mtx.unlock(); } on_response_arrived(payload); } else if (topic.find(m_status_topic) != std::string::npos) { size_t pos = topic.find("/status"); if (pos != std::string::npos) { std::string sn = topic.substr(0, pos); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 从状态主题提取SN: " << sn; wcp_loger.add_log("从状态主题提取SN: " + sn, false, "", "Moonraker_Mqtt", "info"); m_sn_mtx.lock(); m_sn = sn; m_sn_mtx.unlock(); } on_status_arrived(payload); } else if (topic.find(m_notification_topic) != std::string::npos) { size_t pos = topic.find("/notification"); if (pos != std::string::npos) { std::string sn = topic.substr(0, pos); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 从通知主题提取SN: " << sn; wcp_loger.add_log("从通知主题提取SN: " + sn, false, "", "Moonraker_Mqtt", "info"); m_sn_mtx.lock(); m_sn = sn; m_sn_mtx.unlock(); } on_notification_arrived(payload); } else { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 收到未知主题的消息: " << topic; wcp_loger.add_log("收到未知主题的消息: " + topic, false, "", "Moonraker_Mqtt", "warning"); return; } } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理MQTTS消息异常: " << e.what(); wcp_loger.add_log("处理MQTTS消息异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // Handle incoming MQTT messages void Moonraker_Mqtt::on_mqtt_message_arrived(const std::string& topic, const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 收到MQTT消息,主题: " << topic << ", 载荷长度: " << payload.length(); wcp_loger.add_log("收到MQTT消息,主题: " + topic + ", 载荷长度: " + std::to_string(payload.length()), false, "", "Moonraker_Mqtt", "info"); try { if (topic.find(m_auth_topic) != std::string::npos) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 处理认证响应消息"; wcp_loger.add_log("处理认证响应消息", false, "", "Moonraker_Mqtt", "info"); on_auth_arrived(payload); } else { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 收到未知主题的MQTT消息: " << topic; wcp_loger.add_log("收到未知主题的MQTT消息: " + topic, false, "", "Moonraker_Mqtt", "warning"); return; } } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理MQTT消息异常: " << e.what(); wcp_loger.add_log("处理MQTT消息异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // Handle auth messages void Moonraker_Mqtt::on_auth_arrived(const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 处理认证到达消息"; wcp_loger.add_log("处理认证到达消息", false, "", "Moonraker_Mqtt", "info"); try { json body = json::parse(payload); if(!body.count("id")){ BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 认证响应缺少ID字段"; wcp_loger.add_log("认证响应缺少ID字段", false, "", "Moonraker_Mqtt", "warning"); return; } int64_t id = body["id"].get(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 认证响应ID: " << id; wcp_loger.add_log("认证响应ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "info"); auto cb = get_request_callback(id); delete_response_target(id); if (!cb) { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 未找到对应的认证回调"; wcp_loger.add_log("未找到对应的认证回调", false, "", "Moonraker_Mqtt", "warning"); return; } json res = body["result"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 认证响应处理完成"; wcp_loger.add_log("认证响应处理完成", false, "", "Moonraker_Mqtt", "info"); cb(res); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理认证响应异常: " << e.what(); wcp_loger.add_log("处理认证响应异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // Handle response messages void Moonraker_Mqtt::on_response_arrived(const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 处理响应到达消息"; wcp_loger.add_log("处理响应到达消息", false, "", "Moonraker_Mqtt", "info"); try { json body = json::parse(payload); if (!body.count("id")) { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 响应消息缺少ID字段"; wcp_loger.add_log("响应消息缺少ID字段", false, "", "Moonraker_Mqtt", "warning"); return; } int64_t id = -1; id = body["id"].get(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 响应ID: " << id; wcp_loger.add_log("响应ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "info"); auto cb = get_request_callback(id); delete_response_target(id); if (!cb) { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 未找到对应的响应回调,ID: " << id; wcp_loger.add_log("未找到对应的响应回调,ID: " + std::to_string(id), false, "", "Moonraker_Mqtt", "warning"); return; } json res; if (/*id.find("mqtt") != std::string::npos*/ id == 20252025) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 特殊MQTT请求,直接返回原始响应"; wcp_loger.add_log("特殊MQTT请求,直接返回原始响应", false, "", "Moonraker_Mqtt", "info"); cb(body); } else { if (!body.count("result")) { if (body.count("error")) { json error = body["error"]; res["error"] = error; BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 响应包含错误信息"; wcp_loger.add_log("响应包含错误信息", false, "", "Moonraker_Mqtt", "warning"); } } else { res["data"] = body["result"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 响应包含结果数据"; wcp_loger.add_log("响应包含结果数据", false, "", "Moonraker_Mqtt", "info"); } res["method"] = ""; if (body.count("method")) { res["method"] = body["method"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 响应包含方法: " << body["method"].get(); wcp_loger.add_log("响应包含方法: " + body["method"].get(), false, "", "Moonraker_Mqtt", "info"); } cb(res); } } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理响应消息异常: " << e.what(); wcp_loger.add_log("处理响应消息异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // Handle status update messages void Moonraker_Mqtt::on_status_arrived(const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 处理状态更新消息"; wcp_loger.add_log("处理状态更新消息", false, "", "Moonraker_Mqtt", "info"); try { json body = json::parse(payload); json data; if (body.count("params")) { data["data"] = body["params"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含参数"; wcp_loger.add_log("状态更新包含参数", false, "", "Moonraker_Mqtt", "info"); } else if (body.count("result") && body["result"].count("status")) { data["data"] = body["result"]["status"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含结果状态"; wcp_loger.add_log("状态更新包含结果状态", false, "", "Moonraker_Mqtt", "info"); } else { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新消息格式无效"; wcp_loger.add_log("状态更新消息格式无效", false, "", "Moonraker_Mqtt", "info"); return; } // test: 如果有method,则进行传递 data["method"] = ""; if (body.count("method")){ data["method"] = body["method"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含方法: " << body["method"].get(); wcp_loger.add_log("状态更新包含方法: " + body["method"].get(), false, "", "Moonraker_Mqtt", "info"); } if (m_status_cbs.empty()) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态回调未设置"; wcp_loger.add_log("状态回调未设置", false, "", "Moonraker_Mqtt", "info"); return; } BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 调用状态回调"; wcp_loger.add_log("调用状态回调", false, "", "Moonraker_Mqtt", "info"); for (const auto& func : m_status_cbs) { func.second(data); } } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理状态更新异常: " << e.what(); wcp_loger.add_log("处理状态更新异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // Handle notification messages void Moonraker_Mqtt::on_notification_arrived(const std::string& payload) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 处理通知消息,载荷长度: " << payload.length(); wcp_loger.add_log("处理通知消息,载荷长度: " + std::to_string(payload.length()), false, "", "Moonraker_Mqtt", "info"); try { // TODO: 实现通知消息处理逻辑 json body = json::parse(payload); json data; if (body.count("params")) { data["data"] = body["params"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含参数"; wcp_loger.add_log("状态更新包含参数", false, "", "Moonraker_Mqtt", "info"); } else if (body.count("result") && body["result"].count("status")) { data["data"] = body["result"]["status"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含结果状态"; wcp_loger.add_log("状态更新包含结果状态", false, "", "Moonraker_Mqtt", "info"); } else { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 状态更新消息格式无效"; wcp_loger.add_log("状态更新消息格式无效", false, "", "Moonraker_Mqtt", "warning"); return; } data["method"] = ""; if (body.count("method")) { data["method"] = body["method"]; BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 状态更新包含方法: " << body["method"].get(); wcp_loger.add_log("状态更新包含方法: " + body["method"].get(), false, "", "Moonraker_Mqtt", "info"); } if (m_notification_cbs.empty()) { return; } for (const auto& func : m_notification_cbs) { func.second(data); } } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理通知消息异常: " << e.what(); wcp_loger.add_log("处理通知消息异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error"); } } // 添加一个辅助函数来等待SN bool Moonraker_Mqtt::wait_for_sn(int timeout_seconds) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 等待SN,超时时间: " << timeout_seconds << "秒"; wcp_loger.add_log("等待SN,超时时间: " + std::to_string(timeout_seconds) + "秒", false, "", "Moonraker_Mqtt", "info"); using namespace std::chrono; auto start = steady_clock::now(); while (true) { { std::lock_guard lock(m_sn_mtx); if (!m_sn.empty()) { BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] SN已获取: " << m_sn; wcp_loger.add_log("SN已获取: " + m_sn, false, "", "Moonraker_Mqtt", "info"); return true; } } auto now = steady_clock::now(); if (duration_cast(now - start).count() >= timeout_seconds) { BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 等待SN超时"; wcp_loger.add_log("等待SN超时", false, "", "Moonraker_Mqtt", "warning"); return false; } std::this_thread::sleep_for(milliseconds(100)); } } void Moonraker_Mqtt::set_connection_lost(std::function callback) { auto& wcp_loger = GUI::WCP_Logger::getInstance(); BOOST_LOG_TRIVIAL(warning) << "[Moonraker_Mqtt] 设置连接丢失回调"; wcp_loger.add_log("设置连接丢失回调", false, "", "Moonraker_Mqtt", "info"); if (m_mqtt_client_tls) m_mqtt_client_tls->SetConnectionFailureCallback(callback); } std::string Moonraker_Mqtt::get_sn() { auto& wcp_loger = GUI::WCP_Logger::getInstance(); std::string res = ""; m_sn_mtx.lock(); res = m_sn; m_sn_mtx.unlock(); BOOST_LOG_TRIVIAL(info) << "[Moonraker_Mqtt] 获取SN: " << res; wcp_loger.add_log("获取SN: " + res, false, "", "Moonraker_Mqtt", "info"); return res; } } // namespace Slic3r