mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-11 11:07:40 +00:00
feature add download function for web and pc.
This commit is contained in:
@@ -1,20 +1,75 @@
|
|||||||
#include "WCPDownloadManager.hpp"
|
#include "DownloadManager.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
size_t DownloadManager::start_download(const std::string& file_url,
|
// ============================================================================
|
||||||
const std::string& file_name,
|
// WCP Download Interface (for Web-to-PC communication)
|
||||||
std::shared_ptr<SSWCP_Instance> wcp_instance) {
|
// ============================================================================
|
||||||
|
size_t DownloadManager::start_wcp_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
std::shared_ptr<SSWCP_Instance> wcp_instance,
|
||||||
|
bool use_original_event_id) {
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
|
|
||||||
size_t task_id = m_next_task_id++;
|
size_t task_id = m_next_task_id++;
|
||||||
|
|
||||||
// Get download path
|
auto downloadPath = wxGetApp().app_config->get("download_path");
|
||||||
|
boost::filesystem::path dest_folder(downloadPath);
|
||||||
|
boost::filesystem::create_directories(dest_folder);
|
||||||
|
boost::filesystem::path dest_file = dest_folder / file_name;
|
||||||
|
std::string dest_path = dest_file.string();
|
||||||
|
|
||||||
|
auto task = std::make_shared<DownloadTask>(task_id,
|
||||||
|
file_url,
|
||||||
|
file_name,
|
||||||
|
dest_path,
|
||||||
|
wcp_instance,
|
||||||
|
use_original_event_id);
|
||||||
|
|
||||||
|
task->state = DownloadTaskState::Downloading;
|
||||||
|
|
||||||
|
m_tasks[task_id] = task;
|
||||||
|
start_download_impl(task);
|
||||||
|
return task_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Internal Download Interface (for PC internal use)
|
||||||
|
// ============================================================================
|
||||||
|
size_t DownloadManager::start_internal_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
const std::string& dest_path,
|
||||||
|
DownloadCallbacks callbacks) {
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
|
size_t task_id = m_next_task_id++;
|
||||||
|
|
||||||
|
boost::filesystem::path dest_file_path(dest_path);
|
||||||
|
boost::filesystem::create_directories(dest_file_path.parent_path());
|
||||||
|
|
||||||
|
auto task = std::make_shared<DownloadTask>(task_id,
|
||||||
|
file_url,
|
||||||
|
file_name,
|
||||||
|
dest_path,
|
||||||
|
std::move(callbacks));
|
||||||
|
|
||||||
|
task->state = DownloadTaskState::Downloading;
|
||||||
|
|
||||||
|
m_tasks[task_id] = task;
|
||||||
|
start_download_impl(task);
|
||||||
|
|
||||||
|
return task_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DownloadManager::start_internal_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
DownloadCallbacks callbacks) {
|
||||||
|
// Get default download path
|
||||||
auto downloadPath = wxGetApp().app_config->get("download_path");
|
auto downloadPath = wxGetApp().app_config->get("download_path");
|
||||||
boost::filesystem::path dest_folder(downloadPath);
|
boost::filesystem::path dest_folder(downloadPath);
|
||||||
boost::filesystem::create_directories(dest_folder);
|
boost::filesystem::create_directories(dest_folder);
|
||||||
@@ -22,26 +77,25 @@ size_t DownloadManager::start_download(const std::string& file_url,
|
|||||||
boost::filesystem::path dest_file = dest_folder / file_name;
|
boost::filesystem::path dest_file = dest_folder / file_name;
|
||||||
std::string dest_path = dest_file.string();
|
std::string dest_path = dest_file.string();
|
||||||
|
|
||||||
// Create task
|
return start_internal_download(file_url, file_name, dest_path, std::move(callbacks));
|
||||||
auto task = std::make_shared<DownloadTask>(task_id, file_url, file_name, dest_path, wcp_instance);
|
}
|
||||||
task->state = SMDownloadState::Downloading;
|
|
||||||
|
|
||||||
m_tasks[task_id] = task;
|
void DownloadManager::start_download_impl(std::shared_ptr<DownloadTask> task) {
|
||||||
|
|
||||||
// Start download
|
|
||||||
wxGetApp().CallAfter([this, task]() {
|
wxGetApp().CallAfter([this, task]() {
|
||||||
try {
|
try {
|
||||||
// Step 1: Create Http object
|
// Step 1: Create Http object
|
||||||
Http http = Http::get(task->file_url);
|
Http http = Http::get(task->file_url);
|
||||||
|
|
||||||
|
http.timeout_max(0);
|
||||||
|
|
||||||
// Step 2: Set progress callback
|
// Step 2: Set progress callback
|
||||||
http.on_progress([this, task](Http::Progress progress, bool& cancel) {
|
http.on_progress([this, task](Http::Progress progress, bool& cancel) {
|
||||||
if (task->state == SMDownloadState::Canceled) {
|
if (task->state == DownloadTaskState::Canceled) {
|
||||||
cancel = true;
|
cancel = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate progress
|
|
||||||
int percent = 0;
|
int percent = 0;
|
||||||
if (progress.dltotal > 0) {
|
if (progress.dltotal > 0) {
|
||||||
percent = (int)(progress.dlnow * 100 / progress.dltotal);
|
percent = (int)(progress.dlnow * 100 / progress.dltotal);
|
||||||
@@ -87,7 +141,7 @@ size_t DownloadManager::start_download(const std::string& file_url,
|
|||||||
file.write(body.c_str(), body.size());
|
file.write(body.c_str(), body.size());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
task->state = SMDownloadState::Completed;
|
task->state = DownloadTaskState::Completed;
|
||||||
task->percent = 100;
|
task->percent = 100;
|
||||||
send_complete_update(task, task->dest_path);
|
send_complete_update(task, task->dest_path);
|
||||||
cleanup_task(task->task_id);
|
cleanup_task(task->task_id);
|
||||||
@@ -101,7 +155,7 @@ size_t DownloadManager::start_download(const std::string& file_url,
|
|||||||
// Step 4: Set error callback
|
// Step 4: Set error callback
|
||||||
http.on_error([this, task](std::string body, std::string error, unsigned status) {
|
http.on_error([this, task](std::string body, std::string error, unsigned status) {
|
||||||
wxGetApp().CallAfter([this, task, error, status]() {
|
wxGetApp().CallAfter([this, task, error, status]() {
|
||||||
task->state = SMDownloadState::Error;
|
task->state = DownloadTaskState::Error;
|
||||||
task->error_message = error;
|
task->error_message = error;
|
||||||
send_error_update(task, error);
|
send_error_update(task, error);
|
||||||
cleanup_task(task->task_id);
|
cleanup_task(task->task_id);
|
||||||
@@ -112,16 +166,15 @@ size_t DownloadManager::start_download(const std::string& file_url,
|
|||||||
task->http_object = http.perform();
|
task->http_object = http.perform();
|
||||||
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
task->state = SMDownloadState::Error;
|
task->state = DownloadTaskState::Error;
|
||||||
task->error_message = e.what();
|
task->error_message = e.what();
|
||||||
send_error_update(task, e.what());
|
send_error_update(task, e.what());
|
||||||
cleanup_task(task->task_id);
|
cleanup_task(task->task_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return task_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//this function not currently in use
|
||||||
bool DownloadManager::cancel_download(size_t task_id) {
|
bool DownloadManager::cancel_download(size_t task_id) {
|
||||||
std::shared_ptr<SSWCP_Instance> wcp_to_destroy;
|
std::shared_ptr<SSWCP_Instance> wcp_to_destroy;
|
||||||
|
|
||||||
@@ -134,14 +187,25 @@ bool DownloadManager::cancel_download(size_t task_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto task = it->second;
|
auto task = it->second;
|
||||||
if (task->state == SMDownloadState::Downloading) {
|
if (task->state == DownloadTaskState::Downloading) {
|
||||||
task->state = SMDownloadState::Canceled;
|
task->state = DownloadTaskState::Canceled;
|
||||||
if (task->http_object) {
|
if (task->http_object) {
|
||||||
task->http_object->cancel();
|
task->http_object->cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get WCP instance before cleanup (for destruction after lock release)
|
// Only for WCP downloads
|
||||||
wcp_to_destroy = task->wcp_instance.lock();
|
if (task->is_wcp_download()) {
|
||||||
|
wcp_to_destroy = task->wcp_instance.lock();
|
||||||
|
} else {
|
||||||
|
// For internal downloads, call error callback if available
|
||||||
|
if (task->callbacks.on_error) {
|
||||||
|
wxGetApp().CallAfter([task]() {
|
||||||
|
if (task->callbacks.on_error) {
|
||||||
|
task->callbacks.on_error(task->task_id, "Download canceled");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup_task(task_id);
|
cleanup_task(task_id);
|
||||||
} else {
|
} else {
|
||||||
@@ -149,8 +213,6 @@ bool DownloadManager::cancel_download(size_t task_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy WCP instance outside the lock to prevent deadlock
|
|
||||||
// This is the WCP instance from the original download request (sw_DownloadFile)
|
|
||||||
if (wcp_to_destroy) {
|
if (wcp_to_destroy) {
|
||||||
wcp_to_destroy->finish_job();
|
wcp_to_destroy->finish_job();
|
||||||
}
|
}
|
||||||
@@ -158,40 +220,38 @@ bool DownloadManager::cancel_download(size_t task_id) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function not currently in use
|
||||||
bool DownloadManager::pause_download(size_t task_id) {
|
bool DownloadManager::pause_download(size_t task_id) {
|
||||||
// Pause functionality can be implemented if needed
|
|
||||||
// Current Http module may not support pause, need to implement resume from breakpoint
|
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
auto it = m_tasks.find(task_id);
|
auto it = m_tasks.find(task_id);
|
||||||
if (it != m_tasks.end() && it->second->state == SMDownloadState::Downloading) {
|
if (it != m_tasks.end() && it->second->state == DownloadTaskState::Downloading) {
|
||||||
it->second->state = SMDownloadState::Paused;
|
it->second->state = DownloadTaskState::Paused;
|
||||||
// Note: Http module doesn't support pause directly, would need breakpoint resume
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function not currently in use
|
||||||
bool DownloadManager::resume_download(size_t task_id) {
|
bool DownloadManager::resume_download(size_t task_id) {
|
||||||
// Resume functionality can be implemented if needed
|
|
||||||
// Would require breakpoint resume support in Http module
|
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
auto it = m_tasks.find(task_id);
|
auto it = m_tasks.find(task_id);
|
||||||
if (it != m_tasks.end() && it->second->state == SMDownloadState::Paused) {
|
if (it != m_tasks.end() && it->second->state == DownloadTaskState::Paused) {
|
||||||
// Would need to restart download with range header
|
return false;
|
||||||
return false; // Not implemented yet
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMDownloadState DownloadManager::get_task_state(size_t task_id) {
|
// this function not currently in use
|
||||||
|
DownloadTaskState DownloadManager::get_task_state(size_t task_id) {
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
auto it = m_tasks.find(task_id);
|
auto it = m_tasks.find(task_id);
|
||||||
if (it != m_tasks.end()) {
|
if (it != m_tasks.end()) {
|
||||||
return it->second->state;
|
return it->second->state;
|
||||||
}
|
}
|
||||||
return SMDownloadState::Error;
|
return DownloadTaskState::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function not currently in use
|
||||||
std::shared_ptr<DownloadTask> DownloadManager::get_task(size_t task_id) {
|
std::shared_ptr<DownloadTask> DownloadManager::get_task(size_t task_id) {
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
auto it = m_tasks.find(task_id);
|
auto it = m_tasks.find(task_id);
|
||||||
@@ -201,10 +261,39 @@ std::shared_ptr<DownloadTask> DownloadManager::get_task(size_t task_id) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function not currently in use
|
||||||
|
std::vector<std::shared_ptr<DownloadTask>> DownloadManager::get_all_tasks() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
|
std::vector<std::shared_ptr<DownloadTask>> result;
|
||||||
|
result.reserve(m_tasks.size());
|
||||||
|
for (const auto& pair : m_tasks) {
|
||||||
|
result.push_back(pair.second);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Progress/Complete/Error Update Handlers
|
||||||
|
// ============================================================================
|
||||||
void DownloadManager::send_progress_update(std::shared_ptr<DownloadTask> task,
|
void DownloadManager::send_progress_update(std::shared_ptr<DownloadTask> task,
|
||||||
int percent,
|
int percent,
|
||||||
size_t downloaded,
|
size_t downloaded,
|
||||||
size_t total) {
|
size_t total) {
|
||||||
|
if (task->is_wcp_download()) {
|
||||||
|
send_wcp_progress_update(task, percent, downloaded, total);
|
||||||
|
} else {
|
||||||
|
call_internal_progress_callback(task, percent, downloaded, total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::send_wcp_progress_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
int percent,
|
||||||
|
size_t downloaded,
|
||||||
|
size_t total) {
|
||||||
|
if (!task->use_original_event_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto wcp = task->wcp_instance.lock()) {
|
if (auto wcp = task->wcp_instance.lock()) {
|
||||||
json progress_data;
|
json progress_data;
|
||||||
progress_data["task_id"] = task->task_id;
|
progress_data["task_id"] = task->task_id;
|
||||||
@@ -217,9 +306,13 @@ void DownloadManager::send_progress_update(std::shared_ptr<DownloadTask> task,
|
|||||||
wcp->m_status = 0;
|
wcp->m_status = 0;
|
||||||
wcp->m_msg = "Download progress";
|
wcp->m_msg = "Download progress";
|
||||||
|
|
||||||
// Use progress event ID
|
|
||||||
json header;
|
json header;
|
||||||
header["event_id"] = wcp->m_event_id + "_progress";
|
if (task->use_original_event_id) {
|
||||||
|
header["event_id"] = wcp->m_event_id;
|
||||||
|
} else {
|
||||||
|
header["event_id"] = wcp->m_event_id + "_progress";
|
||||||
|
}
|
||||||
|
|
||||||
header["command"] = "download_progress";
|
header["command"] = "download_progress";
|
||||||
wcp->m_header = header;
|
wcp->m_header = header;
|
||||||
|
|
||||||
@@ -227,8 +320,31 @@ void DownloadManager::send_progress_update(std::shared_ptr<DownloadTask> task,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadManager::call_internal_progress_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
int percent,
|
||||||
|
size_t downloaded,
|
||||||
|
size_t total) {
|
||||||
|
if (task->callbacks.on_progress) {
|
||||||
|
task->callbacks.on_progress(task->task_id, percent, downloaded, total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DownloadManager::send_complete_update(std::shared_ptr<DownloadTask> task,
|
void DownloadManager::send_complete_update(std::shared_ptr<DownloadTask> task,
|
||||||
const std::string& file_path) {
|
const std::string& file_path) {
|
||||||
|
if (task->is_wcp_download()) {
|
||||||
|
send_wcp_complete_update(task, file_path);
|
||||||
|
} else {
|
||||||
|
call_internal_complete_callback(task, file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::send_wcp_complete_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& file_path) {
|
||||||
|
|
||||||
|
if (!task->use_original_event_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto wcp = task->wcp_instance.lock()) {
|
if (auto wcp = task->wcp_instance.lock()) {
|
||||||
json complete_data;
|
json complete_data;
|
||||||
complete_data["task_id"] = task->task_id;
|
complete_data["task_id"] = task->task_id;
|
||||||
@@ -240,15 +356,35 @@ void DownloadManager::send_complete_update(std::shared_ptr<DownloadTask> task,
|
|||||||
wcp->m_res_data = complete_data;
|
wcp->m_res_data = complete_data;
|
||||||
wcp->m_status = 0;
|
wcp->m_status = 0;
|
||||||
wcp->m_msg = "Download completed";
|
wcp->m_msg = "Download completed";
|
||||||
wcp->send_to_js();
|
|
||||||
|
|
||||||
// Release WCP instance to prevent memory leak
|
wcp->send_to_js();
|
||||||
wcp->finish_job();
|
wcp->finish_job();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadManager::call_internal_complete_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& file_path) {
|
||||||
|
if (task->callbacks.on_complete) {
|
||||||
|
task->callbacks.on_complete(task->task_id, file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DownloadManager::send_error_update(std::shared_ptr<DownloadTask> task,
|
void DownloadManager::send_error_update(std::shared_ptr<DownloadTask> task,
|
||||||
const std::string& error) {
|
const std::string& error) {
|
||||||
|
if (task->is_wcp_download()) {
|
||||||
|
send_wcp_error_update(task, error);
|
||||||
|
} else {
|
||||||
|
call_internal_error_callback(task, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::send_wcp_error_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& error) {
|
||||||
|
|
||||||
|
if (!task->use_original_event_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto wcp = task->wcp_instance.lock()) {
|
if (auto wcp = task->wcp_instance.lock()) {
|
||||||
json error_data;
|
json error_data;
|
||||||
error_data["task_id"] = task->task_id;
|
error_data["task_id"] = task->task_id;
|
||||||
@@ -258,13 +394,19 @@ void DownloadManager::send_error_update(std::shared_ptr<DownloadTask> task,
|
|||||||
wcp->m_res_data = error_data;
|
wcp->m_res_data = error_data;
|
||||||
wcp->m_status = -1;
|
wcp->m_status = -1;
|
||||||
wcp->m_msg = error;
|
wcp->m_msg = error;
|
||||||
wcp->send_to_js();
|
|
||||||
|
|
||||||
// Release WCP instance to prevent memory leak
|
wcp->send_to_js();
|
||||||
wcp->finish_job();
|
wcp->finish_job();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadManager::call_internal_error_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& error) {
|
||||||
|
if (task->callbacks.on_error) {
|
||||||
|
task->callbacks.on_error(task->task_id, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DownloadManager::cleanup_task(size_t task_id) {
|
void DownloadManager::cleanup_task(size_t task_id) {
|
||||||
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
std::lock_guard<std::mutex> lock(m_tasks_mutex);
|
||||||
m_tasks.erase(task_id);
|
m_tasks.erase(task_id);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef slic3r_WCPDownloadManager_hpp_
|
#ifndef slic3r_DownloadManager_hpp_
|
||||||
#define slic3r_WCPDownloadManager_hpp_
|
#define slic3r_DownloadManager_hpp_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
#include "../Utils/Http.hpp"
|
#include "../Utils/Http.hpp"
|
||||||
#include "SSWCP.hpp"
|
#include "SSWCP.hpp"
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
@@ -14,8 +15,8 @@
|
|||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
// Download task state
|
// Download task state (renamed to avoid conflict with Downloader::DownloadState)
|
||||||
enum class SMDownloadState {
|
enum class DownloadTaskState {
|
||||||
Pending,
|
Pending,
|
||||||
Downloading,
|
Downloading,
|
||||||
Paused,
|
Paused,
|
||||||
@@ -24,25 +25,66 @@ enum class SMDownloadState {
|
|||||||
Canceled
|
Canceled
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Download callback interface for internal downloads
|
||||||
|
struct DownloadCallbacks {
|
||||||
|
std::function<void(size_t task_id, int percent, size_t downloaded, size_t total)> on_progress;
|
||||||
|
std::function<void(size_t task_id, const std::string& file_path)> on_complete;
|
||||||
|
std::function<void(size_t task_id, const std::string& error)> on_error;
|
||||||
|
|
||||||
|
DownloadCallbacks() = default;
|
||||||
|
DownloadCallbacks(
|
||||||
|
std::function<void(size_t, int, size_t, size_t)> progress,
|
||||||
|
std::function<void(size_t, const std::string&)> complete,
|
||||||
|
std::function<void(size_t, const std::string&)> error)
|
||||||
|
: on_progress(std::move(progress))
|
||||||
|
, on_complete(std::move(complete))
|
||||||
|
, on_error(std::move(error))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
// Download task information
|
// Download task information
|
||||||
struct DownloadTask {
|
struct DownloadTask {
|
||||||
size_t task_id;
|
size_t task_id;
|
||||||
std::string file_url;
|
std::string file_url;
|
||||||
std::string file_name;
|
std::string file_name;
|
||||||
std::string dest_path;
|
std::string dest_path;
|
||||||
std::weak_ptr<SSWCP_Instance> wcp_instance; // Associated WCP instance
|
|
||||||
Http::Ptr http_object; // HTTP object for cancellation
|
std::weak_ptr<SSWCP_Instance> wcp_instance;
|
||||||
SMDownloadState state;
|
|
||||||
|
DownloadCallbacks callbacks;
|
||||||
|
|
||||||
|
Http::Ptr http_object;
|
||||||
|
DownloadTaskState state;
|
||||||
int percent;
|
int percent;
|
||||||
std::string error_message;
|
std::string error_message;
|
||||||
|
|
||||||
|
bool auto_finish_job;
|
||||||
|
bool use_original_event_id;
|
||||||
|
|
||||||
|
// Constructor for WCP downloads
|
||||||
DownloadTask(size_t id, const std::string& url, const std::string& name,
|
DownloadTask(size_t id, const std::string& url, const std::string& name,
|
||||||
const std::string& path, std::shared_ptr<SSWCP_Instance> instance)
|
const std::string& path, std::shared_ptr<SSWCP_Instance> instance,
|
||||||
: task_id(id), file_url(url), file_name(name), dest_path(path), wcp_instance(instance), state(SMDownloadState::Pending), percent(0)
|
bool use_original_event = false)
|
||||||
|
: task_id(id), file_url(url), file_name(name), dest_path(path)
|
||||||
|
, wcp_instance(instance), state(DownloadTaskState::Pending), percent(0)
|
||||||
|
, auto_finish_job(false), use_original_event_id(use_original_event)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Constructor for internal downloads
|
||||||
|
DownloadTask(size_t id, const std::string& url, const std::string& name,
|
||||||
|
const std::string& path, DownloadCallbacks cb)
|
||||||
|
: task_id(id), file_url(url), file_name(name), dest_path(path)
|
||||||
|
, callbacks(std::move(cb)), state(DownloadTaskState::Pending), percent(0)
|
||||||
|
, auto_finish_job(false), use_original_event_id(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Check if this is a WCP download
|
||||||
|
bool is_wcp_download() const {
|
||||||
|
return !wcp_instance.expired();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Download Manager
|
|
||||||
class DownloadManager {
|
class DownloadManager {
|
||||||
public:
|
public:
|
||||||
static DownloadManager& getInstance() {
|
static DownloadManager& getInstance() {
|
||||||
@@ -50,11 +92,29 @@ public:
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a download task
|
// ============================================================================
|
||||||
size_t start_download(const std::string& file_url,
|
// WCP Download Interface (for Web-to-PC communication)
|
||||||
const std::string& file_name,
|
// ============================================================================
|
||||||
std::shared_ptr<SSWCP_Instance> wcp_instance);
|
size_t start_wcp_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
std::shared_ptr<SSWCP_Instance> wcp_instance,
|
||||||
|
bool use_original_event_id = false);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Internal Download Interface (for PC internal use)
|
||||||
|
// ============================================================================
|
||||||
|
size_t start_internal_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
const std::string& dest_path,
|
||||||
|
DownloadCallbacks callbacks);
|
||||||
|
|
||||||
|
size_t start_internal_download(const std::string& file_url,
|
||||||
|
const std::string& file_name,
|
||||||
|
DownloadCallbacks callbacks);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Common Interface (works for both WCP and internal downloads)
|
||||||
|
// ============================================================================
|
||||||
// Cancel a download task
|
// Cancel a download task
|
||||||
bool cancel_download(size_t task_id);
|
bool cancel_download(size_t task_id);
|
||||||
|
|
||||||
@@ -65,11 +125,14 @@ public:
|
|||||||
bool resume_download(size_t task_id);
|
bool resume_download(size_t task_id);
|
||||||
|
|
||||||
// Get task state
|
// Get task state
|
||||||
SMDownloadState get_task_state(size_t task_id);
|
DownloadTaskState get_task_state(size_t task_id);
|
||||||
|
|
||||||
// Get task information
|
// Get task information
|
||||||
std::shared_ptr<DownloadTask> get_task(size_t task_id);
|
std::shared_ptr<DownloadTask> get_task(size_t task_id);
|
||||||
|
|
||||||
|
// Get all active tasks
|
||||||
|
std::vector<std::shared_ptr<DownloadTask>> get_all_tasks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DownloadManager() = default;
|
DownloadManager() = default;
|
||||||
~DownloadManager() = default;
|
~DownloadManager() = default;
|
||||||
@@ -84,15 +147,54 @@ private:
|
|||||||
std::unordered_map<size_t, int> m_last_percent;
|
std::unordered_map<size_t, int> m_last_percent;
|
||||||
std::unordered_map<size_t, std::chrono::steady_clock::time_point> m_last_update;
|
std::unordered_map<size_t, std::chrono::steady_clock::time_point> m_last_update;
|
||||||
|
|
||||||
// Send progress update to WCP
|
// ============================================================================
|
||||||
void send_progress_update(std::shared_ptr<DownloadTask> task, int percent,
|
// Internal Implementation
|
||||||
size_t downloaded, size_t total);
|
// ============================================================================
|
||||||
|
|
||||||
// Send completion message to WCP
|
// Common download implementation (used by both WCP and internal downloads)
|
||||||
void send_complete_update(std::shared_ptr<DownloadTask> task, const std::string& file_path);
|
void start_download_impl(std::shared_ptr<DownloadTask> task);
|
||||||
|
|
||||||
// Send error message to WCP
|
// Send progress update (handles both WCP and internal modes)
|
||||||
void send_error_update(std::shared_ptr<DownloadTask> task, const std::string& error);
|
void send_progress_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
int percent,
|
||||||
|
size_t downloaded,
|
||||||
|
size_t total);
|
||||||
|
|
||||||
|
// Send completion message (handles both WCP and internal modes)
|
||||||
|
void send_complete_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& file_path);
|
||||||
|
|
||||||
|
// Send error message (handles both WCP and internal modes)
|
||||||
|
void send_error_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& error);
|
||||||
|
|
||||||
|
// WCP-specific: Send progress update via WCP instance
|
||||||
|
void send_wcp_progress_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
int percent,
|
||||||
|
size_t downloaded,
|
||||||
|
size_t total);
|
||||||
|
|
||||||
|
// WCP-specific: Send completion via WCP instance
|
||||||
|
void send_wcp_complete_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& file_path);
|
||||||
|
|
||||||
|
// WCP-specific: Send error via WCP instance
|
||||||
|
void send_wcp_error_update(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& error);
|
||||||
|
|
||||||
|
// Internal-specific: Call progress callback
|
||||||
|
void call_internal_progress_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
int percent,
|
||||||
|
size_t downloaded,
|
||||||
|
size_t total);
|
||||||
|
|
||||||
|
// Internal-specific: Call complete callback
|
||||||
|
void call_internal_complete_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& file_path);
|
||||||
|
|
||||||
|
// Internal-specific: Call error callback
|
||||||
|
void call_internal_error_callback(std::shared_ptr<DownloadTask> task,
|
||||||
|
const std::string& error);
|
||||||
|
|
||||||
// Clean up completed task
|
// Clean up completed task
|
||||||
void cleanup_task(size_t task_id);
|
void cleanup_task(size_t task_id);
|
||||||
@@ -100,5 +202,5 @@ private:
|
|||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif // slic3r_WCPDownloadManager_hpp_
|
#endif // slic3r_DownloadManager_hpp_
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "slic3r/GUI/WebPresetDialog.hpp"
|
#include "slic3r/GUI/WebPresetDialog.hpp"
|
||||||
|
|
||||||
#include "slic3r/GUI/SSWCP.hpp"
|
#include "slic3r/GUI/SSWCP.hpp"
|
||||||
#include "slic3r/GUI/WCPDownloadManager.hpp"
|
#include "slic3r/GUI/DownloadManager.hpp"
|
||||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||||
#include "slic3r/Config/Version.hpp"
|
#include "slic3r/Config/Version.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "SSWCP.hpp"
|
#include "SSWCP.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "WCPDownloadManager.hpp"
|
#include "DownloadManager.hpp"
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include "slic3r/GUI/Tab.hpp"
|
#include "slic3r/GUI/Tab.hpp"
|
||||||
#include "sentry_wrapper/SentryWrapper.hpp"
|
#include "sentry_wrapper/SentryWrapper.hpp"
|
||||||
@@ -4387,7 +4387,8 @@ void SSWCP_UserLogin_Instance::sw_GetUserUpdatePrivacy()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSWCP_UserLogin_Instance::sw_DownloadFile() {
|
void SSWCP_UserLogin_Instance::sw_DownloadFile()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
std::string fileName = m_param_data.count("file_name") ? m_param_data["file_name"].get<std::string>() : "";
|
std::string fileName = m_param_data.count("file_name") ? m_param_data["file_name"].get<std::string>() : "";
|
||||||
std::string fileUrl = m_param_data.count("file_url") ? m_param_data["file_url"].get<std::string>() : "";
|
std::string fileUrl = m_param_data.count("file_url") ? m_param_data["file_url"].get<std::string>() : "";
|
||||||
@@ -4397,17 +4398,55 @@ void SSWCP_UserLogin_Instance::sw_DownloadFile() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use WCP Download Manager
|
// Use Download Manager
|
||||||
DownloadManager* download_mgr = wxGetApp().download_manager();
|
DownloadManager* download_mgr = wxGetApp().download_manager();
|
||||||
if (!download_mgr) {
|
if (!download_mgr) {
|
||||||
handle_general_fail(-1, "WCP Download Manager not available");
|
handle_general_fail(-1, "Download Manager not available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start download task
|
size_t task_id = download_mgr->start_wcp_download(fileUrl,
|
||||||
size_t task_id = download_mgr->start_download(fileUrl, fileName, shared_from_this());
|
fileName,
|
||||||
|
shared_from_this(),
|
||||||
|
false); // use_original_event_id = false (sw_DownloadFile: finish immediately)
|
||||||
|
|
||||||
// Return task ID to Flutter
|
// Return task ID to Flutter
|
||||||
|
json response;
|
||||||
|
response["task_id"] = task_id;
|
||||||
|
response["file_name"] = fileName;
|
||||||
|
response["file_url"] = fileUrl;
|
||||||
|
m_res_data = response;
|
||||||
|
m_status = 0;
|
||||||
|
m_msg = "Download started";
|
||||||
|
send_to_js();
|
||||||
|
finish_job();
|
||||||
|
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
handle_general_fail(-1, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSWCP_UserLogin_Instance::sw_DownloadFileEx() {
|
||||||
|
try {
|
||||||
|
std::string fileName = m_param_data.count("file_name") ? m_param_data["file_name"].get<std::string>() : "";
|
||||||
|
std::string fileUrl = m_param_data.count("file_url") ? m_param_data["file_url"].get<std::string>() : "";
|
||||||
|
|
||||||
|
if (fileUrl.empty() || fileName.empty()) {
|
||||||
|
handle_general_fail(-1, "file_url and file_name are required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Download Manager
|
||||||
|
DownloadManager* download_mgr = wxGetApp().download_manager();
|
||||||
|
if (!download_mgr) {
|
||||||
|
handle_general_fail(-1, "Download Manager not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t task_id = download_mgr->start_wcp_download(fileUrl,
|
||||||
|
fileName,
|
||||||
|
shared_from_this(),
|
||||||
|
true);
|
||||||
|
|
||||||
json response;
|
json response;
|
||||||
response["task_id"] = task_id;
|
response["task_id"] = task_id;
|
||||||
response["file_name"] = fileName;
|
response["file_name"] = fileName;
|
||||||
@@ -4416,8 +4455,6 @@ void SSWCP_UserLogin_Instance::sw_DownloadFile() {
|
|||||||
m_status = 0;
|
m_status = 0;
|
||||||
m_msg = "Download started";
|
m_msg = "Download started";
|
||||||
send_to_js();
|
send_to_js();
|
||||||
// Note: Do not call finish_job() here, as download is asynchronous
|
|
||||||
// The manager will send progress updates and completion/error messages via WCP
|
|
||||||
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
handle_general_fail(-1, e.what());
|
handle_general_fail(-1, e.what());
|
||||||
|
|||||||
@@ -541,6 +541,9 @@ private:
|
|||||||
void sw_SubUserUpdatePrivacy();
|
void sw_SubUserUpdatePrivacy();
|
||||||
|
|
||||||
void sw_DownloadFile();
|
void sw_DownloadFile();
|
||||||
|
|
||||||
|
void sw_DownloadFileEx();
|
||||||
|
|
||||||
void sw_CancelDownload();
|
void sw_CancelDownload();
|
||||||
|
|
||||||
void sw_FileView();
|
void sw_FileView();
|
||||||
|
|||||||
Reference in New Issue
Block a user