mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 10:21:00 +00:00
revert file transfer abstraction
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#include "BBLPrinterAgent.hpp"
|
||||
#include "BBLNetworkPlugin.hpp"
|
||||
#include "FileTransferUtils.hpp"
|
||||
#include "IPrinterAgent.hpp"
|
||||
#include "NetworkAgentFactory.hpp"
|
||||
#include "NetworkAgent.hpp"
|
||||
@@ -11,395 +10,13 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cmath>
|
||||
#include <slic3r/GUI/DeviceManager.hpp>
|
||||
#include <libslic3r/Utils.hpp>
|
||||
|
||||
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;
|
||||
|
||||
void BBLPrinterAgent::prepare_file_transfer(const FileTransferRequest& request, FileTransferCallbacks cb)
|
||||
{
|
||||
cancel_file_transfer();
|
||||
m_file_transfer_request = request;
|
||||
m_file_transfer_callbacks = std::move(cb);
|
||||
m_file_transfer_tcp = true;
|
||||
m_file_transfer_try_count = 0;
|
||||
start_file_transfer_attempt(++m_file_transfer_generation);
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::start_file_transfer_attempt(uint64_t generation)
|
||||
{
|
||||
FileTransferURLParams params;
|
||||
params.url_state = m_file_transfer_tcp ? URL_TCP : URL_TUTK;
|
||||
params.ip_address = m_file_transfer_request.device_ip;
|
||||
params.username = default_lan_username();
|
||||
params.password = m_file_transfer_request.access_code;
|
||||
params.device_id = m_file_transfer_request.device_id;
|
||||
params.network_version = m_file_transfer_request.network_version;
|
||||
params.device_version = m_file_transfer_request.device_version;
|
||||
params.refresh_url = m_file_transfer_request.refresh_url;
|
||||
params.client_id = m_file_transfer_request.client_id;
|
||||
params.client_version = m_file_transfer_request.client_version;
|
||||
|
||||
auto handle_url = [this, generation](FileTransferURLResult result) {
|
||||
if (generation != m_file_transfer_generation)
|
||||
return;
|
||||
if (!result.is_success) {
|
||||
handle_file_transfer_connection(generation, false, result.error_code, "file-transfer URL unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
m_file_transfer_tunnel = std::make_unique<BBLFileTransferTunnel>(result.url);
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "BBLPrinterAgent: failed to create file-transfer tunnel: " << e.what();
|
||||
m_file_transfer_tunnel.reset();
|
||||
}
|
||||
|
||||
if (!m_file_transfer_tunnel || !m_file_transfer_tunnel->check_valid()) {
|
||||
handle_file_transfer_connection(generation, false, -1, "file-transfer tunnel unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
m_file_transfer_tunnel->on_connection([this, generation](bool is_success, int error_code, std::string error_msg) {
|
||||
handle_file_transfer_connection(generation, is_success, error_code, std::move(error_msg));
|
||||
});
|
||||
m_file_transfer_tunnel->start_connect();
|
||||
};
|
||||
|
||||
if (m_file_transfer_tcp) {
|
||||
get_file_transfer_url(m_file_transfer_request.device_id, std::move(handle_url), params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_cloud_agent) {
|
||||
handle_file_transfer_connection(generation, false, -1, "cloud file-transfer URL unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string protocols = "\"tutk\"";
|
||||
m_cloud_agent->get_camera_url(
|
||||
m_file_transfer_request.device_id + "|" + m_file_transfer_request.device_version + "|" + protocols,
|
||||
[handle_url = std::move(handle_url)](CameraURLResult result) mutable {
|
||||
FileTransferURLResult transfer_result;
|
||||
transfer_result.is_success = result.is_success;
|
||||
transfer_result.url = std::move(result.url);
|
||||
transfer_result.error_code = result.error_code;
|
||||
handle_url(std::move(transfer_result));
|
||||
},
|
||||
CameraURLParams{
|
||||
"", "", "", LVL_None,
|
||||
m_file_transfer_request.device_id,
|
||||
m_file_transfer_request.network_version,
|
||||
m_file_transfer_request.device_version,
|
||||
m_file_transfer_request.refresh_url,
|
||||
m_file_transfer_request.client_id,
|
||||
m_file_transfer_request.client_version,
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::handle_file_transfer_connection(uint64_t generation, bool is_success, int error_code, std::string error_msg)
|
||||
{
|
||||
if (generation != m_file_transfer_generation)
|
||||
return;
|
||||
if (is_success) {
|
||||
if (m_file_transfer_callbacks.on_connection)
|
||||
m_file_transfer_callbacks.on_connection(true, error_code, std::move(error_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
// Preserve the existing dialog fallback order: TCP, then TUTK for cloud
|
||||
// printers, and finally the legacy FTP path handled by SendJob.
|
||||
m_file_transfer_tunnel.reset();
|
||||
if (!m_file_transfer_request.lan_mode && m_file_transfer_tcp && m_file_transfer_try_count == 0) {
|
||||
m_file_transfer_tcp = false;
|
||||
++m_file_transfer_try_count;
|
||||
start_file_transfer_attempt(generation);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_file_transfer_callbacks.on_connection)
|
||||
m_file_transfer_callbacks.on_connection(false, error_code, std::move(error_msg));
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::get_file_destinations(FileTransferCallbacks cb)
|
||||
{
|
||||
if (!m_file_transfer_tunnel || !m_file_transfer_tunnel->check_valid()) {
|
||||
if (cb.file_transfer_error)
|
||||
cb.file_transfer_error();
|
||||
return;
|
||||
}
|
||||
|
||||
nlohmann::json params = {{"cmd_type", 7}};
|
||||
try {
|
||||
m_file_transfer_job = std::make_unique<BBLFileTransferJob>(params.dump());
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "BBLPrinterAgent: failed to create media-ability job: " << e.what();
|
||||
m_file_transfer_job.reset();
|
||||
}
|
||||
|
||||
if (!m_file_transfer_job || !m_file_transfer_job->check_valid()) {
|
||||
if (cb.file_transfer_error)
|
||||
cb.file_transfer_error();
|
||||
return;
|
||||
}
|
||||
|
||||
m_file_transfer_job->on_result([cb = std::move(cb)](int result, int response_error, std::string json_result,
|
||||
std::vector<std::byte>) {
|
||||
if (cb.on_destinations)
|
||||
cb.on_destinations(result, response_error, std::move(json_result));
|
||||
});
|
||||
m_file_transfer_job->start_on(*m_file_transfer_tunnel);
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::upload_file(const std::string& path, const std::string& name, const std::string& destination,
|
||||
FileTransferCallbacks cb)
|
||||
{
|
||||
if (!m_file_transfer_tunnel || !m_file_transfer_tunnel->check_valid()) {
|
||||
if (cb.file_transfer_error)
|
||||
cb.file_transfer_error();
|
||||
return;
|
||||
}
|
||||
|
||||
nlohmann::json params = {
|
||||
{"cmd_type", 5},
|
||||
{"dest_storage", destination},
|
||||
{"dest_name", name},
|
||||
{"file_path", path}
|
||||
};
|
||||
|
||||
try {
|
||||
m_file_transfer_job = std::make_unique<BBLFileTransferJob>(params.dump());
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "BBLPrinterAgent: failed to create upload job: " << e.what();
|
||||
m_file_transfer_job.reset();
|
||||
}
|
||||
|
||||
if (!m_file_transfer_job || !m_file_transfer_job->check_valid()) {
|
||||
if (cb.file_transfer_error)
|
||||
cb.file_transfer_error();
|
||||
return;
|
||||
}
|
||||
|
||||
auto callbacks = std::make_shared<FileTransferCallbacks>(std::move(cb));
|
||||
m_file_transfer_job->on_result([callbacks](int result, int response_error, std::string json_result,
|
||||
std::vector<std::byte> binary_result) {
|
||||
if (callbacks->on_result)
|
||||
callbacks->on_result(result, response_error, std::move(json_result), std::move(binary_result));
|
||||
});
|
||||
m_file_transfer_job->on_msg([callbacks](int kind, std::string json_result) {
|
||||
if (kind == 0 && callbacks->on_progress) {
|
||||
try {
|
||||
callbacks->on_progress(nlohmann::json::parse(json_result).at("progress").get<int>());
|
||||
} catch (...) {
|
||||
BOOST_LOG_TRIVIAL(error) << "BBLPrinterAgent: failed to parse upload progress";
|
||||
}
|
||||
}
|
||||
});
|
||||
m_file_transfer_job->start_on(*m_file_transfer_tunnel);
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::cancel_file_transfer()
|
||||
{
|
||||
++m_file_transfer_generation;
|
||||
if (m_file_transfer_job)
|
||||
m_file_transfer_job->cancel();
|
||||
m_file_transfer_job.reset();
|
||||
m_file_transfer_tunnel.reset();
|
||||
m_file_transfer_callbacks = {};
|
||||
}
|
||||
|
||||
void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
|
||||
{
|
||||
m_cloud_agent = cloud;
|
||||
@@ -702,10 +319,7 @@ int BBLPrinterAgent::get_file_transfer_url(std::string dev_id, std::function<voi
|
||||
callback(std::move(transfer_result));
|
||||
},
|
||||
CameraURLParams{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
LVL_None,
|
||||
"", "", "", LVL_None,
|
||||
params.device_id,
|
||||
params.network_version,
|
||||
params.device_version,
|
||||
@@ -977,15 +591,6 @@ 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);
|
||||
}
|
||||
|
||||
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 result = dispatch_start<func_start_send_gcode_to_sdcard_legacy, func_start_send_gcode_to_sdcard_0203>(
|
||||
@@ -1001,16 +606,6 @@ int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStat
|
||||
|
||||
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>(
|
||||
BBLNetworkPlugin::instance().get_start_local_print(), params, update_fn, cancel_fn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user