Files
OrcaSlicer/src/slic3r/GUI/SSWCP.cpp
2026-02-04 16:35:07 +08:00

6396 lines
229 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Implementation of web communication protocol for Slicer Studio
#include "SSWCP.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "DownloadManager.hpp"
#include "nlohmann/json.hpp"
#include "slic3r/GUI/Tab.hpp"
#include "sentry_wrapper/SentryWrapper.hpp"
#include <algorithm>
#include <iterator>
#include <exception>
#include <cstdlib>
#include <regex>
#include <thread>
#include <string_view>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/asio/ip/host_name.hpp>
#include <slic3r/GUI/Widgets/WebView.hpp>
#include "NetworkTestDialog.hpp"
#include "MoonRaker.hpp"
#include "slic3r/GUI/WebPresetDialog.hpp"
#include <mutex>
#include "slic3r/GUI/SMPhysicalPrinterDialog.hpp"
#include "slic3r/GUI/WebUrlDialog.hpp"
#include "miniz/miniz.h"
#include "slic3r/Utils/MQTT.hpp"
namespace pt = boost::property_tree;
using namespace nlohmann;
namespace Slic3r { namespace GUI {
// WCP_Logger
WCP_Logger::WCP_Logger() {
}
bool WCP_Logger::run()
{
if (inited) {
return true; // Already initialized
}
// 创建IO上下文和TCP套接字
socket = new tcp::socket(io_ctx);
// 解析服务器地址(本地回环)
resolver = new tcp::resolver(io_ctx);
auto endpoints = resolver->resolve("127.0.0.1", "50000"); // 端口与Python服务端一致
// 连接服务器(同步连接,阻塞直到成功或失败)
try {
asio::connect(*socket, endpoints);
} catch (std::exception& e) {
return false;
}
m_work_thread = std::thread(&WCP_Logger::worker, this);
inited = true;
return inited;
}
WCP_Logger& WCP_Logger::getInstance()
{
static WCP_Logger instance;
return instance;
}
bool WCP_Logger::set_level(wxString& level)
{
if (m_log_level_map.count(level)) {
m_log_level = m_log_level_map[level];
return true;
} else {
m_log_level = 0;
return false;
}
}
// Add a log message to the queue
void WCP_Logger::add_log(const wxString& content, bool is_web = false, wxString time = "", wxString module = "Default", wxString level = "debug")
{
if (!inited) {
return;
}
if (time == "") {
// 获取当前时间
wxDateTime now = wxDateTime::Now();
// 格式化日期时间部分(年-月-日 时:分:秒)
wxString dateTimePart = now.Format(_T("%Y-%m-%d %H:%M:%S"));
// 获取毫秒并格式化为三位字符串(补零)
int milliseconds = now.GetMillisecond();
wxString msPart = wxString::Format(_T("%03d"), milliseconds);
// 拼接完整时间字符串
time = dateTimePart + _T(":") + msPart;
}
std::lock_guard<std::mutex> lock(m_log_mtx);
m_log_que.push((time + " [ " + (is_web ? "Flutter" : "Native") + " ] [ " + level + " ] [ " + module + "] " + content + "\n").ToUTF8());
}
void WCP_Logger::worker()
{
while (true) {
m_log_mtx.lock();
if (!m_log_que.empty()) {
wxString log = m_log_que.front();
m_log_que.pop();
m_log_mtx.unlock();
log += "\n";
try {
asio::write(*socket, asio::buffer(log.ToUTF8().data(), log.length() + 1));
}
catch (std::exception& e) {
}
} else {
m_log_mtx.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
bool end_flag = false;
m_end_mtx.lock();
end_flag = m_end;
m_end_mtx.unlock();
if (end_flag)
break;
}
}
WCP_Logger::~WCP_Logger()
{
m_end_mtx.lock();
m_end = true;
m_end_mtx.unlock();
if (m_work_thread.joinable())
m_work_thread.join();
try {
if (socket != nullptr && socket->is_open()) {
socket->close();
}
}
catch (std::exception& e) {
if (resolver)
delete resolver;
if (socket)
delete socket;
return;
}
if (resolver)
delete resolver;
if (socket)
delete socket;
}
extern json m_ProfileJson;
extern std::mutex m_ProfileJson_mutex;
std::vector<std::string> load_thumbnails(const std::string& file, size_t image_count)
{
std::vector<std::string> res;
// Read a 64k block from the end of the G-code.
boost::nowide::ifstream ifs(file);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": before parse_file %1%") % file.c_str();
bool begin_found = false;
bool end_found = false;
std::string line;
int thumbnail_id = 0;
while (std::getline(ifs, line)) {
if (thumbnail_id == image_count) {
break;
}
// 找到缩略图开始标记
if (line.find("; THUMBNAIL_BLOCK_START") != std::string::npos) {
std::string thumb_content = "";
int width = 0;
int height = 0;
int data_size = 0;
// 跳过空行
std::getline(ifs, line);
std::getline(ifs, line);
// 读取缩略图信息行
std::getline(ifs, line);
if (line.find("; thumbnail begin") != std::string::npos) {
// 解析宽度、高度和数据大小
// 格式: "; thumbnail begin 48x48 1144"
sscanf(line.c_str(), "; thumbnail begin %dx%d %d", &width, &height, &data_size);
// 读取Base64编码的数据
std::string base64_data;
while (std::getline(ifs, line)) {
if (line.find("; thumbnail end") != std::string::npos) {
break;
}
// 移除行首的 "; "
if (line.substr(0, 2) == "; ") {
base64_data += line.substr(2);
}
}
thumb_content = base64_data;
res.emplace_back(thumb_content);
++thumbnail_id;
}
// 读取到块结束标记
while (std::getline(ifs, line)) {
if (line.find("; THUMBNAIL_BLOCK_END") != std::string::npos) {
break;
}
}
}
}
ifs.clear(); // 清除可能的 EOF 标志
ifs.seekg(0);
return std::move(res);
}
// Util
std::vector<char> create_zip_with_miniz(const std::string& name1, // 原文件路径(如 "c:/xxx/1.gcode"
const std::string& name2 // ZIP 内文件名(如 "target.gcode"
)
{
// 1. 读取原文件内容
std::ifstream file(name1, std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open source file: " + name1);
}
std::vector<char> file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
SSWCP::m_file_size_mutex.lock();
SSWCP::m_active_file_size = file_content.size();
SSWCP::m_file_size_mutex.unlock();
// 2. 初始化 ZIP 写入器(内存模式)
mz_zip_archive zip_archive;
memset(&zip_archive, 0, sizeof(zip_archive));
// 初始化 ZIP 写入到堆内存
if (!mz_zip_writer_init_heap(&zip_archive, 0, 0)) {
throw std::runtime_error("Failed to initialize ZIP writer");
}
// 3. 将文件内容添加到 ZIP使用 name2 作为内部文件名)
if (!mz_zip_writer_add_mem(&zip_archive,
name2.c_str(), // ZIP 内文件名
file_content.data(), // 文件内容指针
file_content.size(), // 文件内容大小
MZ_DEFAULT_COMPRESSION // 压缩级别
)) {
mz_zip_writer_end(&zip_archive);
throw std::runtime_error("Failed to add file to ZIP");
}
// 4. 完成 ZIP 写入并获取内存数据
void* zip_data = nullptr;
size_t zip_size = 0;
if (!mz_zip_writer_finalize_heap_archive(&zip_archive, &zip_data, &zip_size)) {
mz_zip_writer_end(&zip_archive);
throw std::runtime_error("Failed to finalize ZIP archive");
}
// 将 ZIP 数据复制到 vector方便后续操作
std::vector<char> zip_stream(static_cast<char*>(zip_data), static_cast<char*>(zip_data) + zip_size);
// 5. 清理资源
mz_zip_writer_end(&zip_archive);
mz_free(zip_data);
return zip_stream;
}
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string base64_encode(const char* data, size_t len)
{
std::string encoded;
int i = 0, j = 0;
uint8_t byte3[3], byte4[4];
while (len--) {
byte3[i++] = *(data++);
if (i == 3) {
byte4[0] = (byte3[0] & 0xfc) >> 2;
byte4[1] = ((byte3[0] & 0x03) << 4) | ((byte3[1] & 0xf0) >> 4);
byte4[2] = ((byte3[1] & 0x0f) << 2) | ((byte3[2] & 0xc0) >> 6);
byte4[3] = byte3[2] & 0x3f;
for (i = 0; i < 4; i++)
encoded += base64_chars[byte4[i]];
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++)
byte3[j] = 0;
byte4[0] = (byte3[0] & 0xfc) >> 2;
byte4[1] = ((byte3[0] & 0x03) << 4) | ((byte3[1] & 0xf0) >> 4);
byte4[2] = ((byte3[1] & 0x0f) << 2) | ((byte3[2] & 0xc0) >> 6);
byte4[3] = byte3[2] & 0x3f;
for (j = 0; j < i + 1; j++)
encoded += base64_chars[byte4[j]];
while (i++ < 3)
encoded += '=';
}
return encoded;
}
std::string generate_zip_path(const std::string& oriname, const std::string& targetname)
{
// 解析 name1 的路径
fs::path path1 = oriname;
// 获取父目录(例如 "c:/xxx/xxx/xxx"
fs::path parent_dir = path1.parent_path();
// 将 name2 作为基础文件名,追加 ".zip"(例如 "target.gcode" -> "target.gcode.zip"
fs::path new_filename = fs::path(targetname);
new_filename += ".zip"; // 直接追加扩展名
// 组合完整路径
fs::path zip_path = parent_dir / new_filename;
return zip_path.string();
}
// 检查文件是否存在并读取内容
bool read_existing_zip(const std::string& zip_path, std::vector<char>& out_data)
{
if (!fs::exists(zip_path)) {
return false;
}
std::ifstream file(zip_path, std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open existing ZIP file: " + zip_path);
}
out_data.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
return true;
}
// 主逻辑函数
json get_or_create_zip_json(const std::string& name1, // 原文件路径(如 "1.gcode"
const std::string& name2, // 目标 ZIP 文件名(如 "target.gcode"
const std::string& zip_path // 要检查的 ZIP 文件路径(如 "output.zip"
)
{
std::vector<char> zip_stream;
// 1. 检查同名 ZIP 是否存在
if (read_existing_zip(zip_path, zip_stream)) {
std::cout << "Reusing existing ZIP file: " << zip_path << std::endl;
} else {
// 2. 若不存在,创建新 ZIP 并写入文件
std::cout << "Creating new ZIP file: " << zip_path << std::endl;
zip_stream = create_zip_with_miniz(name1, name2);
// 将新生成的 ZIP 写入文件(可选持久化)
std::ofstream out_file(zip_path, std::ios::binary);
out_file.write(zip_stream.data(), zip_stream.size());
if (!out_file.good()) {
throw std::runtime_error("Failed to write ZIP to: " + zip_path);
}
}
//// 3. 编码为 Base64 并存入 JSON
//std::string base64_str = base64_encode(zip_stream.data(), zip_stream.size());
json j;
j["zip_data"] = zip_stream;
j["zip_name"] = name2 + ".zip";
return j;
}
bool SSWCP_Instance::m_first_connected = true;
// Base SSWCP_Instance implementation
void SSWCP_Instance::process() {
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "test") {
sync_test();
} else if (m_cmd == "test_async"){
async_test();
} else if (m_cmd == "sw_test_mqtt_moonraker") {
test_mqtt_request();
} else if (m_cmd == "sw_SetCache") {
sw_SetCache();
} else if (m_cmd == "sw_GetCache") {
sw_GetCache();
} else if (m_cmd == "sw_RemoveCache") {
sw_RemoveCache();
} else if (m_cmd == "sw_SwitchTab") {
sw_SwitchTab();
} else if (m_cmd == "sw_Webview_Unsubscribe") {
sw_Webview_Unsubscribe();
} else if (m_cmd == "sw_UnsubscribeAll") {
sw_UnsubscribeAll();
} else if (m_cmd == "sw_Unsubscribe_Filter") {
sw_Unsubscribe_Filter();
} else if (m_cmd == "sw_GetFileStream") {
sw_GetFileStream();
} else if (m_cmd == "sw_GetActiveFile") {
sw_GetActiveFile();
} else if (m_cmd == "sw_Log") {
sw_Log();
} else if (m_cmd == "sw_SetLogLevel") {
sw_SetLogLevel();
} else if (m_cmd == "sw_LaunchConsole") {
sw_LaunchConsole();
} else if (m_cmd == "sw_Exit") {
sw_Exit();
} else if(m_cmd == "sw_FileLog") {
sw_FileLog();
} else if (m_cmd == "sw_SubscribeCacheKey") {
sw_SubscribeCacheKey();
} else if (m_cmd == "sw_UnsubscribeCacheKeys") {
sw_UnsubscribeCacheKeys();
} else if (m_cmd == "sw_UploadEvent") {
sw_UploadEvent();
} else if (m_cmd == "sw_OpenOrcaWebview") {
sw_OpenOrcaWebview();
} else if (m_cmd == "sw_OpenBrowser") {
sw_OpenBrowser();
} else if (m_cmd == "sw_OpenNetworkDialog"){
sw_OpenNetworkDialog();
}
else {
handle_general_fail();
}
}
void SSWCP_Instance::sw_UploadEvent() {
try {
if(!m_param_data.count("traceId")){
handle_general_fail(-1, "param [traceId] required!");
return;
}
if(!m_param_data.count("level")){
handle_general_fail(-1, "param [level] required!");
return;
}
if(!m_param_data.count("content")){
handle_general_fail(-1, "param [content] required!");
return;
}
std::string traceId = m_param_data["traceId"].get<std::string>();
int level = m_param_data["level"].get<int>();
std::string content = m_param_data["content"].get<std::string>();
std::string funcModule = m_param_data.count("funcModule") ? m_param_data["funcModule"].get<std::string>() : "";
std::string tagKey = m_param_data.count("tagKey") ? m_param_data["tagKey"].get<std::string>() : "";
std::string tagValue = m_param_data.count("tagValue") ? m_param_data["tagValue"].get<std::string>() : "";
sentryReportLog(SENTRY_LOG_LEVEL(level), content, funcModule, tagKey, tagValue, traceId);
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_OpenNetworkDialog() {
try {
send_to_js();
finish_job();
wxGetApp().CallAfter([]() {
// Use shared_ptr to manage dialog lifetime
auto dlg = std::make_shared<NetworkTestDialog>(wxGetApp().mainframe);
dlg->ShowModal();
// Keep dialog alive for 2 seconds after closing to allow background threads to finish
// Use a timer to delay the destruction
class DelayedReleaseTimer : public wxTimer
{
std::shared_ptr<NetworkTestDialog> m_dialog;
public:
DelayedReleaseTimer(std::shared_ptr<NetworkTestDialog> dlg) : m_dialog(std::move(dlg))
{
StartOnce(5000); // 5 seconds delay
}
void Notify() override
{
m_dialog.reset(); // Release the dialog
delete this; // Delete the timer itself
}
};
new DelayedReleaseTimer(dlg);
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_OpenBrowser() {
try {
std::string url = m_param_data.count("url") ? m_param_data["url"].get<std::string>() : "";
wxString wx_url = wxString::FromUTF8(url);
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
wxGetApp().CallAfter([wx_url, weak_self]() {
auto self = weak_self.lock();
if (!self) {
return;
}
bool res = wxLaunchDefaultBrowser(wx_url);
if (!res) {
self->handle_general_fail(-1, "Open browser failed");
} else {
self->send_to_js();
self->finish_job();
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_OpenOrcaWebview() {
try {
std::string url = m_param_data.count("url") ? m_param_data["url"].get<std::string>() : "";
wxString wx_url = wxString::FromUTF8(url);
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
wxGetApp().CallAfter([wx_url, weak_self]() {
auto self = weak_self.lock();
if (!self) {
return;
}
auto dialog = new WebUrlDialog();
dialog->load_url(wx_url);
self->send_to_js();
self->finish_job();
dialog->Show();
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_FileLog() {
try {
std::string level = m_param_data.count("level") ? m_param_data["level"].get<std::string>() : "debug";
std::string content = m_param_data.count("content") ? m_param_data["content"].get<std::string>() : "";
if(level == "debug") {
BOOST_LOG_TRIVIAL(debug) << "[WCP] " << content;
} else if(level == "info") {
BOOST_LOG_TRIVIAL(info) << "[WCP] " << content;
} else if(level == "warning") {
BOOST_LOG_TRIVIAL(warning) << "[WCP] " << content;
} else if(level == "error") {
BOOST_LOG_TRIVIAL(error) << "[WCP] " << content;
} else if(level == "fatal") {
BOOST_LOG_TRIVIAL(fatal) << "[WCP] " << content;
}
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_Exit() {
try {
wxGetApp().Exit();
}
catch (std::exception& e) {
}
}
void SSWCP_Instance::sw_GetActiveFile()
{
try {
std::string file_path = SSWCP::get_active_filename();
std::string file_name = SSWCP::get_display_filename();
if (file_path == "" || file_name == "") {
handle_general_fail();
return;
}
bool iszip = false;
if (m_param_data.count("is_zip")) {
iszip = m_param_data["is_zip"].get<bool>();
}
if (iszip) {
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([file_path, file_name, weak_self]() {
auto self = weak_self.lock();
std::string zipname = generate_zip_path(file_path, file_name);
json res = get_or_create_zip_json(file_path, file_name, zipname);
size_t name_index = file_name.find_last_of(".");
size_t path_index = file_path.find_last_of(".");
if (!(name_index == std::string::npos || path_index == std::string::npos)) {
self->m_res_data["file_name"] = file_name.substr(0, name_index) + ".zip";
self->m_res_data["file_path"] = wxString(zipname).ToUTF8();
SSWCP::m_file_size_mutex.lock();
self->m_res_data["origin_size"] = SSWCP::m_active_file_size;
SSWCP::m_file_size_mutex.unlock();
wxGetApp().CallAfter([weak_self]() {
if (weak_self.lock()) {
weak_self.lock()->send_to_js();
weak_self.lock()->finish_job();
}
});
} else {
wxGetApp().CallAfter([weak_self]() {
if (weak_self.lock()) {
weak_self.lock()->handle_general_fail();
}
});
return;
}
});
} else {
m_res_data["file_name"] = file_name;
m_res_data["file_path"] = file_path;
send_to_js();
finish_job();
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_LaunchConsole() {
try {
bool res = WCP_Logger::getInstance().run();
if (res) {
m_msg = "Orca Console has been launched";
send_to_js();
finish_job();
} else {
handle_general_fail(-1, "Orca Console launched failed");
}
}
catch (std::exception& e) {
wxString reason = e.what();
handle_general_fail(-1, "Exception caught: " + reason);
}
}
void SSWCP_Instance::sw_SetLogLevel() {
try {
if (m_param_data.count("level")) {
wxString level = m_param_data["level"].get<std::string>();
bool res = WCP_Logger::getInstance().set_level(level);
if (res) {
m_msg = ("The log level has been set to " + level).ToUTF8();
send_to_js();
finish_job();
} else {
handle_general_fail(-1, "The param [level] is not legal, the log level will be set to debug");
}
} else {
handle_general_fail(-1, "param [level] required!");
}
}
catch (std::exception& e) {
wxString reason = e.what();
handle_general_fail(-1, "Exception caught: " + reason);
}
}
void SSWCP_Instance::sw_Log()
{
try {
wxString time = m_param_data.count("time") ? m_param_data["time"].get<wxString>() : "";
wxString level = m_param_data.count("level") ? m_param_data["level"].get<wxString>() : "";
wxString module = m_param_data.count("module") ? m_param_data["module"].get<wxString>() : "";
wxString content = m_param_data.count("content") ? m_param_data["content"].get<wxString>() : "";
auto& logger = WCP_Logger::getInstance();
if (!logger.m_log_level_map.count(level)) {
// todo log:级别不对,转成debug,打原生log
level = "debug";
}
if (logger.m_log_level_map[level] >= logger.get_level()) {
logger.add_log(content, true, time, module, level);
}
finish_job();
}
catch (std::exception& e) {
finish_job();
}
}
void SSWCP_Instance::sw_GetFileStream() {
try {
bool isZip = false;
if (m_param_data.count("is_zip")) {
isZip = m_param_data["is_zip"].get<bool>();
}
std::string file_path = SSWCP::get_active_filename();
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
if (isZip) {
auto oriname = SSWCP::get_active_filename();
auto targetname = SSWCP::get_display_filename();
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([oriname, targetname, weak_self]() {
auto self = weak_self.lock();
if (self) {
std::string zipname = generate_zip_path(oriname, targetname);
json res = get_or_create_zip_json(oriname, targetname, zipname);
wxGetApp().CallAfter([weak_self, res]() {
auto self = weak_self.lock();
if (self) {
self->m_res_data["name"] = res["zip_name"];
self->m_res_data["content"] = res["zip_data"];
self->send_to_js();
self->finish_job();
}
});
}
});
} else {
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([file_path, weak_self]() {
auto self = weak_self.lock();
if (self) {
// 1. 读取原文件内容
std::ifstream file(file_path, std::ios::binary);
if (!file.is_open()) {
self->handle_general_fail();
return;
}
// 获取文件大小
file.seekg(0, std::ios::end);
std::streamsize file_size = file.tellg();
file.seekg(0, std::ios::beg);
// 预分配 std::string 空间
std::string content;
content.resize(file_size);
// 一次性读取整个文件
if (!file.read(&content[0], file_size)) {
std::cerr << "读取文件失败" << std::endl;
self->handle_general_fail();
return;
}
self->m_res_data["content"] = wxString(content).ToUTF8();
wxGetApp().CallAfter([weak_self]() {
auto self = weak_self.lock();
if (self) {
self->send_to_js();
self->finish_job();
}
});
}
});
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::handle_general_fail(int code, const wxString& msg)
{
try {
m_status = code;
m_msg = msg.ToUTF8();
send_to_js();
finish_job();
} catch (std::exception& e) {}
}
// Mark instance as invalid
void SSWCP_Instance::set_Instance_illegal()
{
m_illegal_mtx.lock();
m_illegal = true;
m_illegal_mtx.unlock();
}
// Check if instance is invalid
bool SSWCP_Instance::is_Instance_illegal() {
m_illegal_mtx.lock();
bool res = m_illegal;
m_illegal_mtx.unlock();
return res;
}
// Get associated webview
wxWebView* SSWCP_Instance::get_web_view() const {
return m_webview;
}
void SSWCP_Instance::set_web_view(wxWebView* view) {
m_webview = view;
}
// Send response to JavaScript
void SSWCP_Instance::send_to_js()
{
try {
if (is_Instance_illegal()) {
return;
}
json response, payload;
response["header"] = m_header;
payload["code"] = m_status;
payload["message"] = m_msg;
payload["data"] = m_res_data;
response["payload"] = payload;
std::string json_str = response.dump(4, ' ', true);
std::string str_res = "window.postMessage(JSON.stringify(" + json_str + "), '*');";
WCP_Logger::getInstance().add_log(str_res, false, "", "WCP", "info");
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
wxGetApp().CallAfter([weak_self, str_res]() {
try {
auto self = weak_self.lock();
if (self && self->m_webview && self->m_webview->GetRefData()) {
WebView::RunScript(self->m_webview, str_res);
}
} catch (std::exception& e) {
WCP_Logger::getInstance().add_log(e.what(), false, "", "WCP", "info");
}
});
} catch (std::exception& e) {}
}
// Clean up instance
void SSWCP_Instance::finish_job() {
SSWCP::delete_target(this);
}
// Asynchronous test implementation
void SSWCP_Instance::async_test() {
auto http = Http::get("http://172.18.1.69/");
http.on_error([&](std::string body, std::string error, unsigned status) {
})
.on_complete([=](std::string body, unsigned) {
json data;
data["str"] = body;
this->m_res_data = data;
this->send_to_js();
finish_job();
})
.perform();
}
// Synchronous test implementation
std::unordered_map<std::string, json> SSWCP_Instance::m_wcp_cache;
void SSWCP_Instance::sync_test() {
m_res_data = m_param_data;
send_to_js();
finish_job();
}
void SSWCP_Instance::test_mqtt_request() {
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->test_async_wcp_mqtt_moonraker(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
// host->async_get_printer_info([self](const json& response) { SSWCP_Instance::on_mqtt_msg_arrived(self, response); });
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_SwitchTab() {
try {
if (m_param_data.count("target")) {
std::string target_tab = m_param_data["target"].get<std::string>();
if (SSWCP::m_tab_map.count(target_tab)) {
wxGetApp().mainframe->request_select_tab(MainFrame::TabPosition(SSWCP::m_tab_map[target_tab]));
send_to_js();
finish_job();
return;
}
}
handle_general_fail();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_SetCache() {
try {
if (m_param_data.count("objects") && m_param_data["objects"].is_array() &&
m_param_data["objects"].size() > 0) {
json objects = m_param_data["objects"];
for (size_t i = 0; i < objects.size(); ++i) {
m_wcp_cache.insert({objects[i]["key"].get<std::string>(), objects[i]["value"]});
wxGetApp().cache_notify(objects[i]["key"].get<std::string>(), objects[i]["value"]);
}
send_to_js();
finish_job();
} else {
handle_general_fail();
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_GetCache()
{
try {
if (m_param_data.count("keys") && m_param_data["keys"].is_array() && m_param_data["keys"].size() > 0) {
json res_data;
json keys = m_param_data["keys"];
for (size_t i = 0; i < keys.size(); ++i) {
std::string key = keys[i].get<std::string>();
if (m_wcp_cache.count(key)) {
res_data.push_back(m_wcp_cache[key]);
} else {
res_data.push_back(json::object());
}
}
m_res_data = res_data;
send_to_js();
finish_job();
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_RemoveCache()
{
try {
if (m_param_data.count("keys") && m_param_data["keys"].is_array()) {
json keys = m_param_data["keys"];
if (keys.size() == 0) {
for (const auto& item : m_wcp_cache) {
wxGetApp().cache_notify(item.first, json::value_t::null);
}
m_wcp_cache.clear();
} else {
for (size_t i = 0; i < keys.size(); ++i) {
std::string key = keys[i].get<std::string>();
if (m_wcp_cache.count(key)) {
wxGetApp().cache_notify(key, json::value_t::null);
m_wcp_cache.erase(key);
}
}
}
send_to_js();
finish_job();
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_SubscribeCacheKey()
{
try {
if (!m_param_data.count("key") || !m_param_data["key"].is_string()) {
handle_general_fail(-1, "param [keys] required or wrong type");
return;
}
std::string key = m_param_data["key"].get<std::string>();
auto& cache_map = wxGetApp().m_cache_subscribers;
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview && iter->second == key) {
// 删除之前的订阅
iter = cache_map.erase(iter);
} else {
++iter;
}
}
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
cache_map[{m_webview, weak_self}] = key;
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::sw_UnsubscribeCacheKeys()
{
try {
if (!m_param_data.count("keys") || !m_param_data["keys"].is_array()) {
handle_general_fail(-1, "param [keys] required or wrong type!");
return;
}
json keys = m_param_data["keys"];
auto& cache_map = wxGetApp().m_cache_subscribers;
if (keys.size() == 0) {
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview) {
iter = cache_map.erase(iter);
} else {
iter++;
}
}
} else {
for (size_t i = 0; i < keys.size(); ++i) {
std::string delete_key = keys[i].get<std::string>();
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview && iter->second == delete_key) {
iter = cache_map.erase(iter);
} else {
iter++;
}
}
}
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_Instance::on_mqtt_status_msg_arrived(std::shared_ptr<SSWCP_Instance> obj, const json& response)
{
if (!obj) {
return;
}
if (response.is_null()) {
obj->m_status = -1;
obj->m_msg = "failure";
obj->send_to_js();
} else if (response.count("error")) {
if (response["error"].is_string() && "timeout" == response["error"].get<std::string>()) {
obj->on_timeout();
} else {
obj->m_res_data = response;
obj->send_to_js();
}
} else {
obj->m_res_data = response;
obj->send_to_js();
}
}
void SSWCP_Instance::on_mqtt_msg_arrived(std::shared_ptr<SSWCP_Instance> obj, const json& response) {
if (!obj) {
return;
}
if (response.is_null()) {
obj->m_status = -1;
obj->m_msg = "failure";
obj->send_to_js();
} else if (response.count("error")) {
if (response["error"].is_string() && "timeout" == response["error"].get<std::string>()) {
obj->on_timeout();
} else {
obj->m_res_data = response;
obj->send_to_js();
}
} else {
obj->m_res_data = response;
obj->send_to_js();
}
obj->finish_job();
}
void SSWCP_Instance::sw_UnsubscribeAll() {
wxGetApp().m_device_card_subscribers.clear();
wxGetApp().m_recent_file_subscribers.clear();
wxGetApp().m_user_login_subscribers.clear();
wxGetApp().m_cache_subscribers.clear();
wxGetApp().m_user_update_privacy_subscribers.clear();
send_to_js();
finish_job();
}
void SSWCP_Instance::sw_Webview_Unsubscribe() {
auto& device_map = wxGetApp().m_device_card_subscribers;
for (auto iter = device_map.begin(); iter != device_map.end();) {
if (iter->first == m_webview) {
iter = device_map.erase(iter);
} else {
iter++;
}
}
auto& login_map = wxGetApp().m_user_login_subscribers;
for (auto iter = login_map.begin(); iter != login_map.end();) {
if (iter->first == m_webview) {
iter = login_map.erase(iter);
} else {
iter++;
}
}
auto& recent_file_map = wxGetApp().m_recent_file_subscribers;
for (auto iter = recent_file_map.begin(); iter != recent_file_map.end();) {
if (iter->first == m_webview) {
iter = recent_file_map.erase(iter);
} else {
iter++;
}
}
auto& cache_map = wxGetApp().m_cache_subscribers;
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview) {
iter = cache_map.erase(iter);
} else {
iter++;
}
}
auto& privacy_map = wxGetApp().m_user_update_privacy_subscribers;
for (auto iter = privacy_map.begin(); iter != privacy_map.end();) {
if (iter->first == m_webview) {
iter = privacy_map.erase(iter);
} else {
iter++;
}
}
send_to_js();
finish_job();
}
void SSWCP_Instance::sw_Unsubscribe_Filter() {
try {
std::string cmd = m_param_data.count("cmd") ? m_param_data["cmd"].get<std::string>() : "";
std::string event_id = m_param_data.count("event_id") ? m_param_data["event_id"].get<std::string>() : "";
if (cmd == "" || event_id == "") {
send_to_js();
finish_job();
return;
}
auto& device_map = wxGetApp().m_device_card_subscribers;
auto& login_map = wxGetApp().m_user_login_subscribers;
auto& privacy_map = wxGetApp().m_user_update_privacy_subscribers;
auto& recent_file_map = wxGetApp().m_recent_file_subscribers;
auto& cache_map = wxGetApp().m_cache_subscribers;
if (cmd == "") {
for (auto iter = device_map.begin(); iter != device_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (ptr->m_event_id == event_id) {
iter = device_map.erase(iter);
} else {
iter++;
}
} else {
iter = device_map.erase(iter);
}
} else {
iter++;
}
}
for (auto iter = login_map.begin(); iter != login_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (ptr->m_event_id == event_id) {
iter = login_map.erase(iter);
} else {
iter++;
}
} else {
iter = login_map.erase(iter);
}
} else {
iter++;
}
}
for (auto iter = privacy_map.begin(); iter != privacy_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (ptr->m_event_id == event_id) {
iter = privacy_map.erase(iter);
} else {
iter++;
}
} else {
iter = privacy_map.erase(iter);
}
} else {
iter++;
}
}
for (auto iter = recent_file_map.begin(); iter != recent_file_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (ptr->m_event_id == event_id) {
iter = recent_file_map.erase(iter);
} else {
iter++;
}
} else {
iter = recent_file_map.erase(iter);
}
} else {
iter++;
}
}
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview) {
auto ptr = iter->first.second.lock();
if (ptr) {
if (ptr->m_event_id == event_id) {
iter = cache_map.erase(iter);
} else {
iter++;
}
} else {
iter = cache_map.erase(iter);
}
} else {
iter++;
}
}
} else if (cmd == "sw_SubscribeRecentFiles") {
for (auto iter = recent_file_map.begin(); iter != recent_file_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = recent_file_map.erase(iter);
} else {
iter++;
}
} else {
iter = recent_file_map.erase(iter);
}
} else {
iter++;
}
}
} else if (cmd == "sw_SubscribeUserLoginState") {
for (auto iter = login_map.begin(); iter != login_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = login_map.erase(iter);
} else {
iter++;
}
} else {
iter = login_map.erase(iter);
}
} else {
iter++;
}
}
} else if (cmd == UPDATE_PRIVACY_STATUS) {
for (auto iter = privacy_map.begin(); iter != privacy_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = privacy_map.erase(iter);
} else {
iter++;
}
} else {
iter = privacy_map.erase(iter);
}
} else {
iter++;
}
}
}else if (cmd == "sw_SubscribeLocalDevices") {
for (auto iter = device_map.begin(); iter != device_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = device_map.erase(iter);
} else {
iter++;
}
} else {
iter = device_map.erase(iter);
}
} else {
iter++;
}
}
} else if (cmd == "sw_SubscribeCacheKey") {
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == m_webview) {
auto ptr = iter->first.second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = cache_map.erase(iter);
} else {
iter++;
}
} else {
iter = cache_map.erase(iter);
}
} else {
iter++;
}
}
}
else
{
BOOST_LOG_TRIVIAL(warning) << "no this cmd for:" << cmd;
}
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
// Handle timeout event
void SSWCP_Instance::on_timeout() {
handle_general_fail(-2, "time out");
finish_job();
}
void SSWCP_Instance::update_filament_info(const json& objects, bool send_message)
{
if (objects.size() < 1) {
if (send_message)
handle_general_fail(-1, "objects is empty!");
return;
}
if (!objects[0].count("key") || !objects[0]["key"].is_string()) {
if (send_message)
handle_general_fail(-1, "param [key] required or wrong type!");
return;
}
if (!objects[0].count("value") || !objects[0]["value"].is_string()) {
if (send_message)
handle_general_fail(-1, "param [value] required or wrong type!");
return;
}
std::string sn = objects[0]["key"].get<std::string>();
std::string value = objects[0]["value"].get<std::string>();
DeviceInfo info;
if (!wxGetApp().app_config->get_device_info(sn, info)) {
m_msg = "sn does not exist!";
if (send_message) {
handle_general_fail(-1, m_msg);
}
return;
} else {
if (!info.connected) {
m_msg = "The machine is not connected!";
if (send_message) {
handle_general_fail(-1, m_msg);
}
return;
} else {
json j_value;
try {
j_value = json::parse(value);
} catch (std::exception& e) {
if (send_message)
handle_general_fail(-1, "value parse failed");
return;
}
if (!j_value.count("filament_vendor") || !j_value["filament_vendor"].is_array() || !j_value.count("filament_type") ||
!j_value["filament_type"].is_array() || !j_value.count("filament_sub_type") || !j_value["filament_sub_type"].is_array() ||
((!j_value.count("filament_color") || !j_value["filament_color"].is_array()) &&
(!j_value.count("filament_color_rgba") || !j_value["filament_color_rgba"].is_array())) ||
!j_value.count("extruder_map_table") || !j_value["extruder_map_table"].is_array() || !j_value.count("filament_official") ||
!j_value["filament_official"].is_array()) {
if (send_message) {
handle_general_fail(-1, "value parse failed");
}
return;
}
// 存储耗材,并触发更新
auto& filaments = wxGetApp().preset_bundle->machine_filaments;
static auto tmp_filaments = filaments;
if (m_first_connected) {
tmp_filaments = filaments;
m_first_connected = false;
}
filaments.clear();
size_t count = 0;
for (size_t i = 0; i < j_value["filament_official"].size(); ++i) {
bool is_official = j_value["filament_official"][i].get<bool>();
if (/*is_official*/ true) {
std::string vendor = j_value["filament_vendor"][i].get<std::string>();
std::string type = j_value["filament_type"][i].get<std::string>();
std::string sub_type = j_value["filament_sub_type"][i].get<std::string>();
std::string name = "";
// 名称特殊处理
if (type == "TPU") {
name = vendor + " " + type;
} else if (sub_type == "Support") {
name = vendor + " Support" + " For " + type;
} else {
name = vendor + " " + type + ((sub_type != "NONE" && sub_type != "") ? " " + sub_type : "");
}
int extruder = j_value["extruder_map_table"][i].get<int>();
if (j_value.count("filament_color_rgba") && j_value["filament_color_rgba"].is_array() &&
j_value["filament_color_rgba"].size() != 0) {
std::string str_color = "#" + j_value["filament_color_rgba"][i].get<std::string>();
filaments.insert({int(i), {name, str_color}});
} else {
if (j_value["filament_color"][i].is_number()) {
int color = j_value["filament_color"][i].get<int>();
std::ostringstream oss;
oss << "#" << std::uppercase << std::setfill('0') << std::setw(6) << std::hex
<< (color & 0x00FFFFFF); // 仅取低24位
std::string str_color = oss.str();
filaments.insert({int(i), {name, str_color}});
} else {
std::string str_color = "#" + j_value["filament_color"][i].get<std::string>();
filaments.insert({int(i), {name, str_color}});
}
}
}
}
bool need_load_preset = false;
if (filaments.size() == 0 && tmp_filaments.size() != 0)
need_load_preset = true;
for (auto iter = filaments.begin(); iter != filaments.end(); iter++) {
if (tmp_filaments.count(iter->first)) {
auto pair = iter->second;
auto tmp_pair = tmp_filaments[iter->first];
if (pair.first == tmp_pair.first && pair.second == pair.second) {
continue;
} else {
need_load_preset = true;
break;
}
} else {
auto pair = iter->second;
if (pair.first.find("NONE") != std::string::npos) {
continue;
}
need_load_preset = true;
break;
}
}
if (need_load_preset) {
tmp_filaments = filaments;
wxGetApp().load_current_presets();
}
if (send_message) {
send_to_js();
finish_job();
}
}
}
}
// SSWCP_MachineFind_Instance implementation
// Process machine find commands
void SSWCP_MachineFind_Instance::process() {
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_StartMachineFind") {
sw_StartMachineFind();
} else if (m_cmd == "sw_GetMachineFindSupportInfo") {
sw_GetMachineFindSupportInfo();
} else if (m_cmd == "sw_StopMachineFind") {
sw_StopMachineFind();
} else if (m_cmd == "sw_WakeupFind") {
sw_WakeupFind();
} else {
handle_general_fail();
}
}
// Set stop flag for machine discovery
void SSWCP_MachineFind_Instance::set_stop(bool stop)
{
m_stop_mtx.lock();
m_stop = stop;
m_stop_mtx.unlock();
}
// Get machine discovery support info
void SSWCP_MachineFind_Instance::sw_GetMachineFindSupportInfo()
{
// 2.0.0 只支持 mdns - snapmaker
json protocols = json::array();
protocols.push_back("mdns");
json mdns_service_names = json::array();
mdns_service_names.push_back("snapmaker");
json res;
res["protocols"] = protocols;
res["mdns_service_names"] = mdns_service_names;
m_res_data = res;
send_to_js();
}
void SSWCP_MachineFind_Instance::sw_WakeupFind()
{
try {
// 1) 广域服务浏览:触发 _services._dns-sd._udp.local.维持约8秒
// 此查询促使 AP/交换机为本机建立 224.0.0.251:5353 的组播转发表,并促使设备进行通告
try {
Bonjour::TxtKeys warmup_txt_keys = {};
auto warmup = Bonjour("services._dns-sd")
.set_protocol("udp")
.set_txt_keys(std::move(warmup_txt_keys))
.set_retries(2)
.set_timeout(4) // 2*4 = ~8s
.on_reply([](BonjourReply&&){})
.on_complete([](){})
.lookup();
(void)warmup;
} catch (...) {
// 预热失败不影响后续短查
}
// 2) 目标服务短查:对 snapmaker 做一次短查询2 秒),帮助休眠设备快速回应
try {
auto kick = Bonjour("snapmaker")
.set_retries(1)
.set_timeout(2)
.on_reply([](BonjourReply&&){})
.on_complete([](){})
.lookup();
(void)kick;
} catch (...) {
}
// 立刻返回成功,查询在线程中进行
m_status = 200;
m_msg = "OK";
m_res_data["result"] = "wakeup_started";
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
// Start machine discovery
void SSWCP_MachineFind_Instance::sw_StartMachineFind()
{
try {
std::vector<string> protocols;
float last_time = -1;
if (m_param_data.count("last_time") && m_param_data["last_time"].is_number()) {
last_time = m_param_data["last_time"].get<float>();
}
last_time = -1;
// 目前只支持通过mdns协议搜索snapmaker,prusalink之后可以再扩充
protocols.push_back("mdns");
for (size_t i = 0; i < protocols.size(); ++i) {
if (protocols[i] == "mdns") {
std::vector<std::string> mdns_service_names;
mdns_service_names.push_back("snapmaker");
//mdns_service_names.push_back("prusalink");
//mdns_service_names.push_back("rdlink");
//mdns_service_names.push_back("raop");
m_engines.clear();
for (size_t i = 0; i < mdns_service_names.size(); ++i) {
m_engines.push_back(nullptr);
}
//// 预热扫描发送一轮短超时查询以激活休眠后的mDNS响应
//for (const auto& svc : mdns_service_names) {
// Bonjour(svc)
// .set_retries(1)
// .set_timeout(2)
// .on_reply([](BonjourReply&&){})
// .on_complete([]{})
// .lookup();
//}
//std::this_thread::sleep_for(std::chrono::milliseconds(300));
Bonjour::TxtKeys txt_keys = {"sn", "version", "machine_type", "link_mode", "userid", "device_name", "ip", "region"};
std::string unique_key = "sn";
for (size_t i = 0; i < m_engines.size(); ++i) {
auto self = std::dynamic_pointer_cast<SSWCP_MachineFind_Instance>(shared_from_this());
if(!self){
continue;
}
std::weak_ptr<SSWCP_MachineFind_Instance> weak_self(self);
m_engines[i] = Bonjour(mdns_service_names[i])
.set_txt_keys(std::move(txt_keys))
.set_retries(3)
.set_timeout(last_time >= 0.0 ? last_time/1000 : 20)
.on_reply([weak_self, unique_key](BonjourReply&& reply) {
// Check if application is still alive before processing
if (!GUI_App::m_app_alive.load()) {
return;
}
auto self = weak_self.lock();
if(!self || self->is_stop()){
return;
}
// Double check application is still alive after locking
if (!GUI_App::m_app_alive.load()) {
return;
}
json machine_data;
std::string hostname = reply.hostname;
size_t pos = hostname.find(".local");
if (pos != std::string::npos) {
hostname = hostname.substr(0, pos);
}
machine_data["name"] = hostname != "" ? hostname : reply.service_name;
// machine_data["hostname"] = reply.hostname;
if (!reply.ip.is_v4()) {
return;
}
machine_data["ip"] = reply.ip.to_string();
machine_data["port"] = reply.port;
if (reply.txt_data.count("protocol")) {
machine_data["protocol"] = reply.txt_data["protocol"];
}
if (reply.txt_data.count("version")) {
machine_data["pro_version"] = reply.txt_data["version"];
}
if (reply.txt_data.count(unique_key)) {
machine_data["unique_key"] = unique_key;
machine_data["unique_value"] = reply.txt_data[unique_key];
machine_data[unique_key] = machine_data["unique_value"];
}
if (reply.txt_data.count("link_mode")) {
machine_data["link_mode"] = reply.txt_data["link_mode"];
}
if (reply.txt_data.count("userid")) {
machine_data["userid"] = reply.txt_data["userid"];
}
if (reply.txt_data.count("device_name")) {
machine_data["device_name"] = reply.txt_data["device_name"];
}
// 模拟一下
/* machine_data["cover"] = LOCALHOST_URL + std::to_string(PAGE_HTTP_PORT) +
"/profiles/Snapmaker/Snapmaker A350 Dual BKit_cover.png";*/
if (reply.txt_data.count("machine_type")) {
std::string machine_type = reply.txt_data["machine_type"];
machine_data["machine_type"] = machine_type;
auto machine_ip_type = MachineIPType::getInstance();
if (machine_ip_type) {
machine_ip_type->add_instance(reply.ip.to_string(), machine_type);
}
size_t vendor_pos = machine_type.find_first_of(" ");
if (vendor_pos != std::string::npos) {
std::string vendor = machine_type.substr(0, vendor_pos);
// Check application is still alive before accessing wxGetApp()
if (GUI_App::m_app_alive.load()) {
try {
std::string machine_cover = LOCALHOST_URL + std::to_string(wxGetApp().m_page_http_server.get_port()) + "/profiles/" +
vendor + "/" + machine_type + "_cover.png";
machine_data["cover"] = machine_cover;
} catch (...) {
// Application is shutting down, skip setting cover
}
}
}
} else {
// test
/*auto machine_ip_type = MachineIPType::getInstance();
if (machine_ip_type) {
machine_ip_type->add_instance(reply.ip.to_string(), "unknown");
}*/
}
if (reply.txt_data.count("ip") && machine_data["ip"] == "") {
BOOST_LOG_TRIVIAL(warning) << "[Machine Find] Can't find the endpoint's ip, use the txtData: "
<< reply.txt_data["ip"];
machine_data["ip"] = reply.txt_data["ip"];
}
machine_data["txt_ip"] = reply.txt_data["ip"];
if (reply.txt_data.count("region")) {
machine_data["region"] = reply.txt_data["region"];
}
// Final check before adding to list
if (!GUI_App::m_app_alive.load() || !self || self->is_stop()) {
return;
}
json machine_object;
if (machine_data.count("unique_value")) {
self->add_machine_to_list(machine_object);
machine_object[reply.txt_data[unique_key]] = machine_data;
} else {
machine_object[reply.ip.to_string()] = machine_data;
}
self->add_machine_to_list(machine_object);
})
.on_complete([weak_self]() {
// Check if application is still alive before scheduling callback
if (!GUI_App::m_app_alive.load()) {
return;
}
try {
wxGetApp().CallAfter([weak_self]() {
// Check again inside the callback
if (!GUI_App::m_app_alive.load()) {
return;
}
auto self = weak_self.lock();
if (self && !self->is_stop()) {
self->onOneEngineEnd();
}
});
} catch (...) {
// Application is shutting down, ignore the callback
}
})
.lookup();
}
} else {
// 支持其他机器发现协议
}
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineFind_Instance::sw_StopMachineFind()
{
try {
SSWCP::stop_machine_find();
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineFind_Instance::add_machine_to_list(const json& machine_info)
{
try {
BOOST_LOG_TRIVIAL(info) << "check the machine list on json: " << machine_info.dump();
for (const auto& [key, value] : machine_info.items()) {
std::string sn = value["sn"].get<std::string>();
bool need_send = false;
m_machine_list_mtx.lock();
if (!m_machine_list.count(sn)) {
m_machine_list[sn] = machine_info;
m_machine_list_mtx.unlock();
m_res_data[key] = value;
need_send = true;
} else {
m_machine_list_mtx.unlock();
}
m_res_data[key]["connected"] = false;
DeviceInfo info;
if (wxGetApp().app_config->get_device_info(sn, info)) {
if (info.connected) {
m_res_data[key]["connected"] = true;
}
std::string ip = value["ip"].get<std::string>();
if (0) {
info.ip = ip;
wxGetApp().app_config->save_device_info(info);
wxGetApp().CallAfter([]() {
auto devices = wxGetApp().app_config->get_devices();
json param;
param["command"] = "local_devices_arrived";
param["sequece_id"] = "10001";
param["data"] = devices;
std::string logout_cmd = param.dump();
wxString strJS = wxString::Format("window.postMessage(%s)", logout_cmd);
GUI::wxGetApp().run_script(strJS);
// wcp订阅
json data = devices;
wxGetApp().device_card_notify(data);
});
}
}
if (need_send) {
send_to_js();
}
}
}
catch (std::exception& e) {
}
}
void SSWCP_MachineFind_Instance::onOneEngineEnd()
{
++m_engine_end_count;
if (m_engine_end_count == m_engines.size()) {
this->finish_job();
}
}
// SSWCP_MachineOption_Instance
void SSWCP_MachineOption_Instance::process()
{
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_SendGCodes") {
sw_SendGCodes();
} else if (m_cmd == "sw_FileGetStatus") {
sw_FileGetStatus();
} else if (m_cmd == "sw_SystemGetDeviceInfo") {
sw_SystemGetDeviceInfo();
} else if (m_cmd == "sw_GetMachineState") {
sw_GetMachineState();
} else if (m_cmd == "sw_SubscribeMachineState") {
sw_SubscribeMachineState();
} else if (m_cmd == "sw_GetMachineObjects") {
sw_GetMachineObjects();
} else if (m_cmd == "sw_SetSubscribeFilter") {
sw_SetMachineSubscribeFilter();
} else if (m_cmd == "sw_StopMachineStateSubscription") {
sw_UnSubscribeMachineState();
} else if (m_cmd == "sw_GetPrinterInfo") {
sw_GetPrintInfo();
} else if (m_cmd == "sw_GetMachineSystemInfo") {
sw_GetSystemInfo();
} else if (m_cmd == "sw_MachinePrintStart") {
sw_MachinePrintStart();
} else if (m_cmd == "sw_MachinePrintPause") {
sw_MachinePrintPause();
} else if (m_cmd == "sw_MachinePrintResume") {
sw_MachinePrintResume();
} else if (m_cmd == "sw_MachinePrintCancel") {
sw_MachinePrintCancel();
} else if (m_cmd == "sw_MachineFilesRoots") {
sw_MachineFilesRoots();
} else if (m_cmd == "sw_MachineFilesMetadata") {
sw_MachineFilesMetadata();
} else if (m_cmd == "sw_MachineFilesThumbnails") {
sw_MachineFilesThumbnails();
} else if (m_cmd == "sw_MachineFilesGetDirectory") {
sw_MachineFilesGetDirectory();
} else if (m_cmd == "sw_CameraStartMonitor") {
sw_CameraStartMonitor();
} else if (m_cmd == "sw_CameraStopMonitor") {
sw_CameraStopMonitor();
} else if (m_cmd == "sw_DeleteMachineFile") {
sw_DeleteMachineFile();
} else if (m_cmd == "sw_SetFilamentMappingComplete") {
sw_SetFilamentMappingComplete();
} else if (m_cmd == "sw_GetFileFilamentMapping") {
sw_GetFileFilamentMapping();
} else if (m_cmd == "sw_FinishFilamentMapping") {
sw_FinishFilamentMapping();
} else if(m_cmd == "sw_DownloadMachineFile"){
sw_DownloadMachineFile();
} else if (m_cmd == "sw_UploadFiletoMachine") {
sw_UploadFiletoMachine();
} else if (m_cmd == "sw_GetPrintLegal") {
sw_GetPrintLegal();
} else if (m_cmd == "sw_GetPrintZip") {
sw_GetPrintZip();
} else if (m_cmd == "sw_FinishPreprint") {
sw_FinishPreprint();
} else if (m_cmd == "sw_PullCloudFile") {
sw_PullCloudFile();
} else if (m_cmd == "sw_CancelPullCloudFile") {
sw_CancelPullCloudFile();
} else if (m_cmd == "sw_StartCloudPrint") {
sw_StartCloudPrint();
} else if (m_cmd == "sw_SetDeviceName") {
sw_SetDeviceName();
} else if (m_cmd == "sw_ControlLed") {
sw_ControlLed();
} else if (m_cmd == "sw_ControlPrintSpeed") {
sw_ControlPrintSpeed();
} else if (m_cmd == "sw_BedMesh_AbortProbeMesh") {
sw_BedMesh_AbortProbeMesh();
} else if (m_cmd == "sw_ControlPurifier") {
sw_ControlPurifier();
} else if (m_cmd == "sw_ControlMainFan") {
sw_ControlMainFan();
} else if (m_cmd == "sw_ControlGenericFan") {
sw_ControlGenericFan();
} else if (m_cmd == "sw_ControlBedTemp") {
sw_ControlBedTemp();
} else if (m_cmd == "sw_ControlExtruderTemp") {
sw_ControlExtruderTemp();
} else if (m_cmd == "sw_FilesThumbnailsBase64") {
sw_FilesThumbnailsBase64();
} else if (m_cmd == "sw_exception_query") {
sw_exception_query();
} else if (m_cmd == "sw_GetFileListPage") {
sw_GetFileListPage();
} else if (m_cmd == "sw_UpdateMachineFilamentInfo") {
sw_UpdateMachineFilamentInfo();
} else if (m_cmd == "sw_UploadCameraTimelapse") {
sw_UploadCameraTimelapse();
} else if (m_cmd == "sw_DeleteCameraTimelapse") {
sw_DeleteCameraTimelapse();
} else if (m_cmd == "sw_GetCameraTimelapseInstance") {
sw_GetCameraTimelapseInstance();
} else if (m_cmd == "sw_ServerClientManagerSetUserinfo") {
sw_ServerClientManagerSetUserinfo();
} else if (m_cmd == "sw_DefectDetactionConfig"){
sw_DefectDetactionConfig();
}
else if (m_cmd == GET_DEVICEDATA_STORAGESPACE) {
sw_GetDeviceDataStorageSpace();
}
else {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_UnSubscribeMachineState() {
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
m_status = 1;
m_msg = "failure";
send_to_js();
finish_job();
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
std::string key = m_event_id + std::to_string(int64_t(m_webview));
host->async_unsubscribe_machine_info(key, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
SSWCP::stop_subscribe_machine();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SubscribeMachineState() {
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
m_status = 1;
m_msg = "failure";
send_to_js();
finish_job();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
std::string key = m_event_id + std::to_string(int64_t(m_webview));
host->async_subscribe_machine_info(key, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_status_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetPrintInfo() {
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_printer_info([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetMachineState() {
try {
if (m_param_data.count("objects")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
std::vector<std::pair<std::string, std::vector<std::string>>> targets;
json items = m_param_data["objects"];
for (auto& [key, value] : items.items()) {
if (value.is_null()) {
targets.push_back({key, {}});
} else {
std::vector<std::string> items;
if (value.is_array()) {
for (size_t i = 0; i < value.size(); ++i) {
items.push_back(value[i].get<std::string>());
}
} else {
items.push_back(value.get<std::string>());
}
targets.push_back({key, items});
}
}
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_machine_info(targets, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SystemGetDeviceInfo() {
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_device_info([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (const std::exception&) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_FileGetStatus()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_server_files_get_status ([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SendGCodes() {
try {
if (m_param_data.count("script")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
std::vector<std::string> str_codes;
if (m_param_data["script"].is_array()) {
json codes = m_param_data["script"];
for (size_t i = 0; i < codes.size(); ++i) {
str_codes.push_back(codes[i].get<std::string>());
}
} else if (m_param_data["script"].is_string()) {
str_codes.push_back(m_param_data["script"].get<std::string>());
}
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_send_gcodes(str_codes, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
} catch (const std::exception&) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachinePrintStart() {
try {
if (m_param_data.count("filename")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
std::string filename = m_param_data["filename"].get<std::string>();
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_start_print_job(filename, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
}
catch(std::exception& e){
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachinePrintPause()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_pause_print_job([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachinePrintResume()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_resume_print_job([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachinePrintCancel()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_cancel_print_job([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetSystemInfo()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_system_info([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch(std::exception& e){
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SetMachineSubscribeFilter()
{
try {
if (m_param_data.count("objects")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
std::vector<std::pair<std::string, std::vector<std::string>>> targets;
json items = m_param_data["objects"];
for (auto& [key, value] : items.items()) {
if (value.is_null()) {
targets.push_back({key, {}});
} else {
std::vector<std::string> items;
if (value.is_array()) {
for (size_t i = 0; i < value.size(); ++i) {
items.push_back(value[i].get<std::string>());
}
} else {
items.push_back(value.get<std::string>());
}
targets.push_back({key, items});
}
}
if (!host) {
// 错误处理
handle_general_fail();
} else {
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_set_machine_subscribe_filter(targets, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetMachineObjects()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Can't find the active machine");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_machine_objects([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_PullCloudFile()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Can't find the active machine");
return;
}
json items = m_param_data;
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_pull_cloud_file(items, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_UpdateMachineFilamentInfo()
{
try {
if (!m_param_data.count("objects") || !m_param_data["objects"].is_array()) {
handle_general_fail(-1, "param [objects] required or wrong type!");
return;
}
update_filament_info(m_param_data["objects"], true);
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_CancelPullCloudFile()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Can't find the active machine");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_cancel_pull_cloud_file([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_StartCloudPrint()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Can't find the active machine");
return;
}
json items = m_param_data;
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_start_cloud_print(items, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachineFilesRoots()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_machine_files_roots([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachineFilesMetadata() {
try {
if (m_param_data.count("filename")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
std::string filename = m_param_data["filename"].get<std::string>();
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_machine_files_metadata(filename, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachineFilesThumbnails()
{
try {
if (m_param_data.count("filename")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
std::string filename = m_param_data["filename"].get<std::string>();
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_machine_files_thumbnails(filename,
[weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_MachineFilesGetDirectory()
{
try {
if (m_param_data.count("path") && m_param_data.count("extended")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
std::string path = m_param_data["path"].get<std::string>();
bool extend = m_param_data["extended"].get<bool>();
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_machine_files_directory(path, extend, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ServerClientManagerSetUserinfo()
{
try {
if (!m_param_data.count("auther")) {
handle_general_fail(-1, "param [auther] is required");
return;
}
json auther = m_param_data["auther"];
if(!auther.count("id") || !auther.count("nickname")){
handle_general_fail(-1, "param [id] and [nickname] is required");
return;
}
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "can't find the active machine");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_server_client_manager_set_userinfo(m_param_data,
[weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_FinishPreprint()
{
try {
if (m_param_data.count("status")) {
std::string status = m_param_data["status"].get<std::string>();
auto p_dialog = dynamic_cast<WebPreprintDialog*>(wxGetApp().get_web_preprint_dialog());
if (p_dialog) {
if (status != "success") {
p_dialog->set_swtich_to_device(false);
}
}
send_to_js();
finish_job();
return;
}
handle_general_fail();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetPrintZip()
{
try {
auto oriname = SSWCP::get_active_filename();
auto targetname = SSWCP::get_display_filename();
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([oriname, targetname, weak_self]() {
auto self = weak_self.lock();
if (self) {
std::string zipname = generate_zip_path(oriname, targetname);
json res = get_or_create_zip_json(oriname, targetname, zipname);
wxGetApp().CallAfter([weak_self, res]() {
auto self = weak_self.lock();
if (self) {
self->m_res_data["name"] = res["zip_name"];
self->m_res_data["content"] = res["zip_data"];
self->send_to_js();
self->finish_job();
}
});
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetPrintLegal()
{
try {
if (m_param_data.count("connected_model")) {
std::string connected_model = m_param_data["connected_model"].get<std::string>();
const auto& edit_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
std::string local_name = "";
if (edit_preset.is_system) {
local_name = edit_preset.name;
} else {
const auto& base_preset = wxGetApp().preset_bundle->printers.get_preset_base(edit_preset);
local_name = base_preset->name;
}
local_name.erase(std::remove(local_name.begin(), local_name.end(), '('), local_name.end());
local_name.erase(std::remove(local_name.begin(), local_name.end(), ')'), local_name.end());
m_res_data["preset_model"] = local_name;
m_res_data["legal"] = (local_name == connected_model);
send_to_js();
finish_job();
return;
}
handle_general_fail();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_UploadFiletoMachine() {
try {
if (!m_param_data.count("url")) {
handle_general_fail();
return;
}
std::string upload_url = std::string(wxString(m_param_data["url"].get<std::string>()).ToUTF8());
wxString wildcard = "All files (*.*)|*.*";
wxGetApp().CallAfter([wildcard, this, upload_url]() {
// 创建选择文件对话框
wxFileDialog picFileDialog(nullptr,
L("select file"), // 标题
"", // 默认路径
"", // 默认文件名
wildcard, // 文件类型过滤器
wxFD_OPEN | wxFD_OVERWRITE_PROMPT); // 样式
if (picFileDialog.ShowModal() == wxID_CANCEL) {
// 用户取消上传
handle_general_fail();
return;
}
// 获取选择的保存路径
wxString filepath = picFileDialog.GetPath();
wxString filename = picFileDialog.GetFilename();
std::string tmp_url = upload_url;
auto final_url = Http::encode_url_path(tmp_url);
Http http_object = Http::post(final_url);
http_object
.form_add("print", "false")
.form_add_file("file", std::string(filepath.ToUTF8()), std::string(filename.ToUTF8()))
.on_error([=](std::string body, std::string error, unsigned status) {
handle_general_fail();
wxGetApp().CallAfter([filename]() {
MessageDialog msg_window(nullptr, " " + filename + _L(" upload failed") + "\n", _L("UpLoad Failed"),
wxICON_QUESTION | wxOK);
msg_window.ShowModal();
});
})
.on_complete([=](std::string body, unsigned) {
try {
wxGetApp().CallAfter([=]() {
json response;
response["filename"] = std::string(filename.ToUTF8());
m_res_data = response;
send_to_js();
MessageDialog msg_window(nullptr, " " + filename + _L(" has already been uploaded") + "\n",
_L("UpLoad Successfully"), wxICON_QUESTION | wxOK);
msg_window.ShowModal();
finish_job();
});
} catch (std::exception& e) {
handle_general_fail();
}
})
.on_progress([&](Http::Progress progress, bool& cancel) {
})
.perform();
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_DownloadMachineFile() {
try {
if (!m_param_data.count("url")) {
handle_general_fail();
return;
}
wxString download_url = wxString::FromUTF8(m_param_data["url"].get<std::string>());
// 从 URL 获取默认文件名(如果没有提供)
wxString filename = "";
if (!m_param_data.count("filename")) {
size_t last_slash = download_url.find_last_of("/");
if (last_slash != std::string::npos) {
filename = download_url.substr(last_slash + 1);
}
} else {
filename = wxString::FromUTF8(m_param_data["filename"].get<std::string>());
}
// 获取文件扩展名
wxString extension;
size_t dot_pos = filename.find_last_of(".");
if (dot_pos != std::string::npos) {
extension = filename.substr(dot_pos + 1);
}
// 构建文件类型过滤器
wxString wildcard;
if (!extension.empty()) {
// 例如: "PNG files (*.png)|*.png|All files (*.*)|*.*"
wildcard = wxString::Format("%s files (*.%s)|*.%s|All files (*.*)|*.*", extension, extension, extension);
} else {
wildcard = "All files (*.*)|*.*";
}
wxGetApp().CallAfter([filename, extension, wildcard, this, download_url]() {
// 创建保存文件对话框
wxFileDialog saveFileDialog(nullptr,
L("Save file"), // 标题
"", // 默认路径
filename, // 默认文件名
wildcard, // 文件类型过滤器
wxFD_SAVE | wxFD_OVERWRITE_PROMPT); // 样式
if (saveFileDialog.ShowModal() == wxID_CANCEL) {
// 用户取消下载
handle_general_fail();
return;
}
// 获取选择的保存路径
wxString path = saveFileDialog.GetPath();
auto final_url = Http::encode_url_path(download_url.ToStdString(wxConvUTF8));
Http http_object = Http::get(final_url);
http_object
.on_error([=](std::string body, std::string error, unsigned status) {
handle_general_fail();
wxGetApp().CallAfter([filename]() {
MessageDialog msg_window(nullptr, " " + filename + _L(" download failed") + "\n", _L("DownLoad Failed"),
wxICON_QUESTION | wxOK);
msg_window.ShowModal();
});
})
.on_complete([=](std::string body, unsigned) {
try {
boost::nowide::ofstream file(path.ToStdString(wxConvUTF8), std::ios::binary);
if (!file.is_open()) {
BOOST_LOG_TRIVIAL(error) << "Failed to open file for writing: " << path;
return;
}
file.write(body.c_str(), body.size());
file.close();
wxGetApp().CallAfter([=]() {
MessageDialog msg_window(nullptr, " " + filename + _L(" has already been downloaded") + "\n",
_L("DownLoad Successfully"), wxICON_QUESTION | wxOK);
msg_window.ShowModal();
});
} catch (std::exception& e) {
handle_general_fail();
}
})
.on_progress([&](Http::Progress progress, bool& cancel) {
})
.perform();
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_FinishFilamentMapping()
{
try {
if (wxGetApp().get_web_preprint_dialog()) {
WebPreprintDialog* dialog = dynamic_cast<WebPreprintDialog*>(wxGetApp().get_web_preprint_dialog());
if (dialog) {
// BBS: Use SafeEndModal to prevent duplicate EndModal calls
if(dialog->is_finish()){
dialog->SafeEndModal(wxID_OK);
}else{
dialog->SafeEndModal(wxID_CANCEL);
}
}
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetFileFilamentMapping()
{
try {
std::string filename = m_param_data.count("filename") ? m_param_data["filename"].get<std::string>() : "";
if (filename == "") {
filename = SSWCP::get_active_filename();
}
if (filename == "") {
handle_general_fail();
return;
}
json response = json::object();
// 检查文件是否存在且可读
if (!boost::filesystem::exists(filename) || !boost::filesystem::is_regular_file(filename)) {
handle_general_fail();
return;
}
auto& config = wxGetApp().plater()->get_partplate_list().get_curr_plate()->fff_print()->config();
auto& result = *(wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_slice_result());
/*GCodeProcessor processor;
processor.process_file(filename.data());
auto& result = processor.result();
auto& config = processor.current_dynamic_config();*/
auto time = wxGetApp()
.mainframe->plater()
->get_partplate_list()
.get_curr_plate()
->get_slice_result()
->print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)]
.time;
response["estimated_time"] = time;
auto color_to_int = [](const std::string& oriclr) -> long long {
long long res = 0;
if ((oriclr.size() != 7 && oriclr.size() != 9) || oriclr[0] != '#') {
return -1;
}
if (oriclr.size() == 7) {
for (int i = 1; i <= 6; ++i) {
if (oriclr[7 - i] - '0' >= 0 && oriclr[7 - i] - '0' <= 9) {
res += std::pow(16, i - 1) * (oriclr[7 - i] - '0');
} else {
res += std::pow(16, i - 1) * (oriclr[7 - i] - 'A' + 10);
}
}
} else {
for (int i = 1; i <= 8; ++i) {
if (oriclr[7 - i] - '0' >= 0 && oriclr[7 - i] - '0' <= 9) {
res += std::pow(16, i - 1) * (oriclr[7 - i] - '0');
} else {
res += std::pow(16, i - 1) * (oriclr[7 - i] - 'A' + 10);
}
}
}
return res;
};
// filament colour
if (config.has("filament_colour")) {
auto filament_color = config.option<ConfigOptionStrings>("filament_colour")->values;
std::vector<long long> number_res(filament_color.size(), 0);
std::vector<std::string> str_res(filament_color.size());
for (int i = 0; i < filament_color.size(); ++i) {
number_res[i] = color_to_int(filament_color[i]);
str_res[i] = filament_color[i];
}
response["filament_color"] = number_res;
response["filament_color_rgba"] = str_res;
}
// filament type
if (config.has("filament_type")) {
auto filament_type = config.option<ConfigOptionStrings>("filament_type")->values;
response["filament_type"] = filament_type;
}
// filament used
if (config.has("filament_density")) {
auto filament_density = config.option<ConfigOptionFloats>("filament_density")->values;
std::vector<double> filament_used_g(filament_density.size(), 0);
double total_weight = 0;
for (const auto& pr : result.print_statistics.total_volumes_per_extruder) {
filament_used_g[pr.first] = filament_density[pr.first] * pr.second * 0.001;
total_weight += filament_used_g[pr.first];
}
response["filament_weight"] = filament_used_g;
response["filament_weight_total"] = total_weight;
}
// filament extruder
auto& filament_extruder_map = wxGetApp().app_config->get_filament_extruder_map_ref();
if (!filament_extruder_map.empty()) {
json object;
for (const auto& item : filament_extruder_map) {
object[std::to_string(item.first)] = std::to_string(item.second);
}
response["filament_extruder_map"] = object;
}
// printer model
auto current_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
std::string c_preset = "";
if (current_preset.is_system) {
c_preset = current_preset.name;
} else {
auto base_preset = wxGetApp().preset_bundle->printers.get_preset_base(current_preset);
c_preset = base_preset->name;
}
response["machine_model"] = c_preset;
// file cover
json thumbnails = json::array();
int thumbnail_count = 0;
if (config.has("thumbnails")) {
std::string thumbnails_describe = config.option<ConfigOptionString>("thumbnails")->value;
std::vector<std::pair<double, double>> thumbnails_size;
std::vector<std::string> temp;
do{
size_t pos = thumbnails_describe.find(", ");
std::string tmp = "";
if (pos != std::string::npos) {
tmp = thumbnails_describe.substr(0, pos);
thumbnails_describe = thumbnails_describe.substr(pos + 2);
} else {
tmp = thumbnails_describe;
thumbnails_describe = "";
}
size_t end_tail_pos = tmp.find("/");
if (end_tail_pos == std::string::npos) {
break;
}
tmp = tmp.substr(0, end_tail_pos);
std::string str_width = tmp.substr(0, tmp.find("x"));
std::string str_height = tmp.substr(tmp.find("x") + 1);
thumbnails_size.push_back({atof(str_width.c_str()), atof(str_height.c_str())});
} while (thumbnails_describe != "");
thumbnail_count = thumbnails_size.size();
auto thumbnail_list = load_thumbnails(filename, thumbnail_count);
for (int i = 0; i < thumbnail_list.size(); ++i) {
json thumbnail = json::object();
auto thumbnail_string = "data:image/png;base64," + thumbnail_list[i];
thumbnail["url"] = thumbnail_string;
thumbnail["width"] = thumbnails_size[i].first;
thumbnail["height"] = thumbnails_size[i].second;
thumbnails.push_back(thumbnail);
}
}
response["thumbnails"] = thumbnails;
// file name
response["filename"] = SSWCP::get_display_filename();
response["filepath"] = SSWCP::get_active_filename();
m_res_data = response;
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SetFilamentMappingComplete()
{
try {
if (!m_param_data.count("status")) {
handle_general_fail();
}
std::string status = m_param_data["status"].get<std::string>();
if (status == "success" || status == "canceled") {
int flag = -1;
if (status == "success") {
flag = wxID_OK;
}
//// 耗材绑定成功
//if (status == "success") {
// MessageDialog msg_window(nullptr, " " + _L("setting successfully, continue to print?") + "\n", _L("Print Job Setting"),
// wxICON_QUESTION | wxOK | wxCANCEL);
// flag = msg_window.ShowModal();
//} else {
// MessageDialog msg_window(nullptr, " " + _L("cancel the setting, continue to print?") + "\n", _L("Print Job Setting"),
// wxICON_QUESTION | wxOK | wxCANCEL);
// flag = msg_window.ShowModal();
//}
WebPreprintDialog* dialog = dynamic_cast<WebPreprintDialog*>(wxGetApp().get_web_preprint_dialog());
if (dialog) {
if(flag == wxID_OK){
dialog->set_finish(true);
}else{
dialog->set_finish(false);
}
}
} else {
MessageDialog msg_window(nullptr, " " + _L("setting failed") + "\n", _L("Print Job Setting"),
wxICON_QUESTION | wxOK);
msg_window.ShowModal();
}
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_CameraStartMonitor() {
try {
if (m_param_data.count("domain")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
std::string domain = m_param_data["domain"].get<std::string>();
int interval = m_param_data.count("interval") ? m_param_data["interval"].get<int>() : 2;
bool expect_pw = m_param_data.count("expect_pw") ? m_param_data["expect_pw"].get<bool>() : false;
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_camera_start(domain, interval, expect_pw, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_DeleteMachineFile() {
try {
if(!m_param_data.count("path")){
handle_general_fail(-1, "param [path] required!");
return;
}
std::string path = m_param_data["path"].get<std::string>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_delete_machine_file(path, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_CameraStopMonitor() {
try {
if (m_param_data.count("domain")) {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail();
return;
}
std::string domain = m_param_data["domain"].get<std::string>();
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_canmera_stop(domain, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_SetDeviceName()
{
try {
if (m_param_data.count("name")) {
std::string name = m_param_data["name"].get<std::string>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_set_device_name(name, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} else {
handle_general_fail(-1, "param [name] required!");
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlLed()
{
try {
if (!m_param_data.count("name")) {
handle_general_fail(-1, "param [name] required!");
return;
}
if (!m_param_data.count("white")) {
handle_general_fail(-1, "param [white] required!");
return;
}
std::string name = m_param_data["name"].get<std::string>();
int white = m_param_data["white"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_led(name, white, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlPrintSpeed()
{
try {
if (!m_param_data.count("percentage")) {
handle_general_fail(-1, "param [percentage] required!");
return;
}
int percentage = m_param_data["percentage"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_print_speed(percentage, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_BedMesh_AbortProbeMesh()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_bedmesh_abort_probe_mesh([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlPurifier()
{
try {
int fan_speed = m_param_data.count("fan_speed") ? m_param_data["fan_speed"].get<int>() : -1;
int delay_time = m_param_data.count("delay_time") ? m_param_data["delay_time"].get<int>() : -1;
int work_time = m_param_data.count("work_time") ? m_param_data["work_time"].get<int>() : -1;
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_controlPurifier(fan_speed, delay_time, work_time, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlMainFan()
{
try {
if (!m_param_data.count("speed")) {
handle_general_fail(-1, "param [speed] required!");
return;
}
int speed = m_param_data["speed"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_main_fan(speed, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlGenericFan()
{
try {
if (!m_param_data.count("name")) {
handle_general_fail(-1, "param [fan_id] required!");
return;
}
if (!m_param_data.count("speed")) {
handle_general_fail(-1, "param [speed] required!");
return;
}
std::string name = m_param_data["name"].get<std::string>();
int speed = m_param_data["speed"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_generic_fan(name, speed, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlBedTemp()
{
try {
if (!m_param_data.count("temp")) {
handle_general_fail(-1, "param [temp] required!");
return;
}
int temp = m_param_data["temp"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_bed_temp(temp, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_ControlExtruderTemp()
{
try {
if (!m_param_data.count("temp")) {
handle_general_fail(-1, "param [temp] required!");
return;
}
int index = m_param_data.count("index") ? m_param_data["index"].get<int>() : -1;
int map = m_param_data.count("map") ? m_param_data["map"].get<int>() : -1;
int temp = m_param_data["temp"].get<int>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_control_extruder_temp(temp, index, map, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_FilesThumbnailsBase64()
{
try {
if (!m_param_data.count("path")) {
handle_general_fail(-1, "param [path] required");
return;
}
std::string path = m_param_data["path"].get<std::string>();
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_files_thumbnails_base64(path, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_UploadCameraTimelapse()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_upload_camera_timelapse(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::CmdForwarding()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->test_async_wcp_mqtt_moonraker(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetCameraTimelapseInstance()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_timelapse_instance(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetDeviceDataStorageSpace()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_userdata_space(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_DeleteCameraTimelapse()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_delete_camera_timelapse(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_DefectDetactionConfig()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_defect_detaction_config(m_param_data, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_GetFileListPage()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
if (!m_param_data.count("root") || !m_param_data["root"].is_string()) {
handle_general_fail(-1, "param [root] required or wrong type!");
return;
}
if (!m_param_data.count("files_per_page") || !m_param_data["files_per_page"].is_number()) {
handle_general_fail(-1, "param [files_per_page] required or wrong type");
return;
}
if (!m_param_data.count("page_number") || !m_param_data["page_number"].is_number()) {
handle_general_fail(-1, "param [page_number] required or wrong type");
return;
}
std::string root = m_param_data["root"].get<std::string>();
int files_per_page = m_param_data["files_per_page"].get<int>();
int page_number = m_param_data["page_number"].get<int>();
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_get_file_page_list(root, files_per_page, page_number, [weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineOption_Instance::sw_exception_query()
{
try {
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
if (!host) {
handle_general_fail(-1, "Connection lost!");
return;
}
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
host->async_exception_query([weak_self](const json& response) {
auto self = weak_self.lock();
if (self) {
SSWCP_Instance::on_mqtt_msg_arrived(self, response);
}
});
} catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP_MachineConnect_Instance
void SSWCP_MachineConnect_Instance::process() {
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_Test_connect") {
sw_test_connect();
} else if (m_cmd == "sw_Connect") {
sw_connect();
} else if (m_cmd == "sw_Disconnect") {
sw_disconnect();
} else if (m_cmd == "sw_GetConnectedMachine") {
sw_get_connect_machine();
} else if (m_cmd == "sw_ConnectOtherMachine"){
sw_connect_other_device();
} else if (m_cmd == "sw_GetPincode") {
sw_get_pin_code();
}
else {
handle_general_fail();
}
}
void SSWCP_MachineConnect_Instance::sw_get_pin_code()
{
try {
if (m_param_data.count("ip") && m_param_data.count("userid") && m_param_data.count("nickname")) {
std::string ip = m_param_data["ip"].get<std::string>();
std::string userid = m_param_data["userid"].get<std::string>();
std::string nickname = m_param_data["nickname"].get<std::string>();
int port = m_param_data.count("port") ? m_param_data["port"].get<int>() : 1884;
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
wxGetApp().CallAfter([=]() {
MqttClient* mqtt_client = new MqttClient("mqtt://" + ip + ":" + std::to_string(port), "Snapmaker Orca");
std::string connect_msg = "";
if (mqtt_client->Connect(connect_msg)) {
std::string sub_msg = "success";
if (mqtt_client->Subscribe("cloud/config/response", 1, sub_msg)) {
mqtt_client->SetMessageCallback([weak_self, mqtt_client](const std::string& topic, const std::string& message) {
auto self = weak_self.lock();
if (self) {
if (topic == "cloud/config/response") {
json response = json::parse(message);
if (response.count("result")) {
self->m_res_data = response["result"];
self->send_to_js();
self->finish_job();
std::string dc_msg = "success";
bool flag = mqtt_client->Disconnect(dc_msg);
wxGetApp().CallAfter([mqtt_client]() { delete mqtt_client; });
return;
}
self->handle_general_fail();
}
}
});
// 构建请求消息
json req_body;
req_body["jsonrpc"] = "2.0",
req_body["method"] = "server.client_manager.request_pin_code";
req_body["params"] = json::object();
req_body["params"]["userid"] = userid;
req_body["params"]["nickname"] = nickname;
Moonraker_Mqtt::SequenceGenerator generator;
req_body["id"] = generator.generate_seq_id();
// 发送请求
std::string pub_msg = "success";
if (mqtt_client->Publish("cloud/config/request", req_body.dump(), 1, pub_msg)) {
return;
}
}
return;
}
auto self = weak_self.lock();
if (self) {
self->handle_general_fail();
}
});
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineConnect_Instance::sw_connect_other_device() {
try {
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
wxGetApp().CallAfter([weak_self](){
auto config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
config->set("print_host", "");
config->set("printhost_apikey", "");
auto dialog = SMPhysicalPrinterDialog(wxGetApp().mainframe->plater()->GetParent()); // todo
int res = dialog.ShowModal();
dialog.EndModal(1);
if (dialog.m_connected) {
auto device_dialog = wxGetApp().get_web_device_dialog();
if (device_dialog) {
device_dialog->EndModal(1);
}
} else {
auto self = weak_self.lock();
if (self) {
self->handle_general_fail();
}
}
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineConnect_Instance::sw_test_connect() {
try {
if (m_param_data.count("ip")) {
std::string protocol = "moonraker";
if (m_param_data.count("protcol")) {
protocol = m_param_data["protocol"].get<std::string>();
}
std::string ip = m_param_data["ip"].get<std::string>();
int port = -1;
if (m_param_data.count("port") && m_param_data["port"].is_number_integer()) {
port = m_param_data["port"].get<int>();
}
auto p_config = &(wxGetApp().preset_bundle->printers.get_edited_preset().config);
PrintHostType type = PrintHostType::htMoonRaker;
// todo : 增加输入与type的映射
p_config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value = type;
p_config->set("print_host", ip + (port == -1 ? "" : std::to_string(port)));
std::shared_ptr<PrintHost> host(PrintHost::get_print_host(&wxGetApp().preset_bundle->printers.get_edited_preset().config));
if (!host) {
// 错误处理
finish_job();
} else {
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([this, host] {
wxString msg;
bool res = host->test(msg);
if (res) {
send_to_js();
} else {
// 错误处理
m_status = 1;
m_msg = msg.c_str();
send_to_js();
}
finish_job();
});
}
} else {
// 错误处理
finish_job();
}
} catch (const std::exception&) {
handle_general_fail();
}
}
void SSWCP_MachineConnect_Instance::sw_connect() {
}
void SSWCP_MachineConnect_Instance::sw_get_connect_machine() {
try {
auto devices = wxGetApp().app_config->get_devices();
for (const auto& device : devices) {
if (device.connected) {
m_res_data = device;
break;
}
}
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineConnect_Instance::sw_disconnect() {
bool need_reload = m_param_data.count("need_reload") ? m_param_data["need_reload"].get<bool>() : true;
std::string dev_id = m_param_data.count("dev_id") ? m_param_data["dev_id"] : "";
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_self, need_reload, dev_id](){
auto self = weak_self.lock();
if (dev_id != "") {
DeviceInfo info;
if (wxGetApp().app_config->get_device_info(dev_id, info)) {
if (info.connected == false) {
if (self) {
self->handle_general_fail(-3, dev_id + " is not connected before disconnect!");
return;
}
}
} else {
if (self) {
self->handle_general_fail(-1, dev_id + " is not exist!");
return;
}
}
}
bool res = wxGetApp().sm_disconnect_current_machine(need_reload);
m_first_connected = true;
if (!res) {
if (self) {
self->m_status = 1;
self->m_msg = "disconnected failed";
}
}
wxGetApp().CallAfter([]() {
wxGetApp().app_config->clear_filament_extruder_map();
wxGetApp().preset_bundle->machine_filaments.clear();
wxGetApp().load_current_presets();
});
if (self) {
self->send_to_js();
self->finish_job();
}
});
}
// SSWCP_SliceProject_Instance
// Process machine find commands
void SSWCP_SliceProject_Instance::process()
{
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_NewProject") {
sw_NewProject();
} else if (m_cmd == "sw_OpenProject") {
sw_OpenProject();
} else if (m_cmd == "sw_GetRecentProjects") {
sw_GetRecentProjects();
} else if (m_cmd == "sw_OpenRecentFile") {
sw_OpenRecentFile();
} else if (m_cmd == "sw_DeleteRecentFiles") {
sw_DeleteRecentFiles();
} else if (m_cmd == "sw_SubscribeRecentFiles") {
sw_SubscribeRecentFiles();
} else {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_NewProject()
{
try {
if (!m_param_data.count("preset_name") || m_param_data["preset_name"].get<std::string>() == "")
wxGetApp().request_open_project("<new>");
else {
std::string preset_name = m_param_data["preset_name"].get<std::string>();
wxGetApp().CallAfter([this, preset_name]() {
try {
if (wxGetApp().get_tab(Preset::TYPE_PRINTER)->select_preset(preset_name)) {
wxGetApp().plater()->new_project();
} else {
MessageDialog msg_window(nullptr, "The machine model has not been installed!", _L("Create Failed"),
wxICON_QUESTION | wxOK);
msg_window.ShowModal();
}
} catch (std::exception& e) {
// 异常处理
}
});
}
send_to_js();
finish_job();
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_OpenProject()
{
try {
wxGetApp().request_open_project({});
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_GetRecentProjects()
{
try {
json data;
wxGetApp().mainframe->get_recent_projects(data, INT_MAX);
m_res_data = data;
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_OpenRecentFile()
{
try {
if (m_param_data.count("path")) {
std::string path = m_param_data["path"].get<std::string>();
if (path != "") {
wxGetApp().request_open_project(path);
} else {
handle_general_fail();
return;
}
} else {
handle_general_fail();
return;
}
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_DeleteRecentFiles()
{
try {
if (m_param_data.count("paths") && m_param_data["paths"].is_array()) {
auto paths = m_param_data["paths"];
send_to_js();
if (paths.size() == 0) {
wxGetApp().sm_request_remove_project("");
} else {
for (size_t i = 0; i < paths.size(); ++i) {
wxGetApp().sm_request_remove_project(paths[i].get<std::string>());
}
}
} else {
handle_general_fail();
return;
}
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_SliceProject_Instance::sw_SubscribeRecentFiles()
{
try {
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
wxGetApp().m_recent_file_subscribers[m_webview] = weak_self;
} catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP_UserLogin_Instance
void SSWCP_UserLogin_Instance::process()
{
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_UserLogin") {
sw_UserLogin();
} else if (m_cmd == "sw_UserLogout") {
sw_UserLogout();
} else if (m_cmd == "sw_GetUserLoginState") {
sw_GetUserLoginState();
} else if (m_cmd == "sw_SubscribeUserLoginState") {
sw_SubscribeUserLoginState();
}
else if (m_cmd == UPDATE_PRIVACY_STATUS) {
sw_SubUserUpdatePrivacy();
} else if (m_cmd == GET_PRIVACY_STATUS) {
sw_GetUserUpdatePrivacy();
} else if (m_cmd == DOWNLOAD_FILE) {
sw_DownloadFile();
} else if (m_cmd == CANCEL_DOWNLOAD) {
sw_CancelDownload();
} else if (m_cmd == FILE_VIEW) {
sw_FileView();
}
else {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_UserLogin()
{
try {
send_to_js();
finish_job();
bool show = m_param_data.count("show") ? m_param_data["show"].get<bool>() : true;
wxGetApp().CallAfter([show]() {
wxGetApp().sm_request_login(show);
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_UserLogout()
{
try {
send_to_js();
wxGetApp().sm_request_user_logout();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_GetUserLoginState()
{
try {
json data;
auto pInfo = wxGetApp().sm_get_userinfo();
if (pInfo) {
bool islogin = pInfo->is_user_login();
if (islogin) {
data["status"] = "online";
data["nickname"] = pInfo->get_user_name();
data["icon"] = pInfo->get_user_icon_url();
data["token"] = pInfo->get_user_token();
data["userid"] = pInfo->get_user_id();
data["account"] = pInfo->get_user_account();
} else {
data["status"] = "offline";
}
m_res_data = data;
send_to_js();
finish_job();
} else {
handle_general_fail();
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_GetUserUpdatePrivacy()
{
json data;
auto isAgree = wxGetApp().app_config->get("app", PRIVACY_POLICY_FLAGS);
bool isUserAgree = false;
if (isAgree == "true")
isUserAgree = true;
data[PRIVACY_POLICY_FLAGS] = isUserAgree;
m_res_data = data;
send_to_js();
finish_job();
}
void SSWCP_UserLogin_Instance::sw_DownloadFile()
{
try {
std::string fileName = m_param_data.count("file_name") ? m_param_data["file_name"].get<std::string>() : "";
std::string fileUrl = m_param_data.count("file_url") ? m_param_data["file_url"].get<std::string>() : "";
if (fileUrl.empty() || fileName.empty()) {
handle_general_fail(-1, "file_url and file_name are required");
return;
}
// Use Download Manager
DownloadManager* download_mgr = wxGetApp().download_manager();
if (!download_mgr) {
handle_general_fail(-1, "Download Manager not available");
return;
}
wxGetApp().mainframe->downloadOpenProject(fileUrl, fileName, "");
m_status = 0;
m_msg = "Download started";
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail(-1, e.what());
}
}
void SSWCP_UserLogin_Instance::sw_DownloadFileEx() {
try {
std::string fileName = m_param_data.count("file_name") ? m_param_data["file_name"].get<std::string>() : "";
std::string fileUrl = m_param_data.count("file_url") ? m_param_data["file_url"].get<std::string>() : "";
if (fileUrl.empty() || fileName.empty()) {
handle_general_fail(-1, "file_url and file_name are required");
return;
}
// Use Download Manager
DownloadManager* download_mgr = wxGetApp().download_manager();
if (!download_mgr) {
handle_general_fail(-1, "Download Manager not available");
return;
}
size_t task_id = download_mgr->start_wcp_download(fileUrl,
fileName,
shared_from_this(),
true);
json response;
response["task_id"] = task_id;
response["file_name"] = fileName;
response["file_url"] = fileUrl;
m_res_data = response;
m_status = 0;
m_msg = "Download started";
send_to_js();
} catch (std::exception& e) {
handle_general_fail(-1, e.what());
}
}
void SSWCP_UserLogin_Instance::sw_CancelDownload() {
try {
size_t task_id = m_param_data.count("task_id") ? m_param_data["task_id"].get<size_t>() : 0;
if (task_id == 0) {
handle_general_fail(-1, "task_id is required");
return;
}
DownloadManager* download_mgr = wxGetApp().download_manager();
if (!download_mgr) {
handle_general_fail(-1, "WCP Download Manager not available");
return;
}
bool success = download_mgr->cancel_download(task_id);
if (success) {
json response;
response["task_id"] = task_id;
response["canceled"] = true;
m_res_data = response;
m_status = 0;
m_msg = "Download canceled";
} else {
handle_general_fail(-1, "Failed to cancel download or task not found");
return;
}
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail(-1, e.what());
}
}
void SSWCP_UserLogin_Instance::sw_FileView() {
try {
std::string file_path = m_param_data.count("file_path") ? m_param_data["file_path"].get<std::string>() : "";
wxFileName file(file_path);
if (!file.FileExists()) {
handle_general_fail();
//wxMessageBox(wxT("file not exsit"), wxT("tips"), wxOK | wxICON_WARNING);
return;
}
std::weak_ptr<SSWCP_Instance> weak_self = shared_from_this();
wxGetApp().CallAfter([file_path, weak_self]() {
auto self = weak_self.lock();
if (!self) {
return;
}
//open file in folder
desktop_open_any_folderEx(file_path);
self->send_to_js();
self->finish_job();
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_SubUserUpdatePrivacy()
{
try {
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
wxGetApp().m_user_update_privacy_subscribers[m_webview] = weak_ptr;
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_UserLogin_Instance::sw_SubscribeUserLoginState()
{
try {
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
wxGetApp().m_user_login_subscribers[m_webview] = weak_ptr;
}
catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP_MachineManage_Instance
void SSWCP_MachineManage_Instance::process()
{
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_GetLocalDevices") {
sw_GetLocalDevices();
} else if (m_cmd == "sw_AddDevice") {
sw_AddDevice();
} else if (m_cmd == "sw_SubscribeLocalDevices") {
sw_SubscribeLocalDevices();
} else if (m_cmd == "sw_RenameDevice") {
sw_RenameDevice();
} else if (m_cmd == "sw_SwitchModel") {
sw_SwitchModel();
} else if (m_cmd == "sw_DeleteDevices") {
sw_DeleteDevices();
} else {
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_GetLocalDevices()
{
try {
auto devices = wxGetApp().app_config->get_devices();
m_res_data = devices;
send_to_js();
finish_job();
}
catch (std::exception& e)
{
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_SubscribeLocalDevices()
{
try {
auto self = shared_from_this();
wxGetApp().m_device_card_subscribers[m_webview] = self;
} catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP_PageStateChange_Instance
void SSWCP_PageStateChange_Instance::process()
{
if (m_event_id != "") {
json header;
send_to_js();
m_header.clear();
m_header["event_id"] = m_event_id;
}
if (m_cmd == "sw_SubscribePageStateChange") {
sw_SubscribePageStateChange();
} else if (m_cmd == "sw_UnsubscribePageStateChange") {
sw_UnsubscribePageStateChange();
} else {
handle_general_fail();
}
}
void SSWCP_PageStateChange_Instance::sw_SubscribePageStateChange()
{
try {
auto self = shared_from_this();
wxGetApp().m_page_state_subscribers[m_webview] = self;
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_PageStateChange_Instance::sw_UnsubscribePageStateChange()
{
try {
auto& page_state_map = wxGetApp().m_page_state_subscribers;
std::string event_id = m_param_data.count("event_id") ? m_param_data["event_id"].get<std::string>() : "";
for (auto iter = page_state_map.begin(); iter != page_state_map.end();) {
if (iter->first == m_webview) {
auto ptr = iter->second.lock();
if (ptr) {
if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) {
iter = page_state_map.erase(iter);
} else {
iter++;
}
} else {
iter = page_state_map.erase(iter);
}
} else {
iter++;
}
}
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_AddDevice()
{
try {
wxGetApp().CallAfter([] {
if (wxGetApp().web_device_dialog)
delete wxGetApp().web_device_dialog;
wxGetApp().web_device_dialog = new WebDeviceDialog;
wxGetApp().web_device_dialog->run();
});
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_RenameDevice()
{
try {
if (m_param_data.count("dev_id") && m_param_data.count("dev_name")) {
std::string dev_id = m_param_data["dev_id"].get<std::string>();
std::string dev_name = m_param_data["dev_name"].get<std::string>();
DeviceInfo info;
wxGetApp().app_config->get_device_info(dev_id, info);
info.dev_name = dev_name;
wxGetApp().app_config->save_device_info(info);
wxGetApp().CallAfter([] {
// wcp订阅
json data = wxGetApp().app_config->get_devices();
wxGetApp().device_card_notify(data);
});
send_to_js();
finish_job();
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_DeleteDevices()
{
try {
if (m_param_data.count("dev_ids") && m_param_data["dev_ids"].is_array()) {
auto ids = m_param_data["dev_ids"];
if (ids.size() == 0) {
auto devices = wxGetApp().app_config->get_devices();
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].connected) {
std::shared_ptr<PrintHost> current_host;
wxGetApp().get_connect_host(current_host);
if (current_host && current_host->get_sn() == devices[i].sn) {
wxString msg = "";
json param;
current_host->disconnect(msg, param);
}
}
}
wxGetApp().app_config->clear_device_info();
} else {
for (size_t i = 0; i < ids.size(); ++i) {
std::string dev_id = ids[i].get<std::string>();
DeviceInfo info;
if (wxGetApp().app_config->get_device_info(dev_id, info)) {
if (info.connected) {
std::shared_ptr<PrintHost> current_host;
wxGetApp().get_connect_host(current_host);
wxString msg = "";
json param;
current_host->disconnect(msg, param);
}
}
wxGetApp().app_config->remove_device_info(dev_id);
}
}
wxGetApp().CallAfter([] {
// wcp订阅
json data = wxGetApp().app_config->get_devices();
wxGetApp().device_card_notify(data);
});
send_to_js();
finish_job();
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MachineManage_Instance::sw_SwitchModel()
{
try {
if (m_param_data.count("dev_id")) {
std::string dev_id = m_param_data["dev_id"].get<std::string>();
send_to_js();
wxGetApp().CallAfter([dev_id]() {
WebPresetDialog dialog(&wxGetApp());
dialog.m_device_id = dev_id;
dialog.run();
});
finish_job();
} else {
handle_general_fail();
}
} catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP_MqttAgent_Instance
std::unordered_map<wxWebView*, std::pair<std::string, std::shared_ptr<MqttClient>>> SSWCP_MqttAgent_Instance::m_mqtt_engine_map;
std::mutex SSWCP_MqttAgent_Instance::m_engine_map_mtx;
std::map<std::pair<std::string, wxWebView*>, std::string> SSWCP_MqttAgent_Instance::m_subscribe_map;
std::map<std::pair<std::string, wxWebView*>, std::weak_ptr<SSWCP_Instance>> SSWCP_MqttAgent_Instance::m_subscribe_instance_map;
WebPresetDialog* SSWCP_MqttAgent_Instance::m_dialog = nullptr;
void SSWCP_MqttAgent_Instance::process()
{
if (m_cmd == "sw_create_mqtt_client") {
sw_create_mqtt_client();
} else if (m_cmd == "sw_mqtt_connect") {
sw_mqtt_connect();
} else if (m_cmd == "sw_mqtt_disconnect") {
sw_mqtt_disconnect();
} else if (m_cmd == "sw_mqtt_subscribe") {
sw_mqtt_subscribe();
} else if (m_cmd == "sw_mqtt_unsubscribe") {
sw_mqtt_unsubscribe();
} else if (m_cmd == "sw_mqtt_publish") {
sw_mqtt_publish();
} else if (m_cmd == "sw_mqtt_set_engine") {
sw_mqtt_set_engine();
} else {
handle_general_fail();
}
}
// 校验mqtt引擎id
bool SSWCP_MqttAgent_Instance::validate_id(const std::string& id)
{
bool flag = true;
m_engine_map_mtx.lock();
if (!m_mqtt_engine_map.count(m_webview)) {
flag = false;
} else {
flag = m_mqtt_engine_map[m_webview].first == id;
}
m_engine_map_mtx.unlock();
return flag;
}
// webview析构回调
void SSWCP_MqttAgent_Instance::set_Instance_illegal()
{
SSWCP_Instance::set_Instance_illegal();
clean_current_engine();
}
// 清空当前mqtt实例
void SSWCP_MqttAgent_Instance::clean_current_engine()
{
//清除该实例的所有订阅
for (auto iter = m_subscribe_map.begin(); iter != m_subscribe_map.end();) {
if (iter->first.second == m_webview) {
iter = m_subscribe_map.erase(iter);
} else {
iter++;
}
}
for (auto iter = m_subscribe_instance_map.begin(); iter != m_subscribe_instance_map.end();) {
if (iter->first.second == m_webview) {
iter = m_subscribe_instance_map.erase(iter);
} else {
iter++;
}
}
m_engine_map_mtx.lock();
m_mqtt_engine_map.erase(m_webview);
m_engine_map_mtx.unlock();
}
// mqtt静态消息回调
void SSWCP_MqttAgent_Instance::mqtt_msg_cb(const std::string& topic, const std::string& payload, void* client)
{
auto& wcp_loger = GUI::WCP_Logger::getInstance();
BOOST_LOG_TRIVIAL(info) << "[Mqtt_Agent] 收到MQTT消息主题: " << topic << ", 载荷长度: " << payload.length();
wcp_loger.add_log("收到MQTTS消息主题: " + topic + ", 载荷长度: " + std::to_string(payload.length()), false, "", "Mqtt_Agent",
"info");
try {
wxGetApp().CallAfter([topic, payload, client]() {
for (const auto& item : SSWCP_MqttAgent_Instance::m_subscribe_map) {
std::string id_topic = item.second;
std::string target_topic = topic;
if (id_topic.find("+") != std::string::npos) {
id_topic = id_topic.substr(id_topic.find_first_of("/"));
target_topic = topic.substr(topic.find_first_of("/"));
}
if (id_topic == target_topic) {
if (SSWCP_MqttAgent_Instance::m_subscribe_instance_map.count(item.first)) {
auto& instance = SSWCP_MqttAgent_Instance::m_subscribe_instance_map[item.first];
if (auto self = instance.lock()) {
auto mqtt_self = dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(self);
if (mqtt_self && (void*)(mqtt_self->get_current_engine().get()) == client) {
self->m_res_data["topic"] = topic;
self->m_res_data["data"] = payload;
self->send_to_js();
}
}
} else {
return;
}
}
}
});
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "[Moonraker_Mqtt] 处理MQTT消息异常: " << e.what();
wcp_loger.add_log("处理MQTTS消息异常: " + std::string(e.what()), false, "", "Moonraker_Mqtt", "error");
}
}
// 创建mqtt实例
void SSWCP_MqttAgent_Instance::sw_create_mqtt_client()
{
try {
// 解析参数
std::string server_address = "";
std::string clientId = "";
std::string ca = "";
std::string cert = "";
std::string key = "";
std::string username = "";
std::string password = "";
bool clean_session = false;
if (m_param_data.count("server_address") || !m_param_data["server_address"].is_string()) {
server_address = m_param_data["server_address"].get<std::string>();
if (server_address == "") {
handle_general_fail(-1, "the value of param [server_address] is illegal");
return;
}
}
else {
handle_general_fail(-1, "param [server_address] is required or wrong type");
return;
}
if (m_param_data.count("clientId") || !m_param_data["clientId"].is_string()) {
clientId = m_param_data["clientId"].get<std::string>();
if (clientId == "") {
handle_general_fail(-1, "the value of param [clientId] is illegal");
return;
}
} else {
handle_general_fail(-1, "param [clientId] is required or wroing type");
return;
}
ca = m_param_data.count("ca") ? m_param_data["ca"].get<std::string>() : "";
cert = m_param_data.count("cert") ? m_param_data["cert"].get<std::string>() : "";
key = m_param_data.count("key") ? m_param_data["key"].get<std::string>() : "";
clean_session = m_param_data.count("clean_session") ? m_param_data["clean_session"].get<bool>() : false;
username = m_param_data.count("username") ? m_param_data["username"].get<std::string>() : "";
password = m_param_data.count("password") ? m_param_data["password"].get<std::string>() : "";
// 确认mqtt连接类型并创建实例
std::shared_ptr<MqttClient> client = nullptr;
std::string type = "mqtt";
if (ca != "" && cert != "" && key != "") {
type = "mqtts";
client.reset(new MqttClient(server_address, clientId, ca, cert, key, username, password, clean_session));
}else{
client.reset(new MqttClient(server_address, clientId, username, password, clean_session));
}
if (client == nullptr) {
// 创建失败
handle_general_fail(-1, "create instance failed");
return;
}
// 清空当前m_clinet的订阅列表
auto ptr = get_current_engine();
if (!ptr) {
ptr.reset();
}
clean_current_engine();
// 替换新引擎
bool flag = set_current_engine({std::to_string(int64_t(client.get())), client});
if (!flag) {
handle_general_fail(-1, "create failed");
return;
}
// 绑定静态回调
client->SetMessageCallback(SSWCP_MqttAgent_Instance::mqtt_msg_cb);
m_res_data["type"] = type;
m_res_data["id"] = std::to_string(int64_t(get_current_engine().get()));
send_to_js();
finish_job();
} catch (std::exception& e) {
handle_general_fail();
}
}
// mqtt引擎建立连接
void SSWCP_MqttAgent_Instance::sw_mqtt_connect()
{
try {
if (!m_param_data.count("id") || !m_param_data["id"].is_string()) {
handle_general_fail(-1, "param [id] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_connect param [id] is required or wrong type"), DEVICE_CONNECT_ERR);
return;
}
std::string id = m_param_data["id"].get<std::string>();
if (!validate_id(id)) {
handle_general_fail(-1, "id is illegal");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_connect id is illegal"),DEVICE_CONNECT_ERR);
return;
}
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
auto engine = get_current_engine();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_ptr, engine]() {
if (!weak_ptr.lock()) {
return;
}
auto self = std::dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(weak_ptr.lock());
engine->SetConnectionFailureCallback([engine]() {
std::string msg = "";
engine->Disconnect(msg);
});
std::string msg;
bool flag = engine->Connect(msg);
wxGetApp().CallAfter([weak_ptr, msg, flag]() {
auto self = weak_ptr.lock();
if (self) {
if (flag) {
self->m_msg = msg;
self->send_to_js();
self->finish_job();
} else {
self->handle_general_fail(-1, msg);
}
}
});
});
} catch (std::exception& e) {
handle_general_fail();
}
}
// mqtt引擎断开连接
void SSWCP_MqttAgent_Instance::sw_mqtt_disconnect()
{
try {
if (!m_param_data.count("id") || !m_param_data["id"].is_string()) {
handle_general_fail(-1, "param [id] is required or wrong type");
return;
}
std::string id = m_param_data["id"].get<std::string>();
if (!validate_id(id)) {
handle_general_fail(-1, "id is illegal");
return;
}
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
auto engine = get_current_engine();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_ptr, engine]() {
if (!weak_ptr.lock()) {
return;
}
auto self = std::dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(weak_ptr.lock());
std::string msg = "success";
bool flag = engine->Disconnect(msg);
wxGetApp().CallAfter([weak_ptr, msg, flag]() {
auto self = weak_ptr.lock();
if (self) {
if (flag) {
self->m_msg = msg;
self->send_to_js();
self->finish_job();
} else {
self->handle_general_fail(-1, msg);
}
}
});
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
// 订阅topic
void SSWCP_MqttAgent_Instance::sw_mqtt_subscribe()
{
try {
if (!m_param_data.count("id") || !m_param_data["id"].is_string()) {
handle_general_fail(-1, "param [id] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_subscribe param [id] is required or wrong type"), DEVICE_SUBSCRIBE_ERR);
return;
}
std::string id = m_param_data["id"].get<std::string>();
if (!validate_id(id)) {
handle_general_fail(-1, "id is illegal");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_subscribe id is illegal with:")+id,DEVICE_SUBSCRIBE_ERR);
return;
}
if (m_event_id == "") {
handle_general_fail(-1, "event_id is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_subscribe event_id is required or wrong type with:") + id,DEVICE_SUBSCRIBE_ERR);
return;
}
std::string event_id = m_event_id;
if (!m_param_data.count("topic") || !m_param_data["topic"].is_string()) {
handle_general_fail(-1, "param [topic] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_subscribe param [topic] is required or wrong type"),DEVICE_SUBSCRIBE_ERR);
return;
}
std::string topic = m_param_data["topic"].get<std::string>();
m_subscribe_map[{event_id, m_webview}] = topic;
m_subscribe_instance_map[{event_id, m_webview}] = shared_from_this();
if (!m_param_data.count("qos") || !m_param_data["qos"].is_number()) {
handle_general_fail(-1, "param [qos] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_subscribe param [qos] is required or wrong type"), DEVICE_SUBSCRIBE_ERR);
return;
}
int qos = m_param_data["qos"].get<int>();
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
auto engine = get_current_engine();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_ptr, engine, topic, qos]() {
if (!weak_ptr.lock()) {
return;
}
auto self = std::dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(weak_ptr.lock());
std::string msg = "success";
bool flag = engine->Subscribe(topic, qos, msg);
wxGetApp().CallAfter([weak_ptr, msg, flag]() {
auto self = weak_ptr.lock();
if (self) {
if (flag) {
// 回复后, 设置event_id, 长期保留对象
if (self->m_event_id != "") {
self->m_msg = msg;
self->send_to_js();
json header;
self->m_header.clear();
self->m_header["event_id"] = self->m_event_id;
} else {
self->handle_general_fail(-1, "event_id is null");
}
} else {
self->handle_general_fail(-1, msg);
}
}
});
});
}
catch (std::exception& e) {
handle_general_fail();
}
}
// 取消订阅
void SSWCP_MqttAgent_Instance::sw_mqtt_unsubscribe() {
try {
if (!m_param_data.count("id") || !m_param_data["id"].is_string()) {
handle_general_fail(-1, "param [id] is required or wrong type");
return;
}
std::string id = m_param_data["id"].get<std::string>();
if (!validate_id(id)) {
handle_general_fail(-1, "id is illegal");
return;
}
if (!m_param_data.count("topic") || !m_param_data["topic"].is_string()) {
handle_general_fail(-1, "param [topic] is required or wrong type");
return;
}
std::string topic = m_param_data["topic"].get<std::string>();
// 维护订阅topic表和eventid实例表
for (auto iter = m_subscribe_map.begin();
iter != m_subscribe_map.end(); ) {
if (iter->second == topic) {
if (m_subscribe_instance_map.count(iter->first)) {
m_subscribe_instance_map.erase(iter->first);
}
iter = m_subscribe_map.erase(iter);
} else {
++iter;
}
}
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
auto engine = get_current_engine();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_ptr, engine, topic]() {
if (!weak_ptr.lock()) {
return;
}
auto self = std::dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(weak_ptr.lock());
std::string msg = "success";
bool flag = engine->Unsubscribe(topic, msg);
wxGetApp().CallAfter([weak_ptr, msg, flag]() {
auto self = weak_ptr.lock();
if (self) {
if (flag) {
self->m_msg = msg;
self->send_to_js();
self->finish_job();
} else {
self->handle_general_fail(-1, msg);
}
}
});
});
} catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MqttAgent_Instance::sw_mqtt_set_engine()
{
try {
if (!m_param_data.count("engine_id") || !m_param_data["engine_id"].is_string()) {
handle_general_fail(-1, "param [engine_id] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine param [engine_id] is required or wrong type"),DEVICE_SET_ENGINE_ERR);
return;
}
std::string engine_id = m_param_data["engine_id"].get<std::string>();
if (!validate_id(engine_id)) {
handle_general_fail(-1, "id is illegal");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine id is illegal with:") + engine_id, DEVICE_SET_ENGINE_ERR);
return;
}
if (!m_param_data.count("ip") || !m_param_data["ip"].is_string()) {
handle_general_fail(-1, "param [ip] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine param [ip] is required or wrong type"),DEVICE_SET_ENGINE_ERR);
return;
}
std::string ip = m_param_data["ip"].get<std::string>();
if (!m_param_data.count("port") || !m_param_data["port"].is_number()) {
handle_general_fail(-1, "param [port] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine param [port] is required or wrong type"), DEVICE_SET_ENGINE_ERR);
return;
}
bool reload_device_view = m_param_data.count("need_reload") ? m_param_data["need_reload"].get<bool>() : true;
int port = m_param_data["port"].get<int>();
auto config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
PrintHostType type = PrintHostType::htMoonRaker_mqtt;
// todo : 增加输入与type的映射
config.option<ConfigOptionEnum<PrintHostType>>("host_type")->value = type;
config.set("print_host", ip + (port == -1 ? "" : ":" + std::to_string(port)));
std::shared_ptr<PrintHost> tmp_host(PrintHost::get_print_host(&config));
wxGetApp().set_connect_host(tmp_host);
wxGetApp().set_host_config(config);
std::shared_ptr<Moonraker_Mqtt> host = dynamic_pointer_cast<Moonraker_Mqtt>(tmp_host);
if (host) {
auto engine = get_current_engine();
if (engine == nullptr) {
handle_general_fail(-1, "invalid engine");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine invalid engine"),DEVICE_SET_ENGINE_ERR);
return;
}
BOOST_LOG_TRIVIAL(info) << "[SSWCP_MqttAgent_Instance] 检查引擎连接状态...";
if (!engine->CheckConnected()) {
BOOST_LOG_TRIVIAL(error) << "[SSWCP_MqttAgent_Instance] 引擎连接状态异常";
handle_general_fail(-1, "engine connection lost");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine engine connection lost"), DEVICE_SET_ENGINE_ERR);
return;
}
BOOST_LOG_TRIVIAL(info) << "[SSWCP_MqttAgent_Instance] 引擎连接状态正常";
std::string msg = "success";
BOOST_LOG_TRIVIAL(info) << "[SSWCP_MqttAgent_Instance] 设置引擎...";
bool flag = host->set_engine(engine, msg);
BOOST_LOG_TRIVIAL(info) << "[SSWCP_MqttAgent_Instance] 引擎设置完成, flag: " << flag;
if (flag)
{
if (m_param_data.count("ip")) {
std::string ip = m_param_data["ip"].get<std::string>();
int port = -1;
if (m_param_data.count("port") && m_param_data["port"].is_number_integer()) {
port = m_param_data["port"].get<int>();
}
// test
if (port == -1 || port == 1883) {
port = 1884;
}
json connect_params;
if (m_param_data.count("sn") && m_param_data["sn"].is_string()) {
connect_params["sn"] = m_param_data["sn"].get<std::string>();
host->m_sn_mtx.lock();
host->m_sn = m_param_data["sn"].get<std::string>();
host->m_sn_mtx.unlock();
} else {
handle_general_fail(-1, "param [sn] is required or wrong type");
return;
}
// 序列化参数
if (m_param_data.count("code")){
connect_params["code"] = m_param_data["code"];
}
if (m_param_data.count("ca")) {
connect_params["ca"] = m_param_data["ca"];
host->m_ca = m_param_data["ca"].get<std::string>();
}
if (m_param_data.count("cert")) {
connect_params["cert"] = m_param_data["cert"];
host->m_cert = m_param_data["cert"].get<std::string>();
}
if (m_param_data.count("key")) {
connect_params["key"] = m_param_data["key"];
host->m_key = m_param_data["key"].get<std::string>();
}
if (m_param_data.count("user")) {
connect_params["user"] = m_param_data["user"];
host->m_user_name = m_param_data["user"].get<std::string>();
}
if (m_param_data.count("password")) {
connect_params["password"] = m_param_data["password"];
host->m_password = m_param_data["password"].get<std::string>();
}
if (m_param_data.count("port")) {
connect_params["port"] = m_param_data["port"];
host->m_port = m_param_data["port"].get<int>();
}
if (m_param_data.count("clientId")) {
connect_params["clientId"] = m_param_data["clientId"];
host->m_client_id = m_param_data["clientId"].get<std::string>();
}
std::string link_mode = m_param_data.count("link_mode") ? m_param_data["link_mode"] : "lan";
connect_params["link_mode"] = link_mode;
std::string id = m_param_data.count("id") ? m_param_data["id"].get<std::string>() : "";
std::string userid = m_param_data.count("userid") ? m_param_data["userid"].get<std::string>() : "";
if (!host) {
handle_general_fail(-1, "host created failed");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_set_engine host created failed"), DEVICE_SET_ENGINE_ERR);
return;
} else {
auto weak_self = std::weak_ptr<SSWCP_Instance>(shared_from_this());
// 设置断联回调
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_self, host, connect_params, link_mode, id, userid, reload_device_view] {
auto self = weak_self.lock();
wxString msg = "";
json params;
host->set_connection_lost([]() {
wxGetApp().CallAfter([]() {
SSWCP_Instance::m_first_connected = true;
wxGetApp().app_config->clear_filament_extruder_map();
wxGetApp().preset_bundle->machine_filaments.clear();
wxGetApp().load_current_presets();
});
wxGetApp().CallAfter([]() {
wxGetApp().app_config->set("use_new_connect", "false");
auto p_config = &(wxGetApp().preset_bundle->printers.get_edited_preset().config);
p_config->set("print_host", "");
std::shared_ptr<PrintHost> ptr = nullptr;
wxGetApp().get_connect_host(ptr);
if (ptr) {
wxString disconn_msg = "";
json disconn_param;
ptr->disconnect(disconn_msg, disconn_param);
}
wxGetApp().set_connect_host(nullptr);
auto devices = wxGetApp().app_config->get_devices();
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].connected) {
devices[i].connected = false;
wxGetApp().app_config->save_device_info(devices[i]);
break;
}
}
// 更新卡片
json param;
param["command"] = "local_devices_arrived";
param["sequece_id"] = "10001";
param["data"] = devices;
std::string logout_cmd = param.dump();
wxString strJS = wxString::Format("window.postMessage(%s)", logout_cmd);
GUI::wxGetApp().run_script(strJS);
// wcp订阅
json data = devices;
wxGetApp().device_card_notify(data);
MessageDialog msg_window(nullptr, " " + _L("Connection has been disconnected and recovery attempt failed. Please reconnect.") + "\n", _L("Machine Disconnected"),
wxICON_QUESTION | wxOK);
msg_window.ShowModal();
wxGetApp().set_connect_host(nullptr);
wxGetApp().mainframe->plater()->sidebar().update_all_preset_comboboxes();
});
});
bool res = true;
std::string ip_port = host->get_host();
if (res) {
int pos = ip_port.find(':');
std::string ip = ip_port;
if (pos != std::string::npos) {
ip = ip_port.substr(0, pos);
}
// 更新其他设备连接状态为断开
auto devices = wxGetApp().app_config->get_devices();
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].connected) {
devices[i].connected = false;
wxGetApp().app_config->save_device_info(devices[i]);
break;
}
}
// 查询机器的机型和喷嘴信息
std::string machine_type = "";
std::vector<std::string> nozzle_diameters;
std::string device_name = "";
std::shared_ptr<PrintHost> host = nullptr;
wxGetApp().get_connect_host(host);
// 设置sn
if (SSWCP::query_machine_info(host, machine_type, nozzle_diameters, device_name) && machine_type != "") {
wxGetApp().CallAfter([ip, host, link_mode, machine_type, connect_params, nozzle_diameters, device_name,
id, userid, reload_device_view]() {
// 查询成功
DeviceInfo info;
info.ip = ip;
info.dev_id = host->get_sn() != "" ? host->get_sn() : ip;
info.dev_name = ip;
info.connected = true;
info.link_mode = link_mode;
info.id = id;
info.userid = userid;
;
info.model_name = machine_type;
info.protocol = int(PrintHostType::htMoonRaker_mqtt);
if (connect_params.count("sn") && connect_params["sn"].is_string()) {
std::string sn = host->get_sn();
info.sn = connect_params["sn"].get<std::string>();
if (sn != "" && sn != info.sn) {
info.sn = sn;
}
info.dev_name = info.sn != "" ? info.sn : info.dev_name;
info.dev_id = info.sn != "" ? info.sn : info.ip;
}
if (device_name != "") {
info.dev_name = device_name;
}
size_t vendor_pos = machine_type.find_first_of(" ");
if (vendor_pos != std::string::npos) {
std::string vendor = machine_type.substr(0, vendor_pos);
std::string machine_cover = LOCALHOST_URL +
std::to_string(wxGetApp().m_page_http_server.get_port()) +
"/profiles/" + vendor + "/" + machine_type + "_cover.png";
info.img = machine_cover;
}
auto auth_info = host->get_auth_info();
try {
info.ca = /* auth_info["ca"]*/ "";
info.cert = /* auth_info["cert"]*/ "";
info.key = /* auth_info["key"]*/ "";
info.user = auth_info["user"];
info.password = auth_info["password"];
info.port = auth_info["port"];
info.clientId = auth_info["clientId"];
} catch (std::exception& e) {}
DeviceInfo query_info;
bool exist = wxGetApp().app_config->get_device_info(info.dev_id, query_info);
if (nozzle_diameters.empty()) {
if (exist) {
query_info.connected = true;
wxGetApp().app_config->save_device_info(query_info);
} else {
wxGetApp().app_config->save_device_info(info);
MessageDialog msg_window(nullptr,
ip + " " + _L("The target machine model has been detected as") +
"" + machine_type + "\n" +
_L("Please bind the nozzle information") + "\n",
_L("Nozzle Bind"), wxICON_QUESTION | wxOK);
msg_window.ShowModal();
m_dialog->m_bind_nozzle = true;
m_dialog->m_device_id = ip;
m_dialog->run();
}
} else {
info.nozzle_sizes = nozzle_diameters;
info.preset_name = machine_type + " (" + nozzle_diameters[0] + " nozzle)";
wxGetApp().app_config->save_device_info(info);
m_dialog->m_device_id = ip;
// 检查是否该预设已经选入系统
{
std::lock_guard<std::mutex> lock(m_ProfileJson_mutex);
int nModel = m_ProfileJson["model"].size();
bool isFind = false;
for (int m = 0; m < nModel; m++) {
if (m_ProfileJson["model"][m]["model"].get<std::string>() == info.model_name) {
// 绑定的预设已被选入系统
isFind = true;
std::string nozzle_selected = m_ProfileJson["model"][m]["nozzle_selected"]
.get<std::string>();
std::string se_nozz_selected = nozzle_diameters[0];
if (nozzle_selected.find(se_nozz_selected) == std::string::npos) {
nozzle_selected += ";" + se_nozz_selected;
m_ProfileJson["model"][m]["nozzle_selected"] = nozzle_selected;
}
break;
}
}
if (!isFind) {
json new_item;
new_item["vendor"] = "Snapmaker";
new_item["model"] = info.model_name;
new_item["nozzle_selected"] = nozzle_diameters[0];
m_ProfileJson["model"].push_back(new_item);
}
}
wxGetApp().mainframe->plater()->sidebar().update_all_preset_comboboxes(false);
m_dialog->SaveProfile();
bool flag = false;
m_dialog->apply_config(wxGetApp().app_config, wxGetApp().preset_bundle, wxGetApp().preset_updater,
flag);
wxGetApp().update_mode();
}
});
} else {
wxGetApp().CallAfter([connect_params, ip, host, link_mode, id, userid]() {
// 是否为连接过的设备
DeviceInfo query_info;
std::string dev_id = connect_params.count("sn") ? connect_params["sn"].get<std::string>() : ip;
if (wxGetApp().app_config->get_device_info(dev_id, query_info)) {
query_info.connected = true;
wxGetApp().app_config->save_device_info(query_info);
} else {
auto machine_ip_type = MachineIPType::getInstance();
if (machine_ip_type) {
std::string machine_type = "";
if (machine_ip_type->get_machine_type(ip, machine_type)) {
// 已经发现过的机型信息
// test
if (machine_type == "lava" || machine_type == "Snapmaker test") {
machine_type = "Snapmaker U1";
}
DeviceInfo info;
host->get_auth_info();
auto auth_info = host->get_auth_info();
try {
info.ca = auth_info["ca"];
info.cert = auth_info["cert"];
info.key = auth_info["key"];
info.user = auth_info["user"];
info.password = auth_info["password"];
info.port = auth_info["port"];
info.clientId = auth_info["clientId"];
} catch (std::exception& e) {}
info.ip = ip;
info.dev_id = dev_id;
info.dev_name = ip;
info.connected = true;
info.model_name = machine_type;
info.protocol = int(PrintHostType::htMoonRaker_mqtt);
info.link_mode = link_mode;
info.id = id;
info.userid = userid;
if (connect_params.count("sn") && connect_params["sn"].is_string()) {
info.sn = connect_params["sn"].get<std::string>();
info.dev_name = info.sn != "" ? info.sn : info.dev_name;
info.dev_id = info.sn != "" ? info.sn : info.dev_name;
}
size_t vendor_pos = machine_type.find_first_of(" ");
if (vendor_pos != std::string::npos) {
std::string vendor = machine_type.substr(0, vendor_pos);
std::string machine_cover = LOCALHOST_URL +
std::to_string(
wxGetApp().m_page_http_server.get_port()) +
"/profiles/" + vendor + "/" + machine_type +
"_cover.png";
info.img = machine_cover;
}
wxGetApp().app_config->save_device_info(info);
// todo 绑定喷嘴
MessageDialog msg_window(nullptr,
ip + " " + _L("The target machine model has been detected as") +
" " + machine_type + "\n" +
_L("Please bind the nozzle information") + "\n",
_L("Nozzle Bind"), wxICON_QUESTION | wxOK);
msg_window.ShowModal();
m_dialog->m_bind_nozzle = true;
m_dialog->m_device_id = ip;
m_dialog->run();
if (info.nozzle_sizes.empty())
info.nozzle_sizes.push_back("0.4");
info.preset_name = machine_type + " (" + info.nozzle_sizes[0] + " nozzle)";
wxGetApp().app_config->save_device_info(info);
} else {
DeviceInfo info;
auto auth_info = host->get_auth_info();
try {
info.ca = auth_info["ca"];
info.cert = auth_info["cert"];
info.key = auth_info["key"];
info.user = auth_info["user"];
info.password = auth_info["password"];
info.port = auth_info["port"];
info.clientId = auth_info["clientId"];
} catch (std::exception& e) {}
info.ip = ip;
info.dev_id = dev_id;
info.dev_name = ip;
info.connected = true;
info.link_mode = link_mode;
info.id = id;
info.userid = id;
info.protocol = int(PrintHostType::htMoonRaker_mqtt);
if (connect_params.count("sn") && connect_params["sn"].is_string()) {
info.sn = connect_params["sn"].get<std::string>();
info.dev_name = info.sn != "" ? info.sn : info.dev_name;
info.dev_id = info.sn != "" ? info.sn : info.dev_name;
}
wxGetApp().app_config->save_device_info(info);
MessageDialog msg_window(
nullptr,
ip + " " +
_L("The target machine model has not been detected. Please bind manually."),
_L("Machine Bind"), wxICON_QUESTION | wxOK);
msg_window.ShowModal();
m_dialog->m_device_id = info.dev_id;
m_dialog->run();
}
}
}
});
}
wxGetApp().CallAfter([weak_self, reload_device_view]() {
// 更新首页设备卡片
auto devices = wxGetApp().app_config->get_devices();
json param;
param["command"] = "local_devices_arrived";
param["sequece_id"] = "10001";
param["data"] = devices;
std::string logout_cmd = param.dump();
wxString strJS = wxString::Format("window.postMessage(%s)", logout_cmd);
GUI::wxGetApp().run_script(strJS);
// wcp订阅
json data = devices;
wxGetApp().device_card_notify(data);
/*MessageDialog msg_window(nullptr, ip + " " + _L("connected sucessfully !") + "\n", _L("Machine
Connected"), wxICON_QUESTION | wxOK); msg_window.ShowModal();*/
auto dialog = wxGetApp().get_web_device_dialog();
if (dialog) {
dialog->EndModal(1);
}
wxGetApp().app_config->set("use_new_connect", "true");
wxGetApp().mainframe->plater()->sidebar().update_all_preset_comboboxes(reload_device_view);
wxGetApp().mainframe->m_print_enable = true;
wxGetApp().mainframe->update_slice_print_status(MainFrame::eEventPlateUpdate);
// wxGetApp().mainframe->load_printer_url("http://" + ip); //到时全部加载本地交互页面
if (!wxGetApp().mainframe->m_printer_view->isSnapmakerPage()) {
wxString url = wxString::FromUTF8(LOCALHOST_URL + std::to_string(PAGE_HTTP_PORT) +
"/web/flutter_web/index.html?path=2");
auto real_url = wxGetApp().get_international_url(url);
wxGetApp().mainframe->load_printer_url(real_url); // 到时全部加载本地交互页面
} else {
if (reload_device_view) {
wxString url = wxString::FromUTF8(LOCALHOST_URL + std::to_string(PAGE_HTTP_PORT) +
"/web/flutter_web/index.html?path=2");
auto real_url = wxGetApp().get_international_url(url);
wxGetApp().mainframe->load_printer_url(real_url); // 到时全部加载本地交互页面
}
}
auto self = weak_self.lock();
if (!self) {
return;
}
// 清除耗材喷嘴映射信息
wxGetApp().app_config->clear_filament_extruder_map();
// 尝试获取新的耗材喷嘴映射信息
if (self->m_wcp_cache.count("deviceFilamentInfo")) {
std::string value_str = m_wcp_cache["deviceFilamentInfo"].get<std::string>();
json value = json::parse(value_str);
json value_item = value["value"];
auto machines = wxGetApp().app_config->get_devices();
bool find = false;
for (auto& [key, value] : value_item.items()) {
if (find) {
break;
}
for (const auto& machine : machines) {
if (machine.sn == key && machine.connected) {
find = true;
json target = json::array();
json object = json::object();
object["key"] = key;
object["value"] = value.dump();
target.push_back(object);
self->update_filament_info(target, false);
break;
}
}
}
}
// 整理订阅列表,取消权限,但是保留真正的底层订阅
// 维护订阅topic表和eventid实例表
auto mqtt_self = dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(self);
mqtt_self->clean_current_engine();
self->send_to_js();
self->finish_job();
});
}
});
}
} else {
handle_general_fail(-1, "param [ip] required");
}
} else {
handle_general_fail();
}
} else {
handle_general_fail();
}
}
catch (std::exception& e) {
handle_general_fail();
}
}
void SSWCP_MqttAgent_Instance::sw_mqtt_publish()
{
try {
if (!m_param_data.count("id") || !m_param_data["id"].is_string()) {
handle_general_fail(-1, "param [id] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_publish host created failed"), DEVICE_PBLISH_ERR);
return;
}
std::string id = m_param_data["id"].get<std::string>();
if (!validate_id(id)) {
handle_general_fail(-1, "id is illegal");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_publish id is illegal"), DEVICE_PBLISH_ERR);
return;
}
if (!m_param_data.count("topic") || !m_param_data["topic"].is_string()) {
handle_general_fail(-1, "param [topic] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_publish param [topic] is required or wrong type"), DEVICE_PBLISH_ERR);
return;
}
std::string topic = m_param_data["topic"].get<std::string>();
if (!m_param_data.count("qos") || !m_param_data["qos"].is_number()) {
handle_general_fail(-1, "param [qos] is required or wrong type");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_publish param [qos] is required or wrong type"), DEVICE_PBLISH_ERR);
return;
}
int qos = m_param_data["qos"].get<int>();
if (!m_param_data.count("payload") || !m_param_data["payload"].is_string()) {
handle_general_fail(-1, "param [payload] required");
Slic3r::sentryReportLog(Slic3r::SENTRY_LOG_ERROR, std::string("device_publish param [payload] required"), DEVICE_PBLISH_ERR);
return;
}
std::string payload = m_param_data["payload"].get<std::string>();
std::weak_ptr<SSWCP_Instance> weak_ptr = shared_from_this();
auto engine = get_current_engine();
if (m_work_thread.joinable())
m_work_thread.join();
m_work_thread = std::thread([weak_ptr, engine, topic, payload, qos]() {
if (!weak_ptr.lock()) {
return;
}
auto self = std::dynamic_pointer_cast<SSWCP_MqttAgent_Instance>(weak_ptr.lock());
std::string msg = "success";
bool flag = engine->Publish(topic, payload, qos, msg);
wxGetApp().CallAfter([weak_ptr, msg, flag]() {
auto self = weak_ptr.lock();
if (self) {
if (flag) {
self->m_msg = msg;
self->send_to_js();
self->finish_job();
} else {
self->handle_general_fail(-1, msg);
}
}
});
});
} catch (std::exception& e) {
handle_general_fail();
}
}
// SSWCP
TimeoutMap<SSWCP_Instance*, std::shared_ptr<SSWCP_Instance>> SSWCP::m_instance_list;
constexpr std::chrono::milliseconds SSWCP::DEFAULT_INSTANCE_TIMEOUT;
std::string SSWCP::m_active_gcode_filename = "";
std::string SSWCP::m_display_gcode_filename = "";
long long SSWCP::m_active_file_size = 0;
std::mutex SSWCP::m_file_size_mutex;
std::unordered_map<std::string, int> SSWCP::m_tab_map = {
{"Home", MainFrame::TabPosition::tpHome},
{"3DEditor", MainFrame::TabPosition::tp3DEditor},
{"Preview", MainFrame::TabPosition::tpPreview},
{"Monitor", MainFrame::TabPosition::tpMonitor},
{"MultiDevice", MainFrame::TabPosition::tpMultiDevice},
{"Project", MainFrame::TabPosition::tpProject},
{"Calibration", MainFrame::TabPosition::tpCalibration},
{"Auxiliary", MainFrame::TabPosition::tpAuxiliary},
{"DebugTool", MainFrame::TabPosition::toDebugTool}
};
std::unordered_set<std::string> SSWCP::m_machine_find_cmd_list = {
"sw_GetMachineFindSupportInfo",
"sw_StartMachineFind",
"sw_StopMachineFind",
"sw_WakeupFind",
};
std::unordered_set<std::string> SSWCP::m_machine_option_cmd_list = {
"system.get_device_info",
"sw_SendGCodes",
"sw_FileGetStatus",
"sw_SystemGetDeviceInfo",
"sw_GetMachineState",
"sw_SubscribeMachineState",
"sw_GetMachineObjects",
"sw_SetSubscribeFilter",
"sw_StopMachineStateSubscription",
"sw_GetPrinterInfo",
"sw_MachinePrintStart",
"sw_MachinePrintPause",
"sw_MachinePrintResume",
"sw_MachinePrintCancel",
"sw_GetMachineSystemInfo",
"sw_MachineFilesRoots",
"sw_MachineFilesMetadata",
"sw_MachineFilesThumbnails",
"sw_MachineFilesGetDirectory",
"sw_CameraStartMonitor",
"sw_CameraStopMonitor",
"sw_DeleteMachineFile",
"sw_GetFileFilamentMapping",
"sw_SetFilamentMappingComplete",
"sw_FinishFilamentMapping",
"sw_DownloadMachineFile",
"sw_UploadFiletoMachine",
"sw_GetPrintLegal",
"sw_GetPrintZip",
"sw_FinishPreprint",
"sw_PullCloudFile",
"sw_CancelPullCloudFile",
"sw_StartCloudPrint",
"sw_SetDeviceName",
"sw_ControlLed",
"sw_ControlPrintSpeed",
"sw_BedMesh_AbortProbeMesh",
"sw_ControlPurifier",
"sw_ControlMainFan",
"sw_ControlGenericFan",
"sw_ControlBedTemp",
"sw_ControlExtruderTemp",
"sw_FilesThumbnailsBase64",
"sw_exception_query",
"sw_GetFileListPage",
"sw_UpdateMachineFilamentInfo",
"sw_UploadCameraTimelapse",
"sw_DeleteCameraTimelapse",
"sw_GetCameraTimelapseInstance",
"sw_ServerClientManagerSetUserinfo",
"sw_DefectDetactionConfig",
GET_DEVICEDATA_STORAGESPACE
};
std::unordered_set<std::string> SSWCP::m_machine_connect_cmd_list = {
"sw_Test_connect",
"sw_Connect",
"sw_Disconnect",
"sw_GetConnectedMachine",
"sw_ConnectOtherMachine",
"sw_GetPincode"
};
std::unordered_set<std::string> SSWCP::m_project_cmd_list = {
"sw_NewProject", "sw_OpenProject", "sw_GetRecentProjects", "sw_OpenRecentFile", "sw_DeleteRecentFiles", "sw_SubscribeRecentFiles",
};
std::unordered_set<std::string> SSWCP::m_login_cmd_list = {"sw_UserLogin", "sw_UserLogout", "sw_GetUserLoginState", "sw_SubscribeUserLoginState",
UPDATE_PRIVACY_STATUS, GET_PRIVACY_STATUS};
std::unordered_set<std::string> SSWCP::m_machine_manage_cmd_list = {
"sw_GetLocalDevices", "sw_AddDevice", "sw_SubscribeLocalDevices", "sw_RenameDevice", "sw_SwitchModel", "sw_DeleteDevices"
};
std::unordered_set<std::string> SSWCP::m_page_state_cmd_list = {
"sw_SubscribePageStateChange", "sw_UnsubscribePageStateChange"
};
std::unordered_set<std::string> SSWCP::m_mqtt_agent_cmd_list = {
"sw_create_mqtt_client", "sw_mqtt_connect", "sw_mqtt_disconnect", "sw_mqtt_subscribe", "sw_mqtt_unpublish", "sw_mqtt_publish", "sw_mqtt_set_engine"
};
std::shared_ptr<SSWCP_Instance> SSWCP::create_sswcp_instance(std::string cmd, const json& header, const json& data, std::string event_id, wxWebView* webview)
{
std::shared_ptr<SSWCP_Instance> instance;
if (m_machine_find_cmd_list.find(cmd) != m_machine_find_cmd_list.end()) {
instance = std::make_shared<SSWCP_MachineFind_Instance>(cmd, header, data, event_id, webview);
} else if (m_machine_connect_cmd_list.find(cmd) != m_machine_connect_cmd_list.end()) {
instance = std::make_shared<SSWCP_MachineConnect_Instance>(cmd, header, data, event_id, webview);
} else if (m_machine_option_cmd_list.find(cmd) != m_machine_option_cmd_list.end()) {
instance = std::make_shared<SSWCP_MachineOption_Instance>(cmd, header, data, event_id, webview);
} else if (m_project_cmd_list.find(cmd) != m_project_cmd_list.end()) {
instance = std::make_shared<SSWCP_SliceProject_Instance>(cmd, header, data, event_id, webview);
} else if (m_login_cmd_list.find(cmd) != m_login_cmd_list.end()) {
instance = std::make_shared<SSWCP_UserLogin_Instance>(cmd, header, data, event_id, webview);
} else if (m_machine_manage_cmd_list.find(cmd) != m_machine_manage_cmd_list.end()) {
instance = std::make_shared<SSWCP_MachineManage_Instance>(cmd, header, data, event_id, webview);
} else if (m_page_state_cmd_list.find(cmd) != m_page_state_cmd_list.end()) {
instance = std::make_shared<SSWCP_PageStateChange_Instance>(cmd, header, data, event_id, webview);
} else if(m_mqtt_agent_cmd_list.find(cmd) != m_mqtt_agent_cmd_list.end()) {
instance = std::make_shared<SSWCP_MqttAgent_Instance>(cmd, header, data, event_id, webview);
}
else {
instance = std::make_shared<SSWCP_Instance>(cmd, header, data, event_id, webview);
}
return instance;
}
// Handle incoming web messages
void SSWCP::handle_web_message(std::string message, wxWebView* webview) {
try {
if (!webview) {
return;
}
WCP_Logger::getInstance().add_log(message, false, "", "WCP", "info");
json j_message = json::parse(message);
if (j_message.empty() || !j_message.count("header") || !j_message.count("payload") || !j_message["payload"].count("cmd")) {
return;
}
json header = j_message["header"];
json payload = j_message["payload"];
std::string cmd = "";
std::string event_id = "";
json params;
if (payload.count("cmd")) {
cmd = payload["cmd"].get<std::string>();
}
if (payload.count("params")) {
params = payload["params"];
}
if (payload.count("event_id") && !payload["event_id"].is_null()) {
event_id = payload["event_id"].get<std::string>();
}
std::shared_ptr<SSWCP_Instance> instance = create_sswcp_instance(cmd, header, params, event_id, webview);
if (instance) {
if (event_id != "") {
m_instance_list.add_infinite(instance.get(), instance);
} else {
m_instance_list.add(instance.get(), instance, DEFAULT_INSTANCE_TIMEOUT);
}
instance->process();
}
//if (!m_func_map.count(cmd)) {
// // todo:返回不支持处理
//}
//m_func_map[cmd](sequenceId, data, callback_name, webview);
}
catch (std::exception& e) {
}
}
// Delete instance from list
void SSWCP::delete_target(SSWCP_Instance* target) {
wxGetApp().CallAfter([target]() {
m_instance_list.remove(target);
});
}
// Stop all machine subscriptions
void SSWCP::stop_subscribe_machine()
{
wxGetApp().CallAfter([]() {
std::vector<SSWCP_Instance*> instances_to_stop;
auto snapshot = m_instance_list.get_snapshot();
// Get all subscription instances to stop
for (const auto& instance : snapshot) {
if (instance.second->getType() == SSWCP_MachineFind_Instance::MACHINE_OPTION && instance.second->m_cmd == "sw_SubscribeMachineState") {
instances_to_stop.push_back(instance.first);
}
}
// Stop each instance
for (auto* instance : instances_to_stop) {
auto instance_ptr = m_instance_list.get(instance);
if (instance_ptr) {
(*instance_ptr)->finish_job();
}
}
});
}
// Stop all machine discovery instances
void SSWCP::stop_machine_find() {
wxGetApp().CallAfter([]() {
std::vector<SSWCP_Instance*> instances_to_stop;
auto snapshot = m_instance_list.get_snapshot();
// Get all discovery instances to stop
for (const auto& instance : snapshot) {
if (instance.second->getType() == SSWCP_MachineFind_Instance::MACHINE_FIND) {
instances_to_stop.push_back(instance.first);
}
}
// Set stop flag for each instance
for (auto* instance : instances_to_stop) {
auto instance_ptr = m_instance_list.get(instance);
if (instance_ptr) {
(*instance_ptr)->set_stop(true);
}
}
});
}
// Handle webview deletion
void SSWCP::on_webview_delete(wxWebView* view)
{
// Mark all instances associated with this webview as invalid
std::vector<SSWCP_Instance*> instances_to_invalidate;
// Get all instances using this webview
for (const auto& instance : m_instance_list) {
if (instance.second->value->get_web_view() == view) {
instances_to_invalidate.push_back(instance.first);
instance.second->value->set_web_view(nullptr);
}
}
// Mark each instance as invalid
for (auto* instance : instances_to_invalidate) {
auto instance_ptr = m_instance_list.get(instance);
if (instance_ptr) {
(*instance_ptr)->set_Instance_illegal();
}
}
auto& device_map = wxGetApp().m_device_card_subscribers;
for (auto iter = device_map.begin(); iter != device_map.end();) {
if (iter->first == view) {
iter = device_map.erase(iter);
} else {
iter++;
}
}
auto& login_map = wxGetApp().m_user_login_subscribers;
for (auto iter = login_map.begin(); iter != login_map.end();) {
if (iter->first == view) {
iter = login_map.erase(iter);
} else {
iter++;
}
}
auto& privacy_map = wxGetApp().m_user_update_privacy_subscribers;
for (auto iter = privacy_map.begin(); iter != privacy_map.end();) {
if (iter->first == view) {
iter = privacy_map.erase(iter);
} else {
iter++;
}
}
auto& recent_file_map = wxGetApp().m_recent_file_subscribers;
for (auto iter = recent_file_map.begin(); iter != recent_file_map.end();) {
if (iter->first == view) {
iter = recent_file_map.erase(iter);
} else {
iter++;
}
}
auto& cache_map = wxGetApp().m_cache_subscribers;
for (auto iter = cache_map.begin(); iter != cache_map.end();) {
if (iter->first.first == view) {
iter = cache_map.erase(iter);
} else {
iter++;
}
}
auto& page_state_map = wxGetApp().m_page_state_subscribers;
for (auto iter = page_state_map.begin(); iter != page_state_map.end();) {
if (iter->first == view) {
iter = page_state_map.erase(iter);
} else {
iter++;
}
}
}
std::string SSWCP::get_display_filename()
{
return m_display_gcode_filename;
}
// get the active filename
std::string SSWCP::get_active_filename()
{
return m_active_gcode_filename;
}
// set the display name
void SSWCP::update_display_filename(const std::string& filename)
{ m_display_gcode_filename = filename; }
// set the active filename
void SSWCP::update_active_filename(const std::string& filename)
{
m_active_gcode_filename = filename;
}
// query the info of the machine
bool SSWCP::query_machine_info(std::shared_ptr<PrintHost>& host, std::string& out_model, std::vector<std::string>& out_nozzle_diameters, std::string& device_name, int timeout_second)
{
if (!host) return false;
// 创建同步等待的条件变量和互斥锁
std::condition_variable cv;
std::shared_ptr<std::mutex> mutex(new std::mutex);
std::weak_ptr<std::mutex> cb_mutex = mutex;
bool received = false;
bool timeout = false;
json system_info;
// 发送查询请求
host->async_get_system_info(
[&, cb_mutex](const json& response) {
if (cb_mutex.expired()) {
return;
}
std::lock_guard<std::mutex> lock(*mutex);
if (!response.is_null() && !response.count("error")) {
system_info = response;
}
received = true;
cv.notify_one();
}
);
// 等待响应
{
std::unique_lock<std::mutex> lock(*mutex);
auto predicate = [&received]() { return received; };
timeout = !cv.wait_for(lock, std::chrono::seconds(timeout_second), predicate);
}
if (!timeout && !system_info.is_null()) {
// 成功获取到信息
if (system_info.count("data")) {
system_info = system_info["data"];
}
if (system_info.contains("system_info")) {
auto& system_data = system_info["system_info"];
if(system_data.contains("product_info")){
auto& product_info = system_data["product_info"];
// 获取机型
if(product_info.contains("machine_type")){
out_model = product_info["machine_type"].get<std::string>();
}
// 获取喷嘴信息
if(product_info.contains("nozzle_diameter")){
try {
if (product_info["nozzle_diameter"].is_array()) {
for (const auto& nozzle : product_info["nozzle_diameter"]) {
// todo 不一定是string
if (nozzle.is_number()) {
double temp = nozzle.get<double>();
if (fabs(temp - 0.2) < 1e-6) {
out_nozzle_diameters.push_back("0.2");
} else if (fabs(temp - 0.4) < 1e-6) {
out_nozzle_diameters.push_back("0.4");
} else if (fabs(temp - 0.6) < 1e-6) {
out_nozzle_diameters.push_back("0.6");
} else if (fabs(temp - 0.8) < 1e-6) {
out_nozzle_diameters.push_back("0.8");
}
} else {
std::string temp = nozzle.get<std::string>();
if (temp == "0.2" || temp == "0.4" || temp == "0.6" || temp == "0.8") {
out_nozzle_diameters.push_back(temp);
}
}
}
} else {
// 如果是单个值
if (product_info["nozzle_diameter"].is_number()) {
double temp = product_info["nozzle_diameter"].get<double>();
if (fabs(temp - 0.2) < 1e-6) {
out_nozzle_diameters.push_back("0.2");
} else if (fabs(temp - 0.4) < 1e-6) {
out_nozzle_diameters.push_back("0.2");
} else if (fabs(temp - 0.6) < 1e-6) {
out_nozzle_diameters.push_back("0.2");
} else if (fabs(temp - 0.8) < 1e-6) {
out_nozzle_diameters.push_back("0.2");
}
} else {
std::string temp = product_info["nozzle_diameter"].get<std::string>();
if (temp == "0.2" || temp == "0.4" || temp == "0.6" || temp == "0.8") {
out_nozzle_diameters.push_back(temp);
}
}
}
}
catch (std::exception& e) {
return false;
}
}
if (product_info.contains("device_name")) {
device_name = product_info["device_name"].get<std::string>();
}
}
return true;
}
}
return false;
}
MachineIPType* MachineIPType::getInstance()
{
static MachineIPType mipt_instance;
return &mipt_instance;
}
}}; // namespace Slic3r::GUI