mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 03:11:47 +00:00
refactor: push bbl workflows to bbl printer agent
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include "libslic3r/Time.hpp"
|
#include "libslic3r/Time.hpp"
|
||||||
|
|
||||||
|
#include "IPrinterAgent.hpp"
|
||||||
|
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,36 +337,26 @@ 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],
|
||||||
|
[this, m = m_machine, token = std::weak_ptr(m_token)](CameraURLResult result) {
|
||||||
|
std::string url = std::move(result.url);
|
||||||
|
const bool success = result.is_success;
|
||||||
|
const int error_code = result.error_code;
|
||||||
if (token.expired()) {
|
if (token.expired()) {
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": token has been expired";
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": token has been expired";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boost::algorithm::starts_with(url, "bambu:///")) {
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url, {"?uid=", "authkey=", "passwd=", "license=", "token="});
|
||||||
url += "&device=" + into_u8(m);
|
CallAfter([this, m, url, success, error_code] {
|
||||||
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) {
|
if (m != m_machine) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for machine: " << m;
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for machine: " << m;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_last_state == MEDIASTATE_INITIALIZING) {
|
if (m_last_state == MEDIASTATE_INITIALIZING) {
|
||||||
if (url.empty() || !boost::algorithm::starts_with(url, "bambu:///")) {
|
if (!success) {
|
||||||
m_failed_code = 3;
|
m_failed_code = error_code >= 0 ? error_code : 3;
|
||||||
if (boost::ends_with(url, "]")) {
|
|
||||||
size_t n = url.find_last_of('[');
|
|
||||||
if (n != std::string::npos)
|
|
||||||
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));
|
Stop(_L("Connection Failed. Please check the network and try again"), from_u8(url));
|
||||||
} else {
|
} else {
|
||||||
m_url = url;
|
m_url = url;
|
||||||
@@ -375,7 +366,10 @@ void MediaPlayCtrl::Play()
|
|||||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state;
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, wxGetApp().get_printer_cloud_provider());
|
},
|
||||||
|
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() {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
if (agent->get_printer_agent()) {
|
||||||
|
try {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) {
|
||||||
CallAfter([this, is_success, err_code, error_msg]() {
|
CallAfter([this, is_success, err_code, error_msg]() {
|
||||||
OnConnection(is_success, err_code, error_msg);
|
OnConnection(is_success, err_code, error_msg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
m_filetransfer_tunnel->start_connect();
|
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);
|
|
||||||
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();
|
m_url_timer->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !BBL_RELEASE_TO_PUBLIC
|
#if !BBL_RELEASE_TO_PUBLIC
|
||||||
BOOST_LOG_TRIVIAL(info) << "SendToPrinter::camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
|
BOOST_LOG_TRIVIAL(info) << "SendToPrinter::camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (result.is_success) {
|
||||||
if (boost::algorithm::starts_with(url, "bambu:///"))
|
|
||||||
{
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tutk";
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tutk";
|
||||||
m_filetransfer_tunnel = std::make_unique<FileTransferTunnel>(module(), url);
|
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) {
|
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); });
|
CallAfter([this, is_success, err_code, error_msg]() { OnConnection(is_success, err_code, error_msg); });
|
||||||
});
|
});
|
||||||
m_filetransfer_tunnel->start_connect();
|
m_filetransfer_tunnel->start_connect();
|
||||||
}
|
} else {
|
||||||
else
|
std::string res = result.error_code >= 0 ? std::to_string(result.error_code) : "";
|
||||||
{
|
|
||||||
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;
|
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."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 ¶ms_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
|
||||||
|
|||||||
@@ -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 ¶ms_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,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)
|
|
||||||
{
|
|
||||||
// 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 ¶ms_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
|
} // namespace Slic3r
|
||||||
@@ -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 ¶ms_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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 ¶ms_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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user