diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index 0601b96949..6b460ce01d 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -466,9 +466,18 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) m_waiting_support = false; NetworkAgent *agent = wxGetApp().getAgent(); 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, agent->default_lan_username(), m_lan_passwd, LVL_None, - m_machine, agent->get_version(), m_dev_ver, "", wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION}); - fs->SetUrl(url); + agent->get_file_transfer_url( + m_machine, + [this, wfs](FileTransferURLResult result) { + CallAfter([this, wfs, result = std::move(result)] { + auto fs = wfs.lock(); + if (!fs || fs != m_image_grid->GetFileSystem()) + return; + fs->SetUrl(result.is_success ? result.url : std::to_string(result.error_code)); + }); + }, + {URL_TCP, m_lan_ip, agent->default_lan_username(), m_lan_passwd, + m_machine, agent->get_version(), m_dev_ver, "", wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION}); return; } if (!m_remote_proto && m_local_proto) { // not support tutk @@ -487,11 +496,11 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) return; } if (agent) { - std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; - agent->get_camera_url(m_machine + "|" + m_dev_ver + "|" + protocols[m_remote_proto], - [this, wfs, m = m_machine](CameraURLResult result) { + agent->get_file_transfer_url( + m_machine, + [this, wfs, m = m_machine](FileTransferURLResult result) { std::string url = std::move(result.url); - BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); + BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: file_system_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); CallAfter([=] { boost::shared_ptr fs(wfs.lock()); if (!fs || fs != m_image_grid->GetFileSystem()) return; @@ -503,8 +512,9 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) fs->SetUrl(res); } }); - }, wxGetApp().get_printer_cloud_provider(), CameraURLParams{"", "", "", LVL_None, m_machine, agent->get_version(), m_dev_ver, - boost::lexical_cast(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true}); + }, + {URL_TUTK, "", "", "", m_machine, agent->get_version(), m_dev_ver, + boost::lexical_cast(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION}); } } diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index 10620dbabf..80167850e6 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -845,11 +845,8 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) m_task_timer.reset(); } - if (m_filetransfer_uploadfile_job) { - m_filetransfer_uploadfile_job->cancel(); - m_filetransfer_uploadfile_job.reset(); - m_filetransfer_uploadfile_job = nullptr; - } + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); m_is_canceled = true; wxCommandEvent* event = new wxCommandEvent(EVT_PRINT_JOB_CANCEL); @@ -868,16 +865,16 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) if (wxGetApp().plater()->using_exported_file()) { m_plater->set_print_job_plate_idx(m_print_plate_idx); result = 0; + } else { + result = m_plater->send_gcode(m_print_plate_idx, [this](int export_stage, int current, int total, bool& cancel) { + if (this->m_is_canceled) + return; + bool cancelled = false; + wxString msg = _L("Preparing print job"); + m_status_bar->update_status(msg, cancelled, 10, true); + m_export_3mf_cancel = cancel = cancelled; + }); } - else { - result = m_plater->send_gcode(m_print_plate_idx, [this](int export_stage, int current, int total, bool &cancel) { - if (this->m_is_canceled) return; - bool cancelled = false; - wxString msg = _L("Preparing print job"); - m_status_bar->update_status(msg, cancelled, 10, true); - m_export_3mf_cancel = cancel = cancelled; - }); - } if (m_is_canceled || m_export_3mf_cancel) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": send progress 10"; @@ -941,7 +938,8 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) this->Bind(wxEVT_TIMER, [this](auto e){ show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); - m_filetransfer_uploadfile_job->cancel(); + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); update_print_status_msg(_L("Upload file timeout, please check if the firmware version supports it."), false, true); },m_task_timer->GetId()); m_task_timer->StartOnce(timeout_period); @@ -1297,10 +1295,8 @@ void SendToPrinterDialog::update_show_status() else m_if_has_sdcard = true; - if (m_filetransfer_tunnel) { - m_filetransfer_tunnel.reset(); - m_filetransfer_tunnel = nullptr; - } + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); GetConnection(); } @@ -1659,7 +1655,6 @@ bool SendToPrinterDialog::Show(bool show) return DPIDialog::Show(show); } -extern wxString hide_passwd(wxString url, std::vector const &passwords); extern void refresh_agora_url(char const *device, char const *dev_ver, char const *channel, void *context, void (*callback)(void *context, char const *url)); void SendToPrinterDialog::GetConnection() @@ -1670,126 +1665,71 @@ void SendToPrinterDialog::GetConnection() if (obj == nullptr) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : obj is empty"; m_connection_status = ConnectionStatus::NOT_START; + return; } int remote_proto = obj->get_file_remote(); if (!remote_proto) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : remote_proto is not support"; m_connection_status = ConnectionStatus::NOT_START; + return; } if (obj->is_camera_busy_off()) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : camera is busy"; m_connection_status = ConnectionStatus::NOT_START; + return; } - NetworkAgent *agent = wxGetApp().getAgent(); - std::string agent_version = agent ? agent->get_version() : ""; - std::string dev_ver = obj->get_ota_version(); - std::string dev_id = obj->get_dev_id(); - - if (m_url_timer && m_url_timer->IsRunning()) - { - m_url_timer->Stop(); - } - - m_url_timer.reset(new wxTimer()); - m_url_timer->SetOwner(this); - this->Bind( - wxEVT_TIMER, - [this](wxTimerEvent &e) { - BOOST_LOG_TRIVIAL(info) << "Timer callback triggered!"; - m_connection_status = ConnectionStatus::CONNECTION_FAILED; - m_ftp_try_connect = true; - if (m_filetransfer_tunnel) - { - m_filetransfer_tunnel.reset(); - m_filetransfer_tunnel = nullptr; - } - - }, - m_url_timer->GetId()); - m_url_timer->StartOnce(8000); - - if (agent) { - if (m_tcp_try_connect) { - std::string devIP = obj->get_dev_ip(); - std::string accessCode = obj->get_access_code(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tcp"; - - 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) { - CallAfter([this, is_success, err_code, error_msg]() { - OnConnection(is_success, err_code, error_msg); - }); - }); - m_filetransfer_tunnel->start_connect(); - } else { - show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, - _L("The selected printer does not support file transfer.")); - } - } else { - show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, - _L("The selected printer does not support file transfer.")); - } - } - else if (m_tutk_try_connect) - { - std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""}; - agent->get_camera_url( - obj->get_dev_id() + "|" + dev_ver + "|" + protocols[1], - [this, pa = agent->get_printer_agent()](CameraURLResult result) { - std::string url = std::move(result.url); - if (m_url_timer && m_url_timer->IsRunning()) { - m_url_timer->Stop(); - } - -#if !BBL_RELEASE_TO_PUBLIC - BOOST_LOG_TRIVIAL(info) << "SendToPrinter::camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="}); -#endif - - if (result.is_success) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": Connect method tutk"; - if (!pa) { - show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, - _L("The selected printer does not support file transfer.")); - return; - } - - try { - m_filetransfer_tunnel = pa->create_file_transfer_tunnel_from_url(url); - } catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create TUTK file-transfer tunnel: " << e.what(); - } - if (!m_filetransfer_tunnel || !m_filetransfer_tunnel->check_valid()) { - show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, - _L("The selected printer does not support file transfer.")); - return; - } - - m_filetransfer_tunnel->on_connection([this](bool is_success, int err_code, std::string error_msg) { - CallAfter([this, is_success, err_code, error_msg]() { OnConnection(is_success, err_code, error_msg); }); - }); - m_filetransfer_tunnel->start_connect(); - } else { - std::string res = result.error_code >= 0 ? std::to_string(result.error_code) : ""; - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " : Tutk url error: ress = " << res; - show_file_transfer_error(PrintDialogStatus::PrintStatusPublicInitFailed, - _L("Connection failed. Please check your network and try again.")); - } - }, - wxGetApp().get_printer_cloud_provider(), - CameraURLParams{"", "", "", LVL_None, dev_id, agent->get_version(), dev_ver, - boost::lexical_cast(&refresh_agora_url), wxGetApp().app_config->get("slicer_uuid"), SLIC3R_VERSION, true}); - } + NetworkAgent *agent = wxGetApp().getAgent(); + if (!agent || !agent->get_printer_agent()) { + show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, + _L("The selected printer does not support file transfer.")); + return; } + + if (m_url_timer && m_url_timer->IsRunning()) { + m_url_timer->Stop(); + } + + m_url_timer.reset(new wxTimer()); + m_url_timer->SetOwner(this); + this->Bind( + wxEVT_TIMER, + [this](wxTimerEvent& e) { + BOOST_LOG_TRIVIAL(info) << "Timer callback triggered!"; + m_connection_status = ConnectionStatus::CONNECTION_FAILED; + m_ftp_try_connect = true; + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); + }, + m_url_timer->GetId()); + m_url_timer->StartOnce(8000); + + IPrinterAgent::FileTransferRequest request; + request.device_id = obj->get_dev_id(); + request.device_ip = obj->get_dev_ip(); + request.access_code = obj->get_access_code(); + request.network_version = agent->get_version(); + request.device_version = obj->get_ota_version(); + request.refresh_url = boost::lexical_cast(&refresh_agora_url); + request.client_id = wxGetApp().app_config->get("slicer_uuid"); + request.client_version = SLIC3R_VERSION; + request.lan_mode = obj->connection_type() == "lan"; + + IPrinterAgent::FileTransferCallbacks callbacks; + callbacks.on_connection = [this](bool is_success, int error_code, std::string error_msg) { + CallAfter([this, is_success, error_code, error_msg = std::move(error_msg)] { + OnConnection(is_success, error_code, std::move(error_msg)); + }); + }; + callbacks.file_transfer_error = [this] { + CallAfter([this] { + show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, + _L("The selected printer does not support file transfer.")); + }); + }; + agent->get_printer_agent()->prepare_file_transfer(request, std::move(callbacks)); } void SendToPrinterDialog::show_file_transfer_error(PrintDialogStatus status, wxString message) @@ -1813,41 +1753,11 @@ void SendToPrinterDialog::OnConnection(bool is_success, int error_code, std::str { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Connect failed, error_code is:" << error_code << "error_msg is :" << error_msg; m_connection_status = ConnectionStatus::CONNECTION_FAILED; - ChangeConnectMethod(); - if (!m_tcp_try_connect && !m_tutk_try_connect) { - show_status(PrintDialogStatus::PrintStatusPublicInitFailed); - return; - } - m_filetransfer_tunnel.reset(); - m_filetransfer_tunnel = nullptr; - GetConnection(); - } -} - -void SendToPrinterDialog::ChangeConnectMethod() -{ - DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return; - MachineObject *obj = dev->get_my_machine(m_printer_last_select); - if (!obj) return; - - bool is_lan = (obj->connection_type() == "lan"); - - m_tcp_try_connect = false; - - if (is_lan) { - m_ftp_try_connect = true; + m_tcp_try_connect = false; m_tutk_try_connect = false; - } else { - if (m_connect_try_times == 0) { - m_ftp_try_connect = false; - m_tutk_try_connect = true; - } else { - m_ftp_try_connect = true; - m_tutk_try_connect = false; - } + m_ftp_try_connect = true; + show_status(PrintDialogStatus::PrintStatusPublicInitFailed); } - m_connect_try_times++; } void SendToPrinterDialog::ResetConnectMethod() @@ -1861,48 +1771,21 @@ void SendToPrinterDialog::ResetConnectMethod() void SendToPrinterDialog::ResetTunnelAndJob() { - if (m_filetransfer_uploadfile_job) - { - m_filetransfer_uploadfile_job->cancel(); - m_filetransfer_uploadfile_job.reset(); - m_filetransfer_uploadfile_job = nullptr; - } - if (m_filetransfer_mediability_job) - { - m_filetransfer_mediability_job->cancel(); - m_filetransfer_mediability_job.reset(); - m_filetransfer_mediability_job = nullptr; - } - if (m_filetransfer_tunnel) - { - m_filetransfer_tunnel.reset(); - m_filetransfer_tunnel = nullptr; - } + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); } 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}}; - 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 bin_res) { - //this pl - CallAfter([this, res, resp_ec, json_res] { + NetworkAgent *agent = wxGetApp().getAgent(); + if (!agent || !agent->get_printer_agent()) { + show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, + _L("The selected printer does not support file transfer.")); + return; + } + IPrinterAgent::FileTransferCallbacks callbacks; + callbacks.on_destinations = [this](int res, int resp_ec, std::string json_res) { + CallAfter([this, res, resp_ec, json_res = std::move(json_res)] { if (res == 0) // 0 is success { show_status(PrintDialogStatus::PrintStatusReadingFinished); @@ -1938,78 +1821,41 @@ void SendToPrinterDialog::CreateMediaAbilityJob() show_status(PrintDialogStatus::PrintStatusPublicInitFailed); update_print_status_msg(ParseErrorCode(resp_ec), false, true); } - }); - }); - // Guard against a null transfer tunnel before dereferencing. - if (m_filetransfer_tunnel && m_filetransfer_tunnel->check_valid()) { - m_filetransfer_mediability_job->start_on(*m_filetransfer_tunnel); - } else { + }); + }; + callbacks.file_transfer_error = [this] { + CallAfter([this] { show_file_transfer_error(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard, _L("The selected printer does not support file transfer.")); - } + }); + }; + agent->get_printer_agent()->get_file_destinations(std::move(callbacks)); } void SendToPrinterDialog::CreateUploadFileJob(const std::string &path, const std::string &name) { - nlohmann::json upload_params = { - {"cmd_type", 5}, - }; - upload_params["dest_storage"] = m_selected_storage; - upload_params["dest_name"] = name; // filenme no 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"; - 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 bin_res) { // - CallAfter([this, res, resp_ec, json_res, bin_res] { - UploadFileRessultCallback(res, resp_ec,json_res, bin_res); + IPrinterAgent::FileTransferCallbacks callbacks; + callbacks.on_progress = [this](int progress) { + CallAfter([this, progress] { UploadFileProgressCallback(progress); }); + }; + callbacks.on_result = [this](int res, int resp_ec, std::string json_res, std::vector bin_res) { + CallAfter([this, res, resp_ec, json_res = std::move(json_res), bin_res = std::move(bin_res)] { + UploadFileRessultCallback(res, resp_ec, std::move(json_res), std::move(bin_res)); }); - }); - - m_filetransfer_uploadfile_job->on_msg([this](int kind, std::string json_res) { - CallAfter([this, kind, json_res] { - if (kind == 0) { - try - { - auto js = nlohmann::json::parse(json_res); - int progress = js["progress"].get(); - UploadFileProgressCallback(progress); - } - catch (const nlohmann::json::exception& e) - { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << e.what(); - } - catch (...) - { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": " << "parse_json failed! "; - } - } + }; + callbacks.file_transfer_error = [this] { + CallAfter([this] { + show_file_transfer_error(PrintDialogStatus::PrintStatusPublicUploadFiled, + _L("The selected printer does not support file transfer.")); }); - }); - // Guard against a null transfer tunnel before dereferencing. - if (m_filetransfer_tunnel && m_filetransfer_tunnel->check_valid()) { - m_filetransfer_uploadfile_job->start_on(*m_filetransfer_tunnel); - } else { - show_file_transfer_error(PrintDialogStatus::PrintStatusPublicUploadFiled, - _L("The selected printer does not support file transfer.")); - } + }; + agent->get_printer_agent()->upload_file(path, name, m_selected_storage, std::move(callbacks)); } void SendToPrinterDialog::UploadFileProgressCallback(int progress) @@ -2028,6 +1874,8 @@ void SendToPrinterDialog::UploadFileProgressCallback(int progress) wxEVT_TIMER, [this](auto e) { show_status(PrintDialogStatus::PrintStatusPublicUploadFiled); + if (auto agent = wxGetApp().getAgent(); agent && agent->get_printer_agent()) + agent->get_printer_agent()->cancel_file_transfer(); update_print_status_msg( _L("File upload timed out. Please check if the firmware version supports this operation or verify if the printer is functioning properly."), false, true); }, @@ -2056,8 +1904,6 @@ void SendToPrinterDialog::UploadFileRessultCallback(int res, int resp_ec, std::s update_print_status_msg(ParseErrorCode(resp_ec), false, true); else update_print_status_msg(_L("Sending failed, please try again!"), false, true); - m_filetransfer_uploadfile_job.reset(); - m_filetransfer_uploadfile_job = nullptr; } } diff --git a/src/slic3r/GUI/SendToPrinter.hpp b/src/slic3r/GUI/SendToPrinter.hpp index 717910ae61..2d0073ce59 100644 --- a/src/slic3r/GUI/SendToPrinter.hpp +++ b/src/slic3r/GUI/SendToPrinter.hpp @@ -170,9 +170,6 @@ private: enum ConnectionStatus { NOT_START, CONNECTING, CONNECTED, CONNECTION_FAILED, DISCONNECTED }; ConnectionStatus m_connection_status{ConnectionStatus::NOT_START}; - std::unique_ptr m_filetransfer_tunnel; - std::unique_ptr m_filetransfer_mediability_job; - std::unique_ptr m_filetransfer_uploadfile_job; wxDateTime m_last_refresh_time; public: @@ -226,7 +223,6 @@ private: void OnConnection(bool is_success, int error_code, std::string error_msg); void CreateMediaAbilityJob(); void CreateUploadFileJob(const std::string &path, const std::string &name); - void ChangeConnectMethod(); void UploadFileProgressCallback(int progress); void UploadFileRessultCallback(int res, int resp_ec, std::string json_res, std::vector bin_res); void Reset(); diff --git a/src/slic3r/Utils/BBLPrinterAgent.cpp b/src/slic3r/Utils/BBLPrinterAgent.cpp index 9a49d86b8a..3b81a6fbc5 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.cpp +++ b/src/slic3r/Utils/BBLPrinterAgent.cpp @@ -207,6 +207,199 @@ 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(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(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) { + 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(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(std::move(cb)); + m_file_transfer_job->on_result([callbacks](int result, int response_error, std::string json_result, + std::vector 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()); + } 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 cloud) { m_cloud_agent = cloud; @@ -930,17 +1123,4 @@ FilamentSyncMode BBLPrinterAgent::get_filament_sync_mode() const return FilamentSyncMode::subscription; } -std::unique_ptr 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(url); -} - -std::unique_ptr BBLPrinterAgent::create_file_transfer_tunnel_from_url(std::string url) { - return std::make_unique(url); -} - -std::unique_ptr BBLPrinterAgent::create_file_transfer_job(std::string params_json) { - return std::make_unique(params_json); -} - } // namespace Slic3r diff --git a/src/slic3r/Utils/BBLPrinterAgent.hpp b/src/slic3r/Utils/BBLPrinterAgent.hpp index 63d796a806..685f422228 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.hpp +++ b/src/slic3r/Utils/BBLPrinterAgent.hpp @@ -175,9 +175,12 @@ public: int set_queue_on_main_fn(QueueOnMainFn fn) override; FilamentSyncMode get_filament_sync_mode() const override; - std::unique_ptr create_file_transfer_tunnel(std::string& dev_ip, std::string& access_code) override; - std::unique_ptr create_file_transfer_tunnel_from_url(std::string url) override; - std::unique_ptr create_file_transfer_job(std::string params_json) override; + void prepare_file_transfer(const FileTransferRequest& request, FileTransferCallbacks cb) override; + void get_file_destinations(FileTransferCallbacks cb) override; + void upload_file(const std::string& path, const std::string& name, const std::string& destination, + FileTransferCallbacks cb) override; + void cancel_file_transfer() override; + private: int verify_local_print_access(PrintParams params); @@ -186,6 +189,16 @@ private: int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode); std::shared_ptr m_cloud_agent; + std::unique_ptr m_file_transfer_tunnel; + std::unique_ptr m_file_transfer_job; + FileTransferCallbacks m_file_transfer_callbacks; + FileTransferRequest m_file_transfer_request; + bool m_file_transfer_tcp{true}; + int m_file_transfer_try_count{0}; + uint64_t m_file_transfer_generation{0}; + + void start_file_transfer_attempt(uint64_t generation); + void handle_file_transfer_connection(uint64_t generation, bool is_success, int error_code, std::string error_msg); }; } // namespace Slic3r diff --git a/src/slic3r/Utils/IPrinterAgent.hpp b/src/slic3r/Utils/IPrinterAgent.hpp index 3b4a72e00b..51df990cdb 100644 --- a/src/slic3r/Utils/IPrinterAgent.hpp +++ b/src/slic3r/Utils/IPrinterAgent.hpp @@ -425,32 +425,55 @@ public: */ 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 create_file_transfer_tunnel(std::string& dev_ip, std::string& access_code) - { return nullptr; } + struct FileTransferRequest + { + std::string device_id; + std::string device_ip; + std::string access_code; + std::string network_version; + std::string device_version; + std::string refresh_url; + std::string client_id; + std::string client_version; + bool lan_mode{false}; + }; + + struct FileTransferCallbacks + { + std::function on_connection; + std::function on_destinations; + std::function on_progress; + std::function binary_result)> on_result; + std::function file_transfer_error; + }; /** - * 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. + * Prepare the agent's file-transfer session. The transport is agent-owned; + * callers must not need to know whether it is a tunnel, HTTP connection, + * or another protocol. */ - virtual std::unique_ptr create_file_transfer_tunnel_from_url(std::string url) - { return nullptr; } + virtual void prepare_file_transfer(const FileTransferRequest&, FileTransferCallbacks cb) + { + if (cb.file_transfer_error) + cb.file_transfer_error(); + } - /** - * 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 create_file_transfer_job(std::string params_json) - { return nullptr; } + /** Query the destinations available for the prepared transfer session. */ + virtual void get_file_destinations(FileTransferCallbacks cb) + { + if (cb.file_transfer_error) + cb.file_transfer_error(); + } + + /** Upload a file using the prepared transfer session. */ + virtual void upload_file(const std::string&, const std::string&, const std::string&, FileTransferCallbacks cb) + { + if (cb.file_transfer_error) + cb.file_transfer_error(); + } + + /** Cancel the current file-transfer operation and release its resources. */ + virtual void cancel_file_transfer() {} }; } // namespace Slic3r