refactor: push bbl workflows to bbl printer agent

This commit is contained in:
Ian Chua
2026-08-12 13:50:47 +08:00
parent d5c528b7c7
commit 7cb1805272
23 changed files with 967 additions and 585 deletions
+2
View File
@@ -13,6 +13,8 @@
#include "libslic3r/Time.hpp" #include "libslic3r/Time.hpp"
#include "IPrinterAgent.hpp"
using namespace nlohmann; using namespace nlohmann;
namespace { namespace {
+73
View File
@@ -50,6 +50,7 @@
#include "DeviceCore/DevStatus.h" #include "DeviceCore/DevStatus.h"
#include "DeviceCore/DevUpgrade.h" #include "DeviceCore/DevUpgrade.h"
#include "IPrinterAgent.hpp"
#define CALI_DEBUG #define CALI_DEBUG
#define MINUTE_30 1800000 //ms #define MINUTE_30 1800000 //ms
@@ -2854,6 +2855,78 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
j = j_pre; j = j_pre;
} }
#pragma region CAP_SUBSCRIPTIONS
if (j_pre.contains("capabilities")) {
auto& caps = j_pre["capabilities"];
// if (caps.contains("extruder_count")) {
// GetExtderSystem()->GetTotalExtderCount();
// }
if (caps.contains("supports_extruder_control"))
is_enable_np = caps.value("supports_extruder_control", 0);
if (caps.contains("supports_part_skip"))
is_support_partskip = caps.value("supports_part_skip", 0);
if (caps.contains("has_door_sensor"))
is_support_door_open_check = caps.value("has_door_sensor", 0);
if (caps.contains("supports_auto_recovery"))
is_support_auto_recovery_step_loss = caps.value("supports_auto_recovery", 0);
if (caps.contains("supports_prompt_sound"))
is_support_prompt_sound = caps.value("supports_prompt_sound", 0);
if (caps.contains("supports_spaghetti_detection"))
is_support_spaghetti_detection = caps.value("supports_spaghetti_detection", 0);
if (caps.contains("supports_purge_chute_pileup_detection"))
is_support_purgechutepileup_detection = caps.value("supports_purge_chute_pileup_detection", 0);
if (caps.contains("supports_nozzle_clumping_detection"))
is_support_nozzleclumping_detection = caps.value("supports_nozzle_clumping_detection", 0);
if (caps.contains("supports_build_plate_marker_detection"))
is_support_build_plate_marker_detect = caps.value("supports_build_plate_marker_detection", 0);
if (caps.contains("supports_ams_humidity"))
is_support_ams_humidity = caps.value("supports_ams_humidity", 0);
if (caps.contains("supports_pa_calibration_manual"))
is_support_pa_calibration = caps.value("supports_pa_calibration_manual", 0);
if (caps.contains("supports_flow_rate_calibration_manual"))
is_support_flow_calibration = caps.value("supports_flow_rate_calibration_manual", 0);
if (caps.contains("supports_hotend_rack"))
m_nozzle_system->SetSupportNozzleRack(caps.value("supports_hotend_rack", 0));
if (caps.contains("has_camera"))
has_ipcam = caps.value("has_camera", 0);
// Printing with no filament loaded
if (caps.contains("is_support_ams_air_print_detection"))
is_support_air_print_detection = caps.value("is_support_ams_air_print_detection", 0);
if (caps.contains("is_support_airprinting_detection"))
is_support_airprinting_detection = caps.value("is_support_airprinting_detection", 0);
if (caps.contains("camera_resolutions"))
camera_resolution_supported = caps.value("camera_resolutions", std::vector<std::string>{});
// if (caps.contains("ams_unit_count"))
// DevFilaSystemParser::ParseV1_0(caps["ams_unit_count"], this, m_fila_system.get(), true);
// Remaining documented "capabilities" keys are intentionally not wired here yet.
//
// Already cached elsewhere, but not as a single direct is_support_* bool member
// (a differently-named member, a count, a method on another class, or two competing
// members), so leave these to their existing plumbing:
// extruder_count -> DevExtderSystem::m_total_extder_count
// ams_unit_count -> DevFilaSystem::GetAmsCount()
//
// No existing member at all -- would need a new is_support_* field and a design
// decision on naming/semantics before adding:
// has_lidar
// supports_plate_align_detection
// supports_fod_detection
// supports_displacement_detection
// supports_ai_monitoring -> only an enabled-state member exists (xcam_ai_monitoring)
// supports_first_layer_inspection -> only an enabled-state member exists (xcam_first_layer_inspector)
//
// Genuinely complex (array/object values, or no authoritative single source to derive from):
// supported_nozzle_types, supports_nozzle_blob_detection, has_ams, ams_slot_count,
// supports_ams_rfid, supports_multiple_bed_types, supports_filament_mapping,
// supports_pa_calibration_auto, supports_flow_rate_calibration_auto,
// supports_max_volumetric_speed_calibration, supports_ota_update
}
#pragma endregion
uint64_t t_utc = j.value("t_utc", 0ULL); uint64_t t_utc = j.value("t_utc", 0ULL);
if (t_utc > 0) { if (t_utc > 0) {
last_utc_time = std::chrono::system_clock::time_point(t_utc * 1ms); last_utc_time = std::chrono::system_clock::time_point(t_utc * 1ms);
+30 -23
View File
@@ -100,6 +100,32 @@ struct DevPrintTaskRatingInfo;
// given nozzle diameter (mm), bucketed per nozzle size to mirror the printer firmware. // given nozzle diameter (mm), bucketed per nozzle size to mirror the printer firmware.
bool is_stringing_prone_filament(const std::string& filament_id, float nozzle_diameter); bool is_stringing_prone_filament(const std::string& filament_id, float nozzle_diameter);
enum LiveviewLocal {
LVL_None,
LVL_Disable,
LVL_Local,
LVL_Rtsps,
LVL_Rtsp
};
enum LiveviewRemote {
LVR_None,
LVR_Tutk,
LVR_Agora,
LVR_TutkAgora
};
enum FileLocal {
FL_None,
FL_Local
};
enum FileRemote {
FR_None,
FR_Tutk,
FR_Agora,
FR_TutkAgora
};
class MachineObject class MachineObject
{ {
@@ -538,29 +564,10 @@ public:
time_t xcam_first_layer_hold_start = 0; time_t xcam_first_layer_hold_start = 0;
std::string local_rtsp_url; std::string local_rtsp_url;
std::string tutk_state; std::string tutk_state;
enum LiveviewLocal { LiveviewLocal liveview_local{ LiveviewLocal::LVL_None };
LVL_None, LiveviewRemote liveview_remote{ LiveviewRemote::LVR_None};
LVL_Disable, FileLocal file_local{ FileLocal::FL_None };
LVL_Local, FileRemote file_remote{ FileRemote::FR_None };
LVL_Rtsps,
LVL_Rtsp
} liveview_local{ LVL_None };
enum LiveviewRemote {
LVR_None,
LVR_Tutk,
LVR_Agora,
LVR_TutkAgora
} liveview_remote{ LVR_None };
enum FileLocal {
FL_None,
FL_Local
} file_local{ FL_None };
enum FileRemote {
FR_None,
FR_Tutk,
FR_Agora,
FR_TutkAgora
} file_remote{ FR_None };
enum PlateMakerDectect : int enum PlateMakerDectect : int
{ {
+20 -35
View File
@@ -12,6 +12,8 @@
#include "slic3r/GUI/DeviceCore/DevManager.h" #include "slic3r/GUI/DeviceCore/DevManager.h"
#include "slic3r/GUI/DeviceCore/DevUtil.h" #include "slic3r/GUI/DeviceCore/DevUtil.h"
#include "IPrinterAgent.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@@ -203,41 +205,6 @@ void PrintJob::process(Ctl &ctl)
params.use_ssl_for_mqtt = m_local_use_ssl; params.use_ssl_for_mqtt = m_local_use_ssl;
params.username = m_agent->default_lan_username(); params.username = m_agent->default_lan_username();
params.password = m_access_code; params.password = m_access_code;
// Allow disabling the eMMC print path via AppConfig. Plugin 02.03.00.62's
// eMMC tunnel code hangs indefinitely at the upload phase with some
// printers (e.g., Bambu H2D), so we default to disabled. Users with
// working eMMC support can opt-in by setting disable_emmc_print = 0.
bool disable_emmc = true;
if (wxGetApp().app_config) {
auto v = wxGetApp().app_config->get("disable_emmc_print");
if (v == "0" || v == "false")
disable_emmc = false;
}
params.try_emmc_print = this->could_emmc_print && !disable_emmc;
// check access code and ip address
if (this->connection_type == "lan" && m_print_type == "from_normal") {
params.dev_id = m_dev_id;
params.project_name = "verify_job";
params.filename = job_data._temp_path.string();
params.connection_type = this->connection_type;
result = m_agent->start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr);
if (result != 0) {
BOOST_LOG_TRIVIAL(error) << "LAN connection verification failed:"
<< " result=" << result
<< ", dev_ip=" << m_dev_ip
<< ", dev_id=" << m_dev_id
<< ", password_length=" << m_access_code.size();
m_enter_ip_address_fun_fail();
m_job_finished = true;
return;
}
params.project_name = "";
params.filename = "";
}
params.dev_id = m_dev_id; params.dev_id = m_dev_id;
params.ftp_folder = m_ftp_folder; params.ftp_folder = m_ftp_folder;
@@ -264,6 +231,17 @@ void PrintJob::process(Ctl &ctl)
params.auto_offset_cali = this->auto_offset_cali; params.auto_offset_cali = this->auto_offset_cali;
params.extruder_cali_manual_mode = this->extruder_cali_manual_mode; params.extruder_cali_manual_mode = this->extruder_cali_manual_mode;
params.task_ext_change_assist = this->task_ext_change_assist; params.task_ext_change_assist = this->task_ext_change_assist;
// Allow disabling the eMMC print path via AppConfig. Plugin 02.03.00.62's
// eMMC tunnel code hangs indefinitely at the upload phase with some
// printers (e.g., Bambu H2D), so we default to disabled. Users with
// working eMMC support can opt-in by setting disable_emmc_print = 0.
bool disable_emmc = true;
if (wxGetApp().app_config) {
auto v = wxGetApp().app_config->get("disable_emmc_print");
if (v == "0" || v == "false")
disable_emmc = false;
}
params.try_emmc_print = this->could_emmc_print && !disable_emmc;
if (m_print_type == "from_sdcard_view") { if (m_print_type == "from_sdcard_view") {
params.dst_file = m_dst_path; params.dst_file = m_dst_path;
@@ -618,6 +596,13 @@ void PrintJob::process(Ctl &ctl)
} }
if (result < 0) { if (result < 0) {
if (result == ORCA_NETWORK_ERR_ACCESS_VERIFICATION_FAILED) {
if (m_enter_ip_address_fun_fail)
m_enter_ip_address_fun_fail();
m_job_finished = true;
return;
}
curr_percent = -1; curr_percent = -1;
// The printer is still fetching its encryption flag (a transient state), so ask the // The printer is still fetching its encryption flag (a transient state), so ask the
+10 -25
View File
@@ -11,6 +11,7 @@
#include "Widgets/ProgressDialog.hpp" #include "Widgets/ProgressDialog.hpp"
#include <libslic3r/Model.hpp> #include <libslic3r/Model.hpp>
#include <libslic3r/Format/bbs_3mf.hpp> #include <libslic3r/Format/bbs_3mf.hpp>
#include <slic3r/GUI/DeviceManager.hpp>
#include "DeviceCore/DevStorage.h" #include "DeviceCore/DevStorage.h"
#ifdef __WXMSW__ #ifdef __WXMSW__
@@ -206,7 +207,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
Bind(wxEVT_SHOW, onShowHide); Bind(wxEVT_SHOW, onShowHide);
parent->GetParent()->Bind(wxEVT_SHOW, onShowHide); parent->GetParent()->Bind(wxEVT_SHOW, onShowHide);
m_lan_user = "bblp"; m_lan_user = wxGetApp().getAgent()->default_lan_username();
} }
MediaFilePanel::~MediaFilePanel() MediaFilePanel::~MediaFilePanel()
@@ -465,14 +466,9 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: " << m_local_proto << m_remote_proto; BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: " << m_local_proto << m_remote_proto;
m_waiting_support = false; m_waiting_support = false;
NetworkAgent *agent = wxGetApp().getAgent(); NetworkAgent *agent = wxGetApp().getAgent();
std::string agent_version = agent ? agent->get_version() : "";
if (agent && (m_lan_mode || !m_remote_proto) && m_local_proto && !m_lan_ip.empty()) { if (agent && (m_lan_mode || !m_remote_proto) && m_local_proto && !m_lan_ip.empty()) {
std::string url = agent->get_local_camera_url(m_lan_ip, m_lan_user, m_lan_passwd); std::string url = agent->get_local_camera_url({m_lan_ip, m_lan_user, m_lan_passwd, LVL_None,
url += "&device=" + m_machine; m_machine, agent->get_version(), m_dev_ver, "", wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION});
url += "&net_ver=" + agent_version;
url += "&dev_ver=" + m_dev_ver;
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
fs->SetUrl(url); fs->SetUrl(url);
return; return;
} }
@@ -494,33 +490,22 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
if (agent) { if (agent) {
std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto], agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto],
[this, wfs, m = m_machine, v = agent->get_version(), dv = m_dev_ver](std::string url) { [this, wfs, m = m_machine](CameraURLResult result) {
if (boost::algorithm::starts_with(url, "bambu:///")) { std::string url = std::move(result.url);
url += "&device=" + m;
url += "&net_ver=" + v;
url += "&dev_ver=" + dv;
url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url);
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
CallAfter([=] { CallAfter([=] {
boost::shared_ptr fs(wfs.lock()); boost::shared_ptr fs(wfs.lock());
if (!fs || fs != m_image_grid->GetFileSystem()) return; if (!fs || fs != m_image_grid->GetFileSystem()) return;
if (boost::algorithm::starts_with(url, "bambu:///")) { if (result.is_success) {
fs->SetUrl(url); fs->SetUrl(url);
} else { } else {
m_image_grid->SetStatus(m_bmp_failed, _L("Connection Failed. Please check the network and try again")); m_image_grid->SetStatus(m_bmp_failed, _L("Connection Failed. Please check the network and try again"));
std::string res = "3"; std::string res = result.error_code >= 0 ? std::to_string(result.error_code) : "3";
if (boost::ends_with(url, "]")) {
size_t n = url.find_last_of('[');
if (n != std::string::npos)
res = url.substr(n + 1, url.length() - n - 2);
}
fs->SetUrl(res); fs->SetUrl(res);
} }
}); });
}, wxGetApp().get_printer_cloud_provider()); }, wxGetApp().get_printer_cloud_provider(), CameraURLParams{"", "", "", LVL_None, m_machine, agent->get_version(), m_dev_ver,
boost::lexical_cast<std::string>(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true});
} }
} }
+62 -78
View File
@@ -14,6 +14,7 @@
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#include <boost/nowide/utf8_codecvt.hpp> #include <boost/nowide/utf8_codecvt.hpp>
#include <slic3r/GUI/DeviceManager.hpp>
#undef pid_t #undef pid_t
#include <boost/process.hpp> #include <boost/process.hpp>
#ifdef __WIN32__ #ifdef __WIN32__
@@ -160,12 +161,12 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj)
if (DevPrinterConfigUtil::get_printer_series_str(obj->printer_type) == "series_o" && BBLNetworkPlugin::instance().use_legacy_network()) { if (DevPrinterConfigUtil::get_printer_series_str(obj->printer_type) == "series_o" && BBLNetworkPlugin::instance().use_legacy_network()) {
// Legacy plugin cannot support remote play for H2D, force using local mode // Legacy plugin cannot support remote play for H2D, force using local mode
m_remote_proto = MachineObject::LVR_None; m_remote_proto = LiveviewRemote::LVR_None;
} }
} else { } else {
m_camera_exists = false; m_camera_exists = false;
m_lan_mode = false; m_lan_mode = false;
m_lan_proto = MachineObject::LVL_None; m_lan_proto = LiveviewLocal::LVL_None;
m_lan_ip.clear(); m_lan_ip.clear();
m_lan_passwd.clear(); m_lan_passwd.clear();
m_dev_ver.clear(); m_dev_ver.clear();
@@ -247,8 +248,8 @@ void refresh_agora_url(char const* device, char const* dev_ver, char const* chan
device2 += dev_ver; device2 += dev_ver;
device2 += "|\"agora\"|"; device2 += "|\"agora\"|";
device2 += channel; device2 += channel;
wxGetApp().getAgent()->get_camera_url(device2, [context, callback](std::string url) { wxGetApp().getAgent()->get_camera_url(device2, [context, callback](CameraURLResult result) {
callback(context, url.c_str()); callback(context, result.url.c_str());
}, wxGetApp().get_printer_cloud_provider()); }, wxGetApp().get_printer_cloud_provider());
} }
@@ -283,20 +284,20 @@ void MediaPlayCtrl::Play()
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play: " << m_lan_proto << m_remote_proto << m_disable_lan; BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play: " << m_lan_proto << m_remote_proto << m_disable_lan;
NetworkAgent *agent = wxGetApp().getAgent(); NetworkAgent *agent = wxGetApp().getAgent();
std::string agent_version = agent ? agent->get_version() : ""; std::string agent_version = agent ? agent->get_version() : "";
if (m_lan_proto > MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { if (m_lan_proto > LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) {
m_disable_lan = m_remote_proto && !m_lan_mode; // try remote next time m_disable_lan = m_remote_proto && !m_lan_mode; // try remote next time
std::string url; std::string url = agent->get_local_camera_url({
if (m_lan_proto == MachineObject::LVL_Local) m_lan_ip,
url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; m_lan_user,
else if (m_lan_proto == MachineObject::LVL_Rtsps) m_lan_passwd,
url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps"; LiveviewLocal(m_lan_proto),
else if (m_lan_proto == MachineObject::LVL_Rtsp) into_u8(m_machine),
url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp"; agent_version,
url += "&device=" + m_machine; m_dev_ver,
url += "&net_ver=" + agent_version; "",
url += "&dev_ver=" + m_dev_ver; wxGetApp().app_config->get("slicer_uuid"),
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid"); SLIC3R_VERSION
url += "&cli_ver=" + std::string(SLIC3R_VERSION); });
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(hide_id_middle_string(url, url.find(m_lan_ip), m_lan_ip.length()), {m_lan_passwd}); BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(hide_id_middle_string(url, url.find(m_lan_ip), m_lan_ip.length()), {m_lan_passwd});
m_url = url; m_url = url;
load(); load();
@@ -312,8 +313,8 @@ void MediaPlayCtrl::Play()
// !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_Disable (*) // !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_Disable (*)
// !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_None (x) // !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_None (x)
if (m_lan_proto <= MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto)) { if (m_lan_proto <= LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto)) {
Stop(m_lan_proto == MachineObject::LVL_None Stop(m_lan_proto == LiveviewLocal::LVL_None
? _L("A problem occurred. Please update the printer firmware and try again.") ? _L("A problem occurred. Please update the printer firmware and try again.")
: _L("LAN Only Liveview is off. Please turn on the liveview on printer screen.")); : _L("LAN Only Liveview is off. Please turn on the liveview on printer screen."));
return; return;
@@ -336,46 +337,39 @@ void MediaPlayCtrl::Play()
if (agent) { if (agent) {
std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto], agent->get_camera_url(
[this, m = m_machine, v = agent_version, dv = m_dev_ver, token = std::weak_ptr(m_token)](std::string url) { m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto],
if (token.expired()) { [this, m = m_machine, token = std::weak_ptr(m_token)](CameraURLResult result) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": token has been expired"; std::string url = std::move(result.url);
return; const bool success = result.is_success;
} const int error_code = result.error_code;
if (token.expired()) {
if (boost::algorithm::starts_with(url, "bambu:///")) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": token has been expired";
url += "&device=" + into_u8(m);
url += "&net_ver=" + v;
url += "&dev_ver=" + dv;
url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url);
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url,
{"?uid=", "authkey=", "passwd=", "license=", "token="});
CallAfter([this, m, url] {
if (m != m_machine) {
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for machine: " << m;
return; return;
} }
if (m_last_state == MEDIASTATE_INITIALIZING) {
if (url.empty() || !boost::algorithm::starts_with(url, "bambu:///")) { BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url, {"?uid=", "authkey=", "passwd=", "license=", "token="});
m_failed_code = 3; CallAfter([this, m, url, success, error_code] {
if (boost::ends_with(url, "]")) { if (m != m_machine) {
size_t n = url.find_last_of('['); BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for machine: " << m;
if (n != std::string::npos) return;
m_failed_code = std::atoi(url.substr(n + 1, url.length() - n - 2).c_str());
}
Stop(_L("Connection Failed. Please check the network and try again"), from_u8(url));
} else {
m_url = url;
load();
} }
} else { if (m_last_state == MEDIASTATE_INITIALIZING) {
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state; if (!success) {
} m_failed_code = error_code >= 0 ? error_code : 3;
}); Stop(_L("Connection Failed. Please check the network and try again"), from_u8(url));
}, wxGetApp().get_printer_cloud_provider()); } else {
m_url = url;
load();
}
} else {
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state;
}
});
},
wxGetApp().get_printer_cloud_provider(),
CameraURLParams{"", "", "", LVL_None, into_u8(m_machine), agent_version, m_dev_ver,
boost::lexical_cast<std::string>(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true});
} }
} }
@@ -528,16 +522,11 @@ void MediaPlayCtrl::ToggleStream()
wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1"); wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1");
if (res == wxID_CANCEL) return; if (res == wxID_CANCEL) return;
} }
if (m_lan_proto > MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { if (m_lan_proto > LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) {
std::string url; NetworkAgent *agent = wxGetApp().getAgent();
if (m_lan_proto == MachineObject::LVL_Local) if (!agent) return;
url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; std::string url = agent->get_local_camera_url({m_lan_ip, m_lan_user, m_lan_passwd, LiveviewLocal(m_lan_proto),
else if (m_lan_proto == MachineObject::LVL_Rtsps) into_u8(m_machine), agent->get_version(), m_dev_ver, "", wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION});
url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps";
else if (m_lan_proto == MachineObject::LVL_Rtsp)
url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp";
url += "&device=" + into_u8(m_machine);
url += "&dev_ver=" + m_dev_ver;
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(hide_id_middle_string(url, url.find(m_lan_ip), m_lan_ip.length()), {m_lan_passwd}); BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(hide_id_middle_string(url, url.find(m_lan_ip), m_lan_ip.length()), {m_lan_passwd});
std::string file_url = data_dir() + "/cameratools/url.txt"; std::string file_url = data_dir() + "/cameratools/url.txt";
boost::nowide::ofstream file(file_url); boost::nowide::ofstream file(file_url);
@@ -551,20 +540,14 @@ void MediaPlayCtrl::ToggleStream()
if (!agent) return; if (!agent) return;
std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto], agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto],
[this, m = m_machine, v = agent->get_version(), dv = m_dev_ver](std::string url) { [this, m = m_machine](CameraURLResult result) {
if (boost::algorithm::starts_with(url, "bambu:///")) { std::string url = std::move(result.url);
url += "&device=" + m; const bool success = result.is_success;
url += "&net_ver=" + v;
url += "&dev_ver=" + dv;
url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url);
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url, BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url,
{"?uid=", "authkey=", "passwd=", "license=", "token="}); {"?uid=", "authkey=", "passwd=", "license=", "token="});
CallAfter([this, m, url] { CallAfter([this, m, url, success] {
if (m != m_machine) return; if (m != m_machine) return;
if (url.empty() || !boost::algorithm::starts_with(url, "bambu:///")) { if (!success) {
MessageDialog(this->GetParent(), wxString::Format(_L("Virtual camera initialize failed (%s)!"), url.empty() ? _L("Network unreachable") : from_u8(url)), _L("Information"), MessageDialog(this->GetParent(), wxString::Format(_L("Virtual camera initialize failed (%s)!"), url.empty() ? _L("Network unreachable") : from_u8(url)), _L("Information"),
wxICON_INFORMATION) wxICON_INFORMATION)
.ShowModal(); .ShowModal();
@@ -577,7 +560,8 @@ void MediaPlayCtrl::ToggleStream()
file.close(); file.close();
m_streaming = true; m_streaming = true;
}); });
}, wxGetApp().get_printer_cloud_provider()); }, wxGetApp().get_printer_cloud_provider(), CameraURLParams{"", "", "", LVL_None, into_u8(m_machine), agent->get_version(), m_dev_ver,
boost::lexical_cast<std::string>(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true});
} }
void MediaPlayCtrl::msw_rescale() { void MediaPlayCtrl::msw_rescale() {
+24 -44
View File
@@ -433,58 +433,38 @@ void PartSkipDialog::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
} }
std::string dev_ver = obj->get_ota_version(); std::string dev_ver = obj->get_ota_version();
std::string dev_id = obj->get_dev_id(); std::string dev_id = obj->get_dev_id();
// int remote_proto = obj->get_file_remote();
NetworkAgent *agent = wxGetApp().getAgent(); NetworkAgent *agent = wxGetApp().getAgent();
std::string agent_version = agent ? agent->get_version() : ""; if (!agent) {
fs->SetUrl("3");
return;
}
auto url_state = m_url_state; auto url_state = m_url_state;
if (obj->is_lan_mode_printer()) { url_state = URL_TCP; } if (obj->is_lan_mode_printer()) { url_state = URL_TCP; }
if (agent) { FileTransferURLParams params;
switch (url_state) { params.url_state = url_state;
case URL_TCP: { params.ip_address = obj->get_dev_ip();
std::string devIP = obj->get_dev_ip(); params.username = agent->default_lan_username();
std::string accessCode = obj->get_access_code(); params.password = obj->get_access_code();
std::string tcp_url = "bambu:///local/" + devIP + "?port=6000&user=" + "bblp" + "&passwd=" + accessCode; params.device_id = dev_id;
CallAfter([=] { params.network_version = agent->get_version();
params.device_version = dev_ver;
params.refresh_url = boost::lexical_cast<std::string>(&refresh_agora_url);
params.client_id = wxGetApp().app_config->get("slicer_uuid");
params.client_version = SLIC3R_VERSION;
agent->get_file_transfer_url(
dev_id,
[this, wfs](FileTransferURLResult result) {
CallAfter([wfs, result = std::move(result)]() mutable {
boost::shared_ptr fs(wfs.lock()); boost::shared_ptr fs(wfs.lock());
if (!fs) return; if (!fs) return;
if (boost::algorithm::starts_with(tcp_url, "bambu:///")) { fs->SetUrl(result.is_success ? result.url : "3");
fs->SetUrl(tcp_url);
} else {
fs->SetUrl("3");
}
}); });
break; },
} std::move(params));
case URL_TUTK: {
std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
agent->get_camera_url(obj->get_dev_id() + "|" + dev_ver + "|" + protocols[3], [this, wfs, m = dev_id, v = agent->get_version(), dv = dev_ver](std::string url)
{
if (boost::algorithm::starts_with(url, "bambu:///")) {
url += "&device=" + m;
url += "&net_ver=" + v;
url += "&dev_ver=" + dv;
url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url);
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
CallAfter([=] {
boost::shared_ptr fs(wfs.lock());
if (!fs) return;
if (boost::algorithm::starts_with(url, "bambu:///")) {
fs->SetUrl(url);
} else {
fs->SetUrl("3");
}
});
});
break;
}
default: break;
}
}
} }
// controller // controller
void PartSkipDialog::OnFileSystemEvent(wxCommandEvent &e) void PartSkipDialog::OnFileSystemEvent(wxCommandEvent &e)
+1 -6
View File
@@ -29,11 +29,6 @@ namespace Slic3r { namespace GUI {
class SkipPartCanvas; class SkipPartCanvas;
enum URL_STATE {
URL_TCP,
URL_TUTK,
};
class PartSkipConfirmDialog : public DPIDialog class PartSkipConfirmDialog : public DPIDialog
{ {
private: private:
@@ -160,4 +155,4 @@ private:
void OnApplyDialog(wxCommandEvent &event); void OnApplyDialog(wxCommandEvent &event);
}; };
}} // namespace Slic3r::GUI }} // namespace Slic3r::GUI
+5
View File
@@ -1801,6 +1801,8 @@ void InputIpAddressDialog::on_ok(wxMouseEvent& evt)
m_trouble_shoot->Hide(); m_trouble_shoot->Hide();
std::string str_ip = m_input_ip->GetTextCtrl()->GetValue().ToStdString(); std::string str_ip = m_input_ip->GetTextCtrl()->GetValue().ToStdString();
std::string str_access_code = m_input_access_code->GetTextCtrl()->GetValue().ToStdString(); std::string str_access_code = m_input_access_code->GetTextCtrl()->GetValue().ToStdString();
if (str_access_code.empty())
str_access_code = "88888888";
std::string str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both).ToStdString(); std::string str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both).ToStdString();
// Serial number should not contain lower case letters, and bambu_network plugin crashes // Serial number should not contain lower case letters, and bambu_network plugin crashes
// if user entered the wrong serial number, so we call `Upper()` here. // if user entered the wrong serial number, so we call `Upper()` here.
@@ -1835,6 +1837,8 @@ void InputIpAddressDialog::on_send_retry()
Fit(); Fit();
wxString ip = m_input_ip->GetTextCtrl()->GetValue(); wxString ip = m_input_ip->GetTextCtrl()->GetValue();
wxString str_access_code = m_input_access_code->GetTextCtrl()->GetValue(); wxString str_access_code = m_input_access_code->GetTextCtrl()->GetValue();
if (str_access_code.empty())
str_access_code = "88888888";
// check support function // check support function
if (!m_obj) return; if (!m_obj) return;
@@ -2058,6 +2062,7 @@ void InputIpAddressDialog::on_text(wxCommandEvent &evt)
if (str_access_code.empty()) { if (str_access_code.empty()) {
str_access_code = "88888888"; str_access_code = "88888888";
m_input_access_code->GetTextCtrl()->SetValue(str_access_code);
} }
auto str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both); auto str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both);
+119 -55
View File
@@ -1,6 +1,7 @@
#include "SendToPrinter.hpp" #include "SendToPrinter.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include "IPrinterAgent.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/Thread.hpp" #include "libslic3r/Thread.hpp"
#include "GUI.hpp" #include "GUI.hpp"
@@ -25,7 +26,6 @@
#include "DeviceCore/DevManager.h" #include "DeviceCore/DevManager.h"
#include "DeviceCore/DevStorage.h" #include "DeviceCore/DevStorage.h"
#include "slic3r/Utils/FileTransferUtils.hpp"
namespace Slic3r { namespace Slic3r {
@@ -1715,64 +1715,93 @@ void SendToPrinterDialog::GetConnection()
if (m_tcp_try_connect) { if (m_tcp_try_connect) {
std::string devIP = obj->get_dev_ip(); std::string devIP = obj->get_dev_ip();
std::string accessCode = obj->get_access_code(); std::string accessCode = obj->get_access_code();
std::string url = "bambu:///local/" + devIP + "?port=6000&user=" + "bblp" + "&passwd=" + accessCode;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tcp"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tcp";
m_filetransfer_tunnel = std::make_unique<FileTransferTunnel>(module(), url);
m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) { if (agent->get_printer_agent()) {
CallAfter([this, is_success, err_code, error_msg]() { try {
OnConnection(is_success, err_code, error_msg); m_filetransfer_tunnel = agent->get_printer_agent()->create_file_transfer_tunnel(devIP, accessCode);
}); } catch (const std::exception& e) {
}); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create TCP file-transfer tunnel: " << e.what();
m_filetransfer_tunnel->start_connect(); }
if (m_filetransfer_tunnel && m_filetransfer_tunnel->check_valid()) {
m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) {
CallAfter([this, is_success, err_code, error_msg]() {
OnConnection(is_success, err_code, error_msg);
});
});
m_filetransfer_tunnel->start_connect();
} else {
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
}
} else {
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
}
} }
else if (m_tutk_try_connect) else if (m_tutk_try_connect)
{ {
std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
agent->get_camera_url(obj->get_dev_id() + "|" + dev_ver + "|" + protocols[1], [this, m = dev_id, v = agent->get_version(), dv = dev_ver](std::string url) { agent->get_camera_url(
if (boost::algorithm::starts_with(url, "bambu:///")) { obj->get_dev_id() + "|" + dev_ver + "|" + protocols[1],
url += "&device=" + m; [this, pa = agent->get_printer_agent()](CameraURLResult result) {
url += "&net_ver=" + v; std::string url = std::move(result.url);
url += "&dev_ver=" + dv; if (m_url_timer && m_url_timer->IsRunning()) {
url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url); m_url_timer->Stop();
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
if (m_url_timer && m_url_timer->IsRunning())
{
m_url_timer->Stop();
}
#if !BBL_RELEASE_TO_PUBLIC
BOOST_LOG_TRIVIAL(info) << "SendToPrinter::camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
#endif
if (boost::algorithm::starts_with(url, "bambu:///"))
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tutk";
m_filetransfer_tunnel = std::make_unique<FileTransferTunnel>(module(), url);
m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) {
CallAfter([this, is_success, err_code, error_msg]() { OnConnection(is_success, err_code, error_msg); });
});
m_filetransfer_tunnel->start_connect();
}
else
{
std::string res = "";
if (!url.empty() && boost::ends_with(url, "]"))
{
size_t n = url.find_last_of('[');
if (n != std::string::npos)
res = url.substr(n + 1, url.length() - n - 2);
} }
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : Tutk url error: ress = " << res;
} #if !BBL_RELEASE_TO_PUBLIC
}); BOOST_LOG_TRIVIAL(info) << "SendToPrinter::camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
#endif
if (result.is_success) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tutk";
if (!pa) {
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
return;
}
try {
m_filetransfer_tunnel = pa->create_file_transfer_tunnel_from_url(url);
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create TUTK file-transfer tunnel: " << e.what();
}
if (!m_filetransfer_tunnel || !m_filetransfer_tunnel->check_valid()) {
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
return;
}
m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) {
CallAfter([this, is_success, err_code, error_msg]() { OnConnection(is_success, err_code, error_msg); });
});
m_filetransfer_tunnel->start_connect();
} else {
std::string res = result.error_code >= 0 ? std::to_string(result.error_code) : "";
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : Tutk url error: ress = " << res;
show_file_transfer_error(PrintDialogStatus::PrintStatusPublicInitFailed,
_L("Connection failed. Please check your network and try again."));
}
},
wxGetApp().get_printer_cloud_provider(),
CameraURLParams{"", "", "", LVL_None, dev_id, agent->get_version(), dev_ver,
boost::lexical_cast<std::string>(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true});
} }
} }
} }
void SendToPrinterDialog::show_file_transfer_error(PrintDialogStatus status, wxString message)
{
if (m_url_timer && m_url_timer->IsRunning())
m_url_timer->Stop();
m_connection_status = ConnectionStatus::CONNECTION_FAILED;
GetConnection();
show_status(status);
update_print_status_msg(message, false, true);
}
void SendToPrinterDialog::OnConnection(bool is_success, int error_code, std::string error_msg) { void SendToPrinterDialog::OnConnection(bool is_success, int error_code, std::string error_msg) {
if (is_success) if (is_success)
{ {
@@ -1854,8 +1883,24 @@ void SendToPrinterDialog::ResetTunnelAndJob()
void SendToPrinterDialog::CreateMediaAbilityJob() void SendToPrinterDialog::CreateMediaAbilityJob()
{ {
NetworkAgent *agent = wxGetApp().getAgent();
if (!agent || !agent->get_printer_agent()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no printer agent available";
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
return;
}
nlohmann::json media_ability = {{"cmd_type", 7}}; nlohmann::json media_ability = {{"cmd_type", 7}};
m_filetransfer_mediability_job = std::make_unique<FileTransferJob>(module(), std::string(media_ability.dump())); try {
m_filetransfer_mediability_job = agent->get_printer_agent()->create_file_transfer_job(std::string(media_ability.dump()));
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create media-ability job: " << e.what();
}
if (!m_filetransfer_mediability_job || !m_filetransfer_mediability_job->check_valid()) {
show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
return;
}
m_filetransfer_mediability_job->on_result([this](int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res) { m_filetransfer_mediability_job->on_result([this](int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res) {
//this pl //this pl
CallAfter([this, res, resp_ec, json_res] { CallAfter([this, res, resp_ec, json_res] {
@@ -1897,10 +1942,11 @@ void SendToPrinterDialog::CreateMediaAbilityJob()
}); });
}); });
// Guard against a null transfer tunnel before dereferencing. // Guard against a null transfer tunnel before dereferencing.
if (m_filetransfer_tunnel) { if (m_filetransfer_tunnel && m_filetransfer_tunnel->check_valid()) {
m_filetransfer_mediability_job->start_on(*m_filetransfer_tunnel); m_filetransfer_mediability_job->start_on(*m_filetransfer_tunnel);
} else { } else {
BOOST_LOG_TRIVIAL(info) << "CreateMediaAbilityJob: file transfer tunnel is null"; show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard,
_L("The selected printer does not support file transfer."));
} }
} }
@@ -1913,8 +1959,25 @@ void SendToPrinterDialog::CreateUploadFileJob(const std::string &path, const std
upload_params["dest_name"] = name; // filenme no path upload_params["dest_name"] = name; // filenme no path
upload_params["file_path"] = path; upload_params["file_path"] = path;
NetworkAgent *agent = wxGetApp().getAgent();
if (!agent || !agent->get_printer_agent()) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": no printer agent available";
show_file_transfer_error(PrintDialogStatus::PrintStatusPublicUploadFiled,
_L("The selected printer does not support file transfer."));
return;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Begin CreateUploadFileJob"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Begin CreateUploadFileJob";
m_filetransfer_uploadfile_job = std::make_unique<FileTransferJob>(module(), std::string(upload_params.dump())); try {
m_filetransfer_uploadfile_job = agent->get_printer_agent()->create_file_transfer_job(std::string(upload_params.dump()));
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create upload job: " << e.what();
}
if (!m_filetransfer_uploadfile_job || !m_filetransfer_uploadfile_job->check_valid()) {
show_file_transfer_error(PrintDialogStatus::PrintStatusPublicUploadFiled,
_L("The selected printer does not support file transfer."));
return;
}
m_filetransfer_uploadfile_job->on_result([this](int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res) { // m_filetransfer_uploadfile_job->on_result([this](int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res) { //
CallAfter([this, res, resp_ec, json_res, bin_res] { CallAfter([this, res, resp_ec, json_res, bin_res] {
UploadFileRessultCallback(res, resp_ec,json_res, bin_res); UploadFileRessultCallback(res, resp_ec,json_res, bin_res);
@@ -1942,10 +2005,11 @@ void SendToPrinterDialog::CreateUploadFileJob(const std::string &path, const std
}); });
}); });
// Guard against a null transfer tunnel before dereferencing. // Guard against a null transfer tunnel before dereferencing.
if (m_filetransfer_tunnel) { if (m_filetransfer_tunnel && m_filetransfer_tunnel->check_valid()) {
m_filetransfer_uploadfile_job->start_on(*m_filetransfer_tunnel); m_filetransfer_uploadfile_job->start_on(*m_filetransfer_tunnel);
} else { } else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": file transfer tunnel is null"; show_file_transfer_error(PrintDialogStatus::PrintStatusPublicUploadFiled,
_L("The selected printer does not support file transfer."));
} }
} }
+5 -5
View File
@@ -24,6 +24,7 @@
#include <wx/wrapsizer.h> #include <wx/wrapsizer.h>
#include <wx/srchctrl.h> #include <wx/srchctrl.h>
#include "IPrinterAgent.hpp"
#include "SelectMachine.hpp" #include "SelectMachine.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
@@ -43,8 +44,6 @@
namespace Slic3r { namespace Slic3r {
class FileTransferTunnel;
class FileTransferJob;
namespace GUI { namespace GUI {
@@ -171,9 +170,9 @@ private:
enum ConnectionStatus { NOT_START, CONNECTING, CONNECTED, CONNECTION_FAILED, DISCONNECTED }; enum ConnectionStatus { NOT_START, CONNECTING, CONNECTED, CONNECTION_FAILED, DISCONNECTED };
ConnectionStatus m_connection_status{ConnectionStatus::NOT_START}; ConnectionStatus m_connection_status{ConnectionStatus::NOT_START};
std::unique_ptr<FileTransferTunnel> m_filetransfer_tunnel; std::unique_ptr<IFileTransferTunnel> m_filetransfer_tunnel;
std::unique_ptr<FileTransferJob> m_filetransfer_mediability_job; std::unique_ptr<IFileTransferJob> m_filetransfer_mediability_job;
std::unique_ptr<FileTransferJob> m_filetransfer_uploadfile_job; std::unique_ptr<IFileTransferJob> m_filetransfer_uploadfile_job;
wxDateTime m_last_refresh_time; wxDateTime m_last_refresh_time;
public: public:
@@ -223,6 +222,7 @@ public:
private: private:
void ResetConnectMethod(); void ResetConnectMethod();
void ResetTunnelAndJob(); void ResetTunnelAndJob();
void show_file_transfer_error(PrintDialogStatus status, wxString message);
void OnConnection(bool is_success, int error_code, std::string error_msg); void OnConnection(bool is_success, int error_code, std::string error_msg);
void CreateMediaAbilityJob(); void CreateMediaAbilityJob();
void CreateUploadFileJob(const std::string &path, const std::string &name); void CreateUploadFileJob(const std::string &path, const std::string &name);
+37 -2
View File
@@ -1,5 +1,6 @@
#include "BBLCloudServiceAgent.hpp" #include "BBLCloudServiceAgent.hpp"
#include "BBLNetworkPlugin.hpp" #include "BBLNetworkPlugin.hpp"
#include "NetworkAgent.hpp"
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include "Http.hpp" #include "Http.hpp"
@@ -606,13 +607,47 @@ int BBLCloudServiceAgent::modify_printer_name(std::string dev_id, std::string de
// Model Mall & Publishing // Model Mall & Publishing
// ============================================================================ // ============================================================================
int BBLCloudServiceAgent::get_camera_url(std::string dev_id, std::function<void(std::string)> callback) int BBLCloudServiceAgent::get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback, CameraURLParams params)
{ {
auto& plugin = BBLNetworkPlugin::instance(); auto& plugin = BBLNetworkPlugin::instance();
auto agent = plugin.get_agent(); auto agent = plugin.get_agent();
auto func = plugin.get_get_camera_url(); auto func = plugin.get_get_camera_url();
if (func && agent) { if (func && agent) {
return func(agent, dev_id, callback); auto make_result = [](std::string url) {
CameraURLResult result;
result.url = std::move(url);
result.is_success = result.url.rfind("bambu:///", 0) == 0;
if (result.is_success) {
result.error_code = 0;
} else if (!result.url.empty() && result.url.back() == ']') {
const auto start = result.url.rfind('[');
if (start != std::string::npos && start + 1 < result.url.size() - 1) {
try {
result.error_code = std::stoi(result.url.substr(start + 1, result.url.size() - start - 2));
} catch (...) {
}
}
}
return result;
};
if (params.apply_meta) {
auto decorated_callback = [callback = std::move(callback), params = std::move(params), make_result](std::string url) {
CameraURLResult result = make_result(std::move(url));
if (result.is_success) {
result.url += "&device=" + params.device;
result.url += "&net_ver=" + params.network_version;
result.url += "&dev_ver=" + params.device_version;
result.url += "&refresh_url=" + params.refresh_url;
result.url += "&cli_id=" + params.client_id;
result.url += "&cli_ver=" + params.client_version;
}
callback(std::move(result));
};
return func(agent, std::move(dev_id), std::move(decorated_callback));
}
return func(agent, std::move(dev_id), [callback = std::move(callback), make_result](std::string url) {
callback(make_result(std::move(url)));
});
} }
return -1; return -1;
} }
+1 -1
View File
@@ -89,7 +89,7 @@ public:
int modify_printer_name(std::string dev_id, std::string dev_name) override; int modify_printer_name(std::string dev_id, std::string dev_name) override;
// Model Mall & Publishing // Model Mall & Publishing
int get_camera_url(std::string dev_id, std::function<void(std::string)> callback) override; int get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback, CameraURLParams params) override;
int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback) override; int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback) override;
int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out) override; int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out) override;
int get_model_publish_url(std::string* url) override; int get_model_publish_url(std::string* url) override;
+289 -2
View File
@@ -1,14 +1,208 @@
#include "BBLPrinterAgent.hpp" #include "BBLPrinterAgent.hpp"
#include "BBLNetworkPlugin.hpp" #include "BBLNetworkPlugin.hpp"
#include "FileTransferUtils.hpp"
#include "IPrinterAgent.hpp"
#include "NetworkAgentFactory.hpp" #include "NetworkAgentFactory.hpp"
#include "NetworkAgent.hpp"
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <memory>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <cmath> #include <cmath>
#include <slic3r/GUI/DeviceManager.hpp>
#include <libslic3r/Utils.hpp>
namespace Slic3r { namespace Slic3r {
// ============================================================================
// File Transfer (Bambu eMMC tunnel ABI)
// ============================================================================
BBLFileTransferTunnel::BBLFileTransferTunnel(const std::string &url) : IFileTransferTunnel(url)
{
FileTransferModule &m = module();
m_ = &m;
// Guard against missing symbols in older Bambu networking plugins.
// These symbols were added in a newer plugin ABI; if the installed
// plugin predates them, ft_tunnel_create/ft_tunnel_set_status_cb
// will be null and calling them crashes.
if (!m_->ft_tunnel_create || !m_->ft_tunnel_set_status_cb) {
throw std::runtime_error("Bambu networking plugin is too old: missing ft_tunnel_* symbols. "
"Please update the networking plugin.");
}
FT_TunnelHandle *h{};
if (m_->ft_tunnel_create(url.c_str(), &h) != 0 || !h) {
throw std::runtime_error("ft_tunnel_create failed");
}
h_ = h;
// C API: ft_status_cb(void* user, int old_status, int new_status, int err, const char* msg)
auto tramp = [](void *user, int old_status, int new_status, int err_code, const char *msg) noexcept {
auto *self = reinterpret_cast<BBLFileTransferTunnel *>(user);
self->status_ = new_status;
if (!self->status_cb_) return;
try {
self->status_cb_(old_status, new_status, err_code, std::string(msg ? msg : ""));
} catch (...) {}
};
if (m_->ft_tunnel_set_status_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_set_status_cb failed"); }
}
void BBLFileTransferTunnel::start_connect()
{
// C API: ft_conn_cb(void* user, int ok, int err, const char* msg)
auto tramp = [](void *user, int ok, int ec, const char *msg) noexcept {
auto *pcb = reinterpret_cast<ConnectionCb *>(user);
if (!pcb) return;
try {
(*pcb)(ok == 0, ec, std::string(msg ? msg : ""));
} catch (...) {}
};
if (m_->ft_tunnel_start_connect(h_, tramp, &conn_cb_) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_start_connect failed"); }
}
bool BBLFileTransferTunnel::sync_start_connect()
{
return m_->ft_tunnel_sync_connect(h_) == FT_OK;
}
void BBLFileTransferTunnel::shutdown()
{
if (m_->ft_tunnel_shutdown) (void) m_->ft_tunnel_shutdown(h_);
}
BBLFileTransferJob::BBLFileTransferJob(const std::string &params_json) : IFileTransferJob(params_json)
{
m_ = &module();
FT_JobHandle *h{};
if (m_->ft_job_create(params_json.c_str(), &h) != 0 || !h) {
throw std::runtime_error("ft_job_create failed");
}
h_ = h;
// C API: ft_job_result_cb(void* user, int tunnel_err, ft_job_result result)
auto tramp = [](void *user, ft_job_result r) noexcept {
auto *self = reinterpret_cast<BBLFileTransferJob *>(user);
if (!self) return;
try {
self->finished_ = true;
self->solve_result(r);
if (self->result_cb_) self->result_cb_(self->res_, self->resp_ec_, self->res_json_, self->res_bin_);
} catch (...) {
// swallow
}
try {
if (auto *mod = self ? self->m_ : nullptr) {
if (mod->ft_job_result_destroy)
mod->ft_job_result_destroy(&r);
else if (mod->ft_free) {
if (r.json) mod->ft_free((void *) r.json);
if (r.bin) mod->ft_free((void *) r.bin);
}
}
} catch (...) {}
};
if (m_->ft_job_set_result_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_job_set_result_cb failed"); }
}
bool BBLFileTransferJob::get_result(int &ec, int &resp_ec, std::string &json, std::vector<std::byte> &bin, uint32_t timeout_ms)
{
if (!h_) throw std::runtime_error("job handle invalid");
ft_job_result result;
if (m_->ft_job_get_result(h_, timeout_ms, &result) == ft_err::FT_EXCEPTION) return false;
solve_result(result);
m_->ft_job_result_destroy(&result);
ec = res_;
resp_ec = res_;
json = res_json_;
bin = res_bin_;
return true;
}
void BBLFileTransferJob::start_on(IFileTransferTunnel &t)
{
if (!h_) throw std::runtime_error("job handle invalid");
auto *handle = reinterpret_cast<FT_TunnelHandle *>(t.native());
if (m_->ft_tunnel_start_job(handle, h_) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_start_job failed"); }
}
void BBLFileTransferJob::on_msg(MsgCb cb)
{
IFileTransferJob::on_msg(std::move(cb));
if (!h_) return;
// C API: ft_job_msg_cb(void* user, ft_job_msg msg)
auto tramp = [](void *user, ft_job_msg m) noexcept {
auto *self = reinterpret_cast<BBLFileTransferJob *>(user);
if (!self) return;
try {
if (self->msg_cb_) { self->msg_cb_(m.kind, std::string(m.json ? m.json : "")); }
} catch (...) {}
try {
if (auto *mod = self->m_) {
if (mod->ft_job_msg_destroy)
mod->ft_job_msg_destroy(&m);
else if (mod->ft_free && m.json)
mod->ft_free((void *) m.json);
}
} catch (...) {}
};
if (m_->ft_job_set_msg_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_job_set_msg_cb failed"); }
}
bool BBLFileTransferJob::try_get_msg(int &kind, std::string &json)
{
if (!h_) return false;
ft_job_msg m{};
int rc = m_->ft_job_try_get_msg(h_, &m);
if (rc != 0) return false;
kind = m.kind;
json.assign(m.json ? m.json : "");
if (m_->ft_job_msg_destroy)
m_->ft_job_msg_destroy(&m);
else if (m_->ft_free && m.json)
m_->ft_free((void *) m.json);
return true;
}
bool BBLFileTransferJob::get_msg(uint32_t timeout_ms, int &kind, std::string &json)
{
if (!h_) return false;
ft_job_msg m{};
int rc = m_->ft_job_get_msg(h_, timeout_ms, &m);
if (rc != 0) return false;
kind = m.kind;
json.assign(m.json ? m.json : "");
if (m_->ft_job_msg_destroy)
m_->ft_job_msg_destroy(&m);
else if (m_->ft_free && m.json)
m_->ft_free((void *) m.json);
return true;
}
void BBLFileTransferJob::solve_result(ft_job_result result)
{
res_ = result.ec;
resp_ec_ = result.resp_ec;
res_bin_.clear();
if (result.bin && result.bin_size) res_bin_.assign(reinterpret_cast<const std::byte *>(result.bin),
reinterpret_cast<const std::byte *>(result.bin) + result.bin_size);
res_json_.assign(result.json ? result.json : "");
}
BBLPrinterAgent::BBLPrinterAgent() = default; BBLPrinterAgent::BBLPrinterAgent() = default;
BBLPrinterAgent::~BBLPrinterAgent() = default; BBLPrinterAgent::~BBLPrinterAgent() = default;
@@ -246,9 +440,70 @@ int BBLPrinterAgent::send_message_to_printer(std::string dev_id, std::string jso
return -1; return -1;
} }
std::string BBLPrinterAgent::get_local_camera_url(std::string dev_ip, std::string username, std::string password) std::string BBLPrinterAgent::get_local_camera_url(CameraURLParams params)
{ {
return "bambu:///local/" + dev_ip + ".?port=6000&user=" + username + "&passwd=" + password; std::string url;
if (params.protocol == LVL_Local)
url = "bambu:///local/" + params.ip_address + ".?port=6000&user=" + params.user + "&passwd=" + params.password;
else if (params.protocol == LVL_Rtsps)
url = "bambu:///rtsps___" + params.user + ":" + params.password + "@" + params.ip_address + "/streaming/live/1?proto=rtsps";
else if (params.protocol == LVL_Rtsp)
url = "bambu:///rtsp___" + params.user + ":" + params.password + "@" + params.ip_address + "/streaming/live/1?proto=rtsp";
else
url = "bambu:///local/" + params.ip_address + ".?port=6000&user=" + params.user + "&passwd=" + params.password;
url += "&device=" + params.device;
url += "&net_ver=" + params.network_version;
url += "&dev_ver=" + params.device_version;
url += "&cli_id=" + params.client_id;
url += "&cli_ver=" + params.client_version;
return url;
}
std::string BBLPrinterAgent::get_local_file_transfer_url(const FileTransferURLParams& params)
{
// Keep the historical PartSkipDialog URL unchanged. It is a file-transfer
// tunnel URL, not a camera URL, so it intentionally has no camera metadata
// suffix and no dot before the query string.
return "bambu:///local/" + params.ip_address + "?port=6000&user=" + params.username + "&passwd=" + params.password;
}
int BBLPrinterAgent::get_file_transfer_url(std::string dev_id, std::function<void(FileTransferURLResult)> callback,
FileTransferURLParams params)
{
if (params.url_state == URL_TCP) {
FileTransferURLResult result;
result.url = get_local_file_transfer_url(params);
result.is_success = !result.url.empty();
result.error_code = result.is_success ? 0 : -1;
if (callback)
callback(std::move(result));
return result.is_success ? 0 : -1;
}
if (!m_cloud_agent) {
if (callback)
callback({});
return -1;
}
const std::string protocols = "\"tutk\",\"agora\"";
return m_cloud_agent->get_camera_url(
std::move(dev_id) + "|" + params.device_version + "|" + protocols,
std::move(callback),
CameraURLParams{
"",
"",
"",
LVL_None,
params.device_id,
params.network_version,
params.device_version,
params.refresh_url,
params.client_id,
params.client_version,
true
});
} }
// ============================================================================ // ============================================================================
@@ -512,6 +767,15 @@ int BBLPrinterAgent::start_local_print_with_record(PrintParams params, OnUpdateS
BBLNetworkPlugin::instance().get_start_local_print_with_record(), params, update_fn, cancel_fn, wait_fn); BBLNetworkPlugin::instance().get_start_local_print_with_record(), params, update_fn, cancel_fn, wait_fn);
} }
int BBLPrinterAgent::verify_local_print_access(PrintParams params)
{
params.project_name = "verify_job";
params.filename = Slic3r::resources_dir() + "/check_access_code.txt";
params.try_emmc_print = false;
return start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr);
}
int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn) int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn)
{ {
int result = dispatch_start<func_start_send_gcode_to_sdcard_legacy, func_start_send_gcode_to_sdcard_0203>( int result = dispatch_start<func_start_send_gcode_to_sdcard_legacy, func_start_send_gcode_to_sdcard_0203>(
@@ -527,6 +791,16 @@ int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStat
int BBLPrinterAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn) int BBLPrinterAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
{ {
if (params.connection_type == "lan" && params.print_type == "from_normal") {
const int verify_result = verify_local_print_access(params);
if (verify_result != 0) {
BOOST_LOG_TRIVIAL(error) << "LAN connection verification failed: result=" << verify_result
<< ", dev_ip=" << params.dev_ip << ", dev_id=" << params.dev_id
<< ", password_length=" << params.password.size();
return ORCA_NETWORK_ERR_ACCESS_VERIFICATION_FAILED;
}
}
return dispatch_start<func_start_local_print_legacy, func_start_local_print_0203>( return dispatch_start<func_start_local_print_legacy, func_start_local_print_0203>(
BBLNetworkPlugin::instance().get_start_local_print(), params, update_fn, cancel_fn); BBLNetworkPlugin::instance().get_start_local_print(), params, update_fn, cancel_fn);
} }
@@ -639,4 +913,17 @@ FilamentSyncMode BBLPrinterAgent::get_filament_sync_mode() const
return FilamentSyncMode::subscription; return FilamentSyncMode::subscription;
} }
std::unique_ptr<IFileTransferTunnel> BBLPrinterAgent::create_file_transfer_tunnel(std::string& dev_ip, std::string& access_code) {
std::string url = "bambu:///local/" + dev_ip + "?port=6000&user=" + default_lan_username() + "&passwd=" + access_code;
return std::make_unique<BBLFileTransferTunnel>(url);
}
std::unique_ptr<IFileTransferTunnel> BBLPrinterAgent::create_file_transfer_tunnel_from_url(std::string url) {
return std::make_unique<BBLFileTransferTunnel>(url);
}
std::unique_ptr<IFileTransferJob> BBLPrinterAgent::create_file_transfer_job(std::string params_json) {
return std::make_unique<BBLFileTransferJob>(params_json);
}
} // namespace Slic3r } // namespace Slic3r
+81 -1
View File
@@ -3,12 +3,83 @@
#include "IPrinterAgent.hpp" #include "IPrinterAgent.hpp"
#include "ICloudServiceAgent.hpp" #include "ICloudServiceAgent.hpp"
#include "FileTransferUtils.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace Slic3r { namespace Slic3r {
/**
* BBLFileTransferTunnel - Bambu eMMC tunnel, backed by the Bambu network
* plugin's ft_tunnel_* ABI (see FileTransferUtils.hpp). Only BBLPrinterAgent
* constructs these; callers only ever see them through IFileTransferTunnel.
*/
class BBLFileTransferTunnel : public IFileTransferTunnel
{
public:
BBLFileTransferTunnel(const std::string &url);
~BBLFileTransferTunnel() override { reset(); }
void start_connect() override;
bool sync_start_connect() override;
void shutdown() override;
bool check_valid() const override { return h_ != nullptr; }
void *native() const noexcept override { return h_; }
private:
void reset() noexcept
{
if (h_) {
m_->ft_tunnel_release(h_);
h_ = nullptr;
}
}
FileTransferModule *m_{};
FT_TunnelHandle *h_{};
};
/**
* BBLFileTransferJob - a single ft_job_* operation (media-ability query,
* file upload, ...) run on a BBLFileTransferTunnel. Same ABI-wrapper role
* as BBLFileTransferTunnel; only BBLPrinterAgent constructs these.
*/
class BBLFileTransferJob : public IFileTransferJob
{
public:
explicit BBLFileTransferJob(const std::string &params_json);
~BBLFileTransferJob() override { reset(); }
bool get_result(int &ec, int &resp_ec, std::string &json, std::vector<std::byte> &bin, uint32_t timeout_ms) override;
void start_on(IFileTransferTunnel &t) override;
// why: unlike on_result() (fires from a trampoline registered once in the ctor),
// ft_job_set_msg_cb is only wired up here, lazily, on first real subscriber -
// that ABI call has to happen in the concrete class, not the vendor-neutral base.
void on_msg(MsgCb cb) override;
bool try_get_msg(int &kind, std::string &json) override;
bool get_msg(uint32_t timeout_ms, int &kind, std::string &json) override;
void *native() const noexcept override { return h_; }
bool check_valid() const override { return h_ != nullptr; }
void cancel() override
{
if (m_->ft_job_cancel && h_) m_->ft_job_cancel(h_);
}
private:
void reset() noexcept
{
if (h_) {
m_->ft_job_release(h_);
h_ = nullptr;
}
}
void solve_result(ft_job_result result);
FileTransferModule *m_{};
FT_JobHandle *h_{};
};
/** /**
* BBLPrinterAgent - BBL DLL wrapper implementation of IPrinterAgent. * BBLPrinterAgent - BBL DLL wrapper implementation of IPrinterAgent.
* *
@@ -45,7 +116,10 @@ public:
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override; int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override;
int disconnect_printer() override; int disconnect_printer() override;
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override; int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override;
std::string get_local_camera_url(std::string dev_ip, std::string username, std::string password) override; std::string get_local_camera_url(CameraURLParams params) override;
std::string get_local_file_transfer_url(const FileTransferURLParams& params) override;
int get_file_transfer_url(std::string dev_id, std::function<void(FileTransferURLResult)> callback,
FileTransferURLParams params) override;
std::string default_lan_username() const override { return "bblp"; } std::string default_lan_username() const override { return "bblp"; }
// Certificates // Certificates
@@ -100,7 +174,13 @@ public:
int set_queue_on_main_fn(QueueOnMainFn fn) override; int set_queue_on_main_fn(QueueOnMainFn fn) override;
FilamentSyncMode get_filament_sync_mode() const override; FilamentSyncMode get_filament_sync_mode() const override;
std::unique_ptr<IFileTransferTunnel> create_file_transfer_tunnel(std::string& dev_ip, std::string& access_code) override;
std::unique_ptr<IFileTransferTunnel> create_file_transfer_tunnel_from_url(std::string url) override;
std::unique_ptr<IFileTransferJob> create_file_transfer_job(std::string params_json) override;
private: private:
int verify_local_print_access(PrintParams params);
// why: the lan/cloud DECISION stays machine-side; keep this mechanical branch in sync with publish_json. // why: the lan/cloud DECISION stays machine-side; keep this mechanical branch in sync with publish_json.
int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode); int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode);
+1 -192
View File
@@ -1,8 +1,4 @@
#include <wx/wx.h>
#include <type_traits>
#include "FileTransferUtils.hpp" #include "FileTransferUtils.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/DeviceCore/DevManager.h"
namespace Slic3r { namespace Slic3r {
@@ -37,191 +33,4 @@ FileTransferModule::FileTransferModule(ModuleHandle networking_module, int requi
ft_job_get_msg = sym_lookup<fn_ft_job_get_msg>(networking_, "ft_job_get_msg"); ft_job_get_msg = sym_lookup<fn_ft_job_get_msg>(networking_, "ft_job_get_msg");
} }
FileTransferTunnel::FileTransferTunnel(FileTransferModule &m, const std::string &url) : m_(&m) } // namespace Slic3r
{
// Guard against missing symbols in older Bambu networking plugins.
// These symbols were added in a newer plugin ABI; if the installed
// plugin predates them, ft_tunnel_create/ft_tunnel_set_status_cb
// will be null and calling them crashes.
if (!m_->ft_tunnel_create || !m_->ft_tunnel_set_status_cb) {
throw std::runtime_error("Bambu networking plugin is too old: missing ft_tunnel_* symbols. "
"Please update the networking plugin.");
}
FT_TunnelHandle *h{};
if (m_->ft_tunnel_create(url.c_str(), &h) != 0 || !h) {
throw std::runtime_error("ft_tunnel_create failed");
}
h_ = h;
// C API: ft_status_cb(void* user, int old_status, int new_status, int err, const char* msg)
auto tramp = [](void *user, int old_status, int new_status, int err_code, const char *msg) noexcept {
auto *self = reinterpret_cast<FileTransferTunnel *>(user);
self->status_ = new_status;
if (!self->status_cb_) return;
try {
self->status_cb_(old_status, new_status, err_code, std::string(msg ? msg : ""));
} catch (...) {}
};
if (m_->ft_tunnel_set_status_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_set_status_cb failed"); }
}
void FileTransferTunnel::start_connect()
{
// C API: ft_conn_cb(void* user, int ok, int err, const char* msg)
auto tramp = [](void *user, int ok, int ec, const char *msg) noexcept {
auto *pcb = reinterpret_cast<ConnectionCb *>(user);
if (!pcb) return;
try {
(*pcb)(ok == 0, ec, std::string(msg ? msg : ""));
} catch (...) {}
};
if (m_->ft_tunnel_start_connect(h_, tramp, &conn_cb_) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_start_connect failed"); }
}
bool FileTransferTunnel::sync_start_connect()
{
return m_->ft_tunnel_sync_connect(h_) == FT_OK;
}
void FileTransferTunnel::on_connection(ConnectionCb cb) { conn_cb_ = std::move(cb); }
void FileTransferTunnel::on_status(TunnelStatusCb cb) { status_cb_ = std::move(cb); }
void FileTransferTunnel::shutdown()
{
if (m_->ft_tunnel_shutdown) (void) m_->ft_tunnel_shutdown(h_);
}
FileTransferJob::FileTransferJob(FileTransferModule &m, const std::string &params_json) : m_(&m)
{
FT_JobHandle *h{};
if (m_->ft_job_create(params_json.c_str(), &h) != 0 || !h) {
}
h_ = h;
// C API: ft_job_result_cb(void* user, int tunnel_err, ft_job_result result)
auto tramp = [](void *user, ft_job_result r) noexcept {
auto *self = reinterpret_cast<FileTransferJob *>(user);
if (!self) return;
try {
self->finished_ = true;
self->solve_result(r);
if (self->result_cb_) self->result_cb_(self->res_, self->resp_ec_, self->res_json_, self->res_bin_);
self->m_->ft_job_result_destroy(&r);
} catch (...) {
// swallow
}
try {
if (auto *mod = self ? self->m_ : nullptr) {
if (mod->ft_job_result_destroy)
mod->ft_job_result_destroy(&r);
else if (mod->ft_free) {
if (r.json) mod->ft_free((void *) r.json);
if (r.bin) mod->ft_free((void *) r.bin);
}
}
} catch (...) {}
};
if (m_->ft_job_set_result_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_job_set_result_cb failed"); }
}
void FileTransferJob::on_result(ResultCb cb) { result_cb_ = std::move(cb); }
bool FileTransferJob::get_result(int &ec, int &resp_ec, std::string &json, std::vector<std::byte> &bin, uint32_t timeout_ms)
{
if (!h_) throw std::runtime_error("job handle invalid");
ft_job_result result;
if (m_->ft_job_get_result(h_, timeout_ms, &result) == ft_err::FT_EXCEPTION) return false;
solve_result(result);
m_->ft_job_result_destroy(&result);
ec = res_;
resp_ec = res_;
json = res_json_;
bin = res_bin_;
return true;
}
void FileTransferJob::start_on(FileTransferTunnel &t)
{
if (!h_) throw std::runtime_error("job handle invalid");
if (m_->ft_tunnel_start_job(t.native(), h_) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_start_job failed"); }
}
void FileTransferJob::on_msg(MsgCb cb)
{
msg_cb_ = std::move(cb);
if (!h_) return;
// C API: ft_job_msg_cb(void* user, ft_job_msg msg)
auto tramp = [](void *user, ft_job_msg m) noexcept {
auto *self = reinterpret_cast<FileTransferJob *>(user);
if (!self) return;
try {
if (self->msg_cb_) { self->msg_cb_(m.kind, std::string(m.json ? m.json : "")); }
} catch (...) {}
try {
if (auto *mod = self->m_) {
if (mod->ft_job_msg_destroy)
mod->ft_job_msg_destroy(&m);
else if (mod->ft_free && m.json)
mod->ft_free((void *) m.json);
}
} catch (...) {}
};
if (m_->ft_job_set_msg_cb(h_, tramp, this) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_job_set_msg_cb failed"); }
}
bool FileTransferJob::try_get_msg(int &kind, std::string &json)
{
if (!h_) return false;
ft_job_msg m{};
int rc = m_->ft_job_try_get_msg(h_, &m);
if (rc != 0) return false;
kind = m.kind;
json.assign(m.json ? m.json : "");
if (m_->ft_job_msg_destroy)
m_->ft_job_msg_destroy(&m);
else if (m_->ft_free && m.json)
m_->ft_free((void *) m.json);
return true;
}
bool FileTransferJob::get_msg(uint32_t timeout_ms, int &kind, std::string &json)
{
if (!h_) return false;
ft_job_msg m{};
int rc = m_->ft_job_get_msg(h_, timeout_ms, &m);
if (rc != 0) return false;
kind = m.kind;
json.assign(m.json ? m.json : "");
if (m_->ft_job_msg_destroy)
m_->ft_job_msg_destroy(&m);
else if (m_->ft_free && m.json)
m_->ft_free((void *) m.json);
return true;
}
void FileTransferJob::solve_result(ft_job_result result)
{
res_ = result.ec;
resp_ec_ = result.resp_ec;
res_bin_.clear();
if (result.bin && result.bin_size) res_bin_.assign(reinterpret_cast<const std::byte *>(result.bin),
reinterpret_cast<const std::byte *>(result.bin) + result.bin_size);
res_json_.assign(result.json ? result.json : "");
}
} // namespace Slic3r
+5 -103
View File
@@ -1,13 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <functional>
#include <vector>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <stdexcept> #include <stdexcept>
#include <utility>
#include <cstring>
#include <memory>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#ifdef _WIN32 #ifdef _WIN32
@@ -134,103 +128,11 @@ struct FileTransferModule
FileTransferModule &operator=(const FileTransferModule &) = delete; FileTransferModule &operator=(const FileTransferModule &) = delete;
}; };
class FileTransferTunnel // FileTransferTunnel/FileTransferJob (the OOP wrapper around the ft_tunnel_*/
{ // ft_job_* ABI below) live in BBLPrinterAgent.hpp as BBLFileTransferTunnel/
public: // BBLFileTransferJob, implementing IFileTransferTunnel/IFileTransferJob
using ConnectionCb = std::function<void(bool is_success, int err_code, std::string error_msg)>; // (IPrinterAgent.hpp) - this header stays the low-level symbol-table layer
using TunnelStatusCb = std::function<void(int old_status, int new_status, int err_code, std::string error_msg)>; // only, same role as bambu_networking.hpp's function pointer typedefs.
explicit FileTransferTunnel(FileTransferModule &m, const std::string &url);
~FileTransferTunnel() { reset(); }
FileTransferTunnel(const FileTransferTunnel &) = delete;
FileTransferTunnel &operator=(const FileTransferTunnel &) = delete;
FileTransferTunnel(FileTransferTunnel &&) = delete;
FileTransferTunnel &operator=(FileTransferTunnel &&) = delete;
void start_connect();
bool sync_start_connect();
void on_connection(ConnectionCb cb);
void on_status(TunnelStatusCb cb);
void shutdown();
int get_status() const { return status_; }
bool check_valid() const { return h_ != nullptr; }
FT_TunnelHandle *native() const noexcept { return h_; }
private:
void reset() noexcept
{
if (h_) {
m_->ft_tunnel_release(h_);
h_ = nullptr;
}
}
int status_{};
FileTransferModule *m_{};
FT_TunnelHandle *h_{};
ConnectionCb conn_cb_{};
TunnelStatusCb status_cb_{};
};
class FileTransferJob
{
public:
using ResultCb = std::function<void(int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res)>;
using MsgCb = std::function<void(int kind, std::string json)>;
explicit FileTransferJob(FileTransferModule &m, const std::string &params_json);
~FileTransferJob() { reset(); }
FileTransferJob(const FileTransferJob &) = delete;
FileTransferJob &operator=(const FileTransferJob &) = delete;
FileTransferJob(FileTransferJob &&) = delete;
FileTransferJob &operator=(FileTransferJob &&) = delete;
void on_result(ResultCb cb);
bool get_result(int &ec, int &resp_ec, std::string &json, std::vector<std::byte> &bin, uint32_t timeout_ms);
void start_on(FileTransferTunnel &t);
void on_msg(MsgCb cb);
bool try_get_msg(int &kind, std::string &json);
bool get_msg(uint32_t timeout_ms, int &kind, std::string &json);
FT_JobHandle *native() const noexcept { return h_; }
bool check_valid() const { return h_ != nullptr; }
bool finished() const { return finished_; }
void cancel()
{
if (m_->ft_job_cancel && h_) m_->ft_job_cancel(h_);
}
private:
void reset() noexcept
{
if (h_) {
m_->ft_job_release(h_);
h_ = nullptr;
}
}
void solve_result(ft_job_result result);
FileTransferModule *m_{};
FT_JobHandle *h_{};
ResultCb result_cb_{};
MsgCb msg_cb_{};
bool finished_ = false;
int res_ = 0;
int resp_ec_ = 0;
std::string res_json_;
std::vector<std::byte> res_bin_;
};
namespace detail { namespace detail {
inline FileTransferModule *g_mod = nullptr; inline FileTransferModule *g_mod = nullptr;
+5 -1
View File
@@ -47,6 +47,9 @@ struct CloudEvent {
using AppOnServerConnectedFn = std::function<void(CloudEvent event, int return_code, int reason_code)>; using AppOnServerConnectedFn = std::function<void(CloudEvent event, int return_code, int reason_code)>;
using AppOnHttpErrorFn = std::function<void(CloudEvent event, unsigned http_code, std::string http_body)>; using AppOnHttpErrorFn = std::function<void(CloudEvent event, unsigned http_code, std::string http_body)>;
struct CameraURLParams;
struct CameraURLResult;
class ICloudServiceAgent { class ICloudServiceAgent {
public: public:
virtual ~ICloudServiceAgent() = default; virtual ~ICloudServiceAgent() = default;
@@ -328,7 +331,8 @@ public:
/** /**
* Request live camera streaming URL. * Request live camera streaming URL.
*/ */
virtual int get_camera_url(std::string dev_id, std::function<void(std::string)> callback) = 0; virtual int get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback,
CameraURLParams params) = 0;
/** /**
* Fetch staff-picked designs from model mall. * Fetch staff-picked designs from model mall.
+115 -2
View File
@@ -2,6 +2,7 @@
#define __I_PRINTER_AGENT_HPP__ #define __I_PRINTER_AGENT_HPP__
#include "bambu_networking.hpp" #include "bambu_networking.hpp"
#include <slic3r/GUI/DeviceManager.hpp>
// why: these extend the BAMBU_NETWORK_* return space rather than opening a new one - the value // why: these extend the BAMBU_NETWORK_* return space rather than opening a new one - the value
// flows through the same int domain callers already compare against BAMBU_NETWORK_SUCCESS. // flows through the same int domain callers already compare against BAMBU_NETWORK_SUCCESS.
// They live here and not in bambu_networking.hpp because that file is a vendor header replaced // They live here and not in bambu_networking.hpp because that file is a vendor header replaced
@@ -9,8 +10,14 @@
// -70xx is free: the vendor occupies -1..-25 and -10xx through -60xx. // -70xx is free: the vendor occupies -1..-25 and -10xx through -60xx.
#define ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED -7010 // no translation exists for this command #define ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED -7010 // no translation exists for this command
#define ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE -7020 // a translation exists; this printer lacks the capability #define ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE -7020 // a translation exists; this printer lacks the capability
#define ORCA_NETWORK_ERR_ACCESS_VERIFICATION_FAILED -7030 // printer access preflight failed before printing
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector>
#include <functional>
#include <cstdint>
#include "NetworkAgent.hpp"
namespace Slic3r { namespace Slic3r {
@@ -43,6 +50,77 @@ enum class FilamentSyncMode {
pull ///< On-demand fetch via REST API (blocking call) pull ///< On-demand fetch via REST API (blocking call)
}; };
class IFileTransferTunnel
{
public:
using ConnectionCb = std::function<void(bool is_success, int err_code, std::string error_msg)>;
using TunnelStatusCb = std::function<void(int old_status, int new_status, int err_code, std::string error_msg)>;
explicit IFileTransferTunnel(const std::string& url) : url_(url) {}
virtual ~IFileTransferTunnel() = default;
IFileTransferTunnel(const IFileTransferTunnel&) = delete;
IFileTransferTunnel& operator=(const IFileTransferTunnel&) = delete;
IFileTransferTunnel(IFileTransferTunnel&&) = delete;
IFileTransferTunnel& operator=(IFileTransferTunnel&&) = delete;
virtual void start_connect() = 0;
virtual bool sync_start_connect() = 0;
virtual void on_connection(ConnectionCb cb) { conn_cb_ = std::move(cb); }
virtual void on_status(TunnelStatusCb cb) { status_cb_ = std::move(cb); }
virtual void shutdown() = 0;
virtual int get_status() const { return status_; }
virtual bool check_valid() const = 0;
// why: IFileTransferJob::start_on() only ever sees a tunnel through this interface,
// but needs the concrete backend handle to hand to its own start-job call - native()
// is the type-erased escape hatch, same pattern IFileTransferJob::native() already uses.
virtual void *native() const noexcept { return nullptr; }
protected:
std::string url_;
int status_{};
ConnectionCb conn_cb_{};
TunnelStatusCb status_cb_{};
};
class IFileTransferJob {
public:
using ResultCb = std::function<void(int res, int resp_ec, std::string json_res, std::vector<std::byte> bin_res)>;
using MsgCb = std::function<void(int kind, std::string json)>;
explicit IFileTransferJob(const std::string &params_json) : params_json_(params_json) {}
virtual ~IFileTransferJob() = default;
IFileTransferJob(const IFileTransferJob &) = delete;
IFileTransferJob &operator=(const IFileTransferJob &) = delete;
IFileTransferJob(IFileTransferJob &&) = delete;
IFileTransferJob &operator=(IFileTransferJob &&) = delete;
virtual void on_result(ResultCb cb) { result_cb_ = std::move(cb); }
virtual bool get_result(int &ec, int &resp_ec, std::string &json, std::vector<std::byte> &bin, uint32_t timeout_ms) = 0;
virtual void start_on(IFileTransferTunnel &t) = 0;
virtual void on_msg(MsgCb cb) { msg_cb_ = std::move(cb); }
virtual bool try_get_msg(int &kind, std::string &json) = 0;
virtual bool get_msg(uint32_t timeout_ms, int &kind, std::string &json) = 0;
virtual void *native() const noexcept { return nullptr; }
virtual bool check_valid() const = 0;
virtual bool finished() const { return finished_; }
virtual void cancel() = 0;
protected:
std::string params_json_;
ResultCb result_cb_{};
MsgCb msg_cb_{};
bool finished_ = false;
int res_ = 0;
int resp_ec_ = 0;
std::string res_json_;
std::vector<std::byte> res_bin_;
};
/** /**
* IPrinterAgent - Interface for printer operations. * IPrinterAgent - Interface for printer operations.
* *
@@ -111,8 +189,16 @@ public:
* Build a ready-to-use local (LAN) camera stream URL for this agent's protocol. * Build a ready-to-use local (LAN) camera stream URL for this agent's protocol.
* Returns an empty string if the agent has no local camera stream support. * Returns an empty string if the agent has no local camera stream support.
*/ */
virtual std::string get_local_camera_url(std::string dev_ip, std::string username, std::string password) virtual std::string get_local_camera_url(CameraURLParams params) { return ""; }
{ return {}; }
/**
* Build a ready-to-use local (LAN) file transfer URL for this agent's protocol.
* Returns an empty string if the agent has no local file transfer support.
*/
virtual std::string get_local_file_transfer_url(const FileTransferURLParams& params) { return ""; }
virtual int get_file_transfer_url(std::string, std::function<void(FileTransferURLResult)>, FileTransferURLParams)
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
/** /**
* Default LAN account username for this agent's protocol, if it has a fixed one. * Default LAN account username for this agent's protocol, if it has a fixed one.
@@ -326,6 +412,33 @@ public:
* Populates the MachineObject's DevFilaSystem with fetched filament data. * Populates the MachineObject's DevFilaSystem with fetched filament data.
*/ */
virtual bool fetch_filament_info(std::string dev_id) { return false; } virtual bool fetch_filament_info(std::string dev_id) { return false; }
/**
* Build a local eMMC transfer tunnel for this agent's protocol, if it has one.
* Returns nullptr if the agent has no local file-transfer tunnel concept
* (matches the inert-default pattern used by get_local_camera_url() etc. above -
* this stays non-pure so adding it doesn't force every IPrinterAgent implementation,
* including the Python plugin capability bridge, to override a Bambu-only concept).
*/
virtual std::unique_ptr<IFileTransferTunnel> create_file_transfer_tunnel(std::string& dev_ip, std::string& access_code)
{ return nullptr; }
/**
* Wrap an already-resolved transfer URL (e.g. a cloud-relay/TUTK URL obtained via
* a camera-url lookup) in a local transfer tunnel. Same inert-default reasoning as
* create_file_transfer_tunnel() above; use that one instead when building a tunnel
* straight from dev_ip/access_code.
*/
virtual std::unique_ptr<IFileTransferTunnel> create_file_transfer_tunnel_from_url(std::string url)
{ return nullptr; }
/**
* Build a file-transfer job (media-ability query, upload, ...) to run on a tunnel
* from create_file_transfer_tunnel()/create_file_transfer_tunnel_from_url(). Same
* inert-default reasoning as the tunnel factories above.
*/
virtual std::unique_ptr<IFileTransferJob> create_file_transfer_job(std::string params_json)
{ return nullptr; }
}; };
} // namespace Slic3r } // namespace Slic3r
+21 -4
View File
@@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include "IPrinterAgent.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "NetworkAgent.hpp" #include "NetworkAgent.hpp"
#include "BBLNetworkPlugin.hpp" #include "BBLNetworkPlugin.hpp"
@@ -507,11 +508,12 @@ int NetworkAgent::modify_printer_name(std::string dev_id, std::string dev_name,
return -1; return -1;
} }
int NetworkAgent::get_camera_url(std::string dev_id, std::function<void(std::string)> callback, const std::string& provider) int NetworkAgent::get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback,
const std::string& provider, CameraURLParams params)
{ {
const auto cloud_agent = get_cloud_agent(provider); const auto cloud_agent = get_cloud_agent(provider);
if (cloud_agent) if (cloud_agent)
return cloud_agent->get_camera_url(std::move(dev_id), std::move(callback)); return cloud_agent->get_camera_url(std::move(dev_id), std::move(callback), std::move(params));
return -1; return -1;
} }
@@ -852,13 +854,28 @@ int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_s
return -1; return -1;
} }
std::string NetworkAgent::get_local_camera_url(std::string dev_ip, std::string username, std::string password) std::string NetworkAgent::get_local_camera_url(CameraURLParams params)
{ {
if (m_printer_agent) if (m_printer_agent)
return m_printer_agent->get_local_camera_url(dev_ip, username, password); return m_printer_agent->get_local_camera_url(params);
return {}; return {};
} }
std::string NetworkAgent::get_local_file_transfer_url(const FileTransferURLParams& params)
{
if (m_printer_agent)
return m_printer_agent->get_local_file_transfer_url(params);
return {};
}
int NetworkAgent::get_file_transfer_url(std::string dev_id, std::function<void(FileTransferURLResult)> callback,
FileTransferURLParams params)
{
if (m_printer_agent)
return m_printer_agent->get_file_transfer_url(std::move(dev_id), std::move(callback), std::move(params));
return -1;
}
std::string NetworkAgent::default_lan_username() const std::string NetworkAgent::default_lan_username() const
{ {
if (m_printer_agent) if (m_printer_agent)
+56 -3
View File
@@ -2,9 +2,11 @@
#define __NETWORK_Agent_HPP__ #define __NETWORK_Agent_HPP__
#include "bambu_networking.hpp" #include "bambu_networking.hpp"
#include "libslic3r/ProjectTask.hpp" #include "libslic3r/ProjectTask.hpp"
#include "ICloudServiceAgent.hpp" #include "ICloudServiceAgent.hpp"
#include "IPrinterAgent.hpp" #include "slic3r/GUI/DeviceManager.hpp"
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -12,6 +14,53 @@
namespace Slic3r { namespace Slic3r {
class IPrinterAgent;
enum class FilamentSyncMode;
enum URL_STATE {
URL_TCP,
URL_TUTK,
};
struct CameraURLParams {
std::string ip_address;
std::string user;
std::string password;
LiveviewLocal protocol;
std::string device;
std::string network_version;
std::string device_version;
std::string refresh_url;
std::string client_id;
std::string client_version;
bool apply_meta{false};
};
struct FileTransferURLParams {
URL_STATE url_state{URL_TCP};
std::string ip_address;
std::string username;
std::string password;
std::string device_id;
std::string network_version;
std::string device_version;
std::string refresh_url;
std::string client_id;
std::string client_version;
};
struct FileTransferURLResult {
bool is_success{false};
std::string url;
int error_code{-1};
};
struct CameraURLResult {
bool is_success{false};
std::string url;
int error_code{-1};
};
// Forward declaration // Forward declaration
class BBLNetworkPlugin; class BBLNetworkPlugin;
@@ -108,7 +157,8 @@ public:
int get_slice_info(std::string project_id, std::string profile_id, int plate_index, std::string* slice_json, const std::string& provider = ORCA_CLOUD_PROVIDER); int get_slice_info(std::string project_id, std::string profile_id, int plate_index, std::string* slice_json, const std::string& provider = ORCA_CLOUD_PROVIDER);
int query_bind_status(std::vector<std::string> query_list, unsigned int* http_code, std::string* http_body, const std::string& provider = ORCA_CLOUD_PROVIDER); int query_bind_status(std::vector<std::string> query_list, unsigned int* http_code, std::string* http_body, const std::string& provider = ORCA_CLOUD_PROVIDER);
int modify_printer_name(std::string dev_id, std::string dev_name, const std::string& provider = ORCA_CLOUD_PROVIDER); int modify_printer_name(std::string dev_id, std::string dev_name, const std::string& provider = ORCA_CLOUD_PROVIDER);
int get_camera_url(std::string dev_id, std::function<void(std::string)> callback, const std::string& provider = ORCA_CLOUD_PROVIDER); int get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback,
const std::string& provider = ORCA_CLOUD_PROVIDER, CameraURLParams params = {});
int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback, const std::string& provider = ORCA_CLOUD_PROVIDER); int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback, const std::string& provider = ORCA_CLOUD_PROVIDER);
int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out, const std::string& provider = ORCA_CLOUD_PROVIDER); int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out, const std::string& provider = ORCA_CLOUD_PROVIDER);
int get_model_publish_url(std::string* url, const std::string& provider = ORCA_CLOUD_PROVIDER); int get_model_publish_url(std::string* url, const std::string& provider = ORCA_CLOUD_PROVIDER);
@@ -155,7 +205,10 @@ public:
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl);
int disconnect_printer(); int disconnect_printer();
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag); int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag);
std::string get_local_camera_url(std::string dev_ip, std::string username, std::string password); std::string get_local_camera_url(CameraURLParams params);
std::string get_local_file_transfer_url(const FileTransferURLParams& params);
int get_file_transfer_url(std::string dev_id, std::function<void(FileTransferURLResult)> callback,
FileTransferURLParams params = {});
std::string default_lan_username() const; std::string default_lan_username() const;
int check_cert(); int check_cert();
void install_device_cert(std::string dev_id, bool lan_only); void install_device_cert(std::string dev_id, bool lan_only);
+4 -2
View File
@@ -1,4 +1,5 @@
#include "OrcaCloudServiceAgent.hpp" #include "OrcaCloudServiceAgent.hpp"
#include "NetworkAgent.hpp"
#include "Http.hpp" #include "Http.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
@@ -2698,11 +2699,12 @@ int OrcaCloudServiceAgent::modify_printer_name(std::string dev_id, std::string d
return BAMBU_NETWORK_SUCCESS; return BAMBU_NETWORK_SUCCESS;
} }
int OrcaCloudServiceAgent::get_camera_url(std::string dev_id, std::function<void(std::string)> callback) int OrcaCloudServiceAgent::get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback, CameraURLParams params)
{ {
(void) params;
BOOST_LOG_TRIVIAL(debug) << "OrcaCloudServiceAgent: get_camera_url (stub)"; BOOST_LOG_TRIVIAL(debug) << "OrcaCloudServiceAgent: get_camera_url (stub)";
if (callback) if (callback)
callback(""); callback({});
return BAMBU_NETWORK_SUCCESS; return BAMBU_NETWORK_SUCCESS;
} }
+1 -1
View File
@@ -240,7 +240,7 @@ public:
// ======================================================================== // ========================================================================
// ICloudServiceAgent Interface Implementation - Model Mall & Publishing // ICloudServiceAgent Interface Implementation - Model Mall & Publishing
// ======================================================================== // ========================================================================
int get_camera_url(std::string dev_id, std::function<void(std::string)> callback) override; int get_camera_url(std::string dev_id, std::function<void(CameraURLResult)> callback, CameraURLParams params) override;
int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback) override; int get_design_staffpick(int offset, int limit, std::function<void(std::string)> callback) override;
int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out) override; int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out) override;
int get_model_publish_url(std::string* url) override; int get_model_publish_url(std::string* url) override;