Multiple downloads witch mid download saving to file

This commit is contained in:
David Kocik 2022-05-30 17:25:29 +02:00
parent 816dd9490d
commit 648e56d8bf
10 changed files with 374 additions and 83 deletions

View File

@ -24,9 +24,12 @@ Download::Download(int ID, std::string url, wxEvtHandler* evt_handler, const boo
void Download::start() void Download::start()
{ {
m_state = DownloadState::DownloadOngoing;
m_file_get->get(); m_file_get->get();
} }
void Download::stop() void Download::cancel()
{ {
m_state = DownloadState::DownloadStopped;
m_file_get->cancel();
} }
} }

View File

@ -7,21 +7,34 @@
namespace Downloader { namespace Downloader {
enum DownloadState
{
DownloadPending,
DownloadOngoing,
DownloadStopped,
DownloadDone,
DownloadError,
};
class Download { class Download {
public: public:
Download(int ID, std::string url, wxEvtHandler* evt_handler,const boost::filesystem::path& dest_folder); Download(int ID, std::string url, wxEvtHandler* evt_handler,const boost::filesystem::path& dest_folder);
void start(); void start();
void stop(); void cancel();
// void pause(); // void pause();
int get_id() const { return m_id; } int get_id() const { return m_id; }
boost::filesystem::path get_final_path() const { return m_final_path; } boost::filesystem::path get_final_path() const { return m_final_path; }
std::string get_filename() const { return m_filename; } std::string get_filename() const { return m_filename; }
DownloadState get_state() const { return m_state; }
void set_state(DownloadState state) { m_state = state; }
private: private:
const int m_id; const int m_id;
std::string m_filename; std::string m_filename;
boost::filesystem::path m_final_path; boost::filesystem::path m_final_path;
std::shared_ptr<FileGet> m_file_get; std::shared_ptr<FileGet> m_file_get;
DownloadState m_state { DownloadState::DownloadPending };
}; };
} }

View File

@ -9,6 +9,61 @@
namespace Downloader { namespace Downloader {
namespace{
void open_folder(const wxString& widepath)
{
// Code taken from desktop_open_datadir_folder()
// Execute command to open a file explorer, platform dependent.
// FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
#ifdef _WIN32
//const wxString widepath = wxString::FromUTF8(path.c_str());
const wchar_t* argv[] = { L"explorer", widepath.GetData(), nullptr };
::wxExecute(const_cast<wchar_t**>(argv), wxEXEC_ASYNC, nullptr);
#elif __APPLE__
std::string path = boost::nowide::narrow(widepath);
const char* argv[] = { "open", path.data(), nullptr };
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr);
#else
std::string path = boost::nowide::narrow(widepath);
const char* argv[] = { "xdg-open", path.data(), nullptr };
// Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
// because they may mess up the environment expected by the file manager.
// Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
if (wxGetEnv("APPIMAGE", nullptr)) {
// We're running from AppImage
wxEnvVariableHashMap env_vars;
wxGetEnvMap(&env_vars);
env_vars.erase("APPIMAGE");
env_vars.erase("APPDIR");
env_vars.erase("LD_LIBRARY_PATH");
env_vars.erase("LD_PRELOAD");
env_vars.erase("UNION_PRELOAD");
wxExecuteEnv exec_env;
exec_env.env = std::move(env_vars);
wxString owd;
if (wxGetEnv("OWD", &owd)) {
// This is the original work directory from which the AppImage image was run,
// set it as CWD for the child process:
exec_env.cwd = std::move(owd);
}
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, &exec_env);
}
else {
// Looks like we're NOT running from AppImage, we'll make no changes to the environment.
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, nullptr);
}
#endif
}
} // namespace
bool DownloadApp::OnInit() bool DownloadApp::OnInit()
{ {
m_dwnldr_send = std::make_unique<DownloaderSend>(); m_dwnldr_send = std::make_unique<DownloaderSend>();
@ -16,10 +71,10 @@ bool DownloadApp::OnInit()
if (m_dwnldr_send->get_instance_exists()) { if (m_dwnldr_send->get_instance_exists()) {
m_other_exists = true; m_other_exists = true;
m_frame = new DownloadFrame("PrusaSlicer-Downloader", wxPoint(50, 50), wxSize(0,0)); m_frame = new DownloadFrame("Downloader", wxPoint(50, 50), wxSize(0,0));
return wxApp::OnInit(); return wxApp::OnInit();
} }
m_frame = new DownloadFrame("PrusaSlicer-Downloader", wxPoint(50, 50), wxSize(450, 340)); m_frame = new DownloadFrame("Downloader", wxPoint(50, 50), wxSize(450, 340));
m_frame->Show(true); m_frame->Show(true);
wxWindow::MSWRegisterMessageHandler(WM_COPYDATA, [](wxWindow* win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) { wxWindow::MSWRegisterMessageHandler(WM_COPYDATA, [](wxWindow* win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) {
@ -70,6 +125,8 @@ bool DownloadApp::OnCmdLineParsed(wxCmdLineParser& parser)
if (!url.empty() && m_frame != nullptr) if (!url.empty() && m_frame != nullptr)
m_frame->start_download(std::move(url)); m_frame->start_download(std::move(url));
m_frame->start_download("open?file=https%3A%2F%2Fmedia.printables.com%2Fmedia%2Fprints%2F152208%2Fstls%2F1431590_8b8287b3-03b1-4cbe-82d0-268a0affa171%2Ff1_logo.stl");
return wxApp::OnCmdLineParsed(parser); return wxApp::OnCmdLineParsed(parser);
} }
} }
@ -78,35 +135,62 @@ bool DownloadApp::OnCmdLineParsed(wxCmdLineParser& parser)
DownloadFrame::DownloadFrame(const wxString& title, const wxPoint& pos, const wxSize& size) DownloadFrame::DownloadFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size) : wxFrame(NULL, wxID_ANY, title, pos, size)
, m_instance_send(std::make_unique<SlicerSend>()) , m_slicer_send(std::make_unique<SlicerSend>())
{ {
dataview = new wxDataViewListCtrl(this, wxID_ANY); auto * data_sizer = new wxBoxSizer(wxVERTICAL);
/* dataview->AppendColumn(new wxDataViewColumn("ID", new TextRenderer(), 0, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE)); m_dataview = new wxDataViewListCtrl(this, wxID_ANY);
dataview->AppendColumn(new wxDataViewColumn("Filename", new TextRenderer(), 1, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE));
dataview->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); /* m_dataview->AppendColumn(new wxDataViewColumn("ID", new TextRenderer(), 0, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE));
dataview->AppendColumn(new wxDataViewColumn("status", new TextRenderer(), 2, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE));*/ m_dataview->AppendColumn(new wxDataViewColumn("Filename", new TextRenderer(), 1, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE));
m_dataview->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
m_dataview->AppendColumn(new wxDataViewColumn("status", new TextRenderer(), 2, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE));*/
dataview->AppendTextColumn("ID", wxDATAVIEW_CELL_INERT, 30, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); m_dataview->AppendTextColumn("ID", wxDATAVIEW_CELL_INERT, 30, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
dataview->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); m_dataview->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
dataview->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); m_dataview->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
dataview->AppendTextColumn("status", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); m_dataview->AppendTextColumn("status", wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
data_sizer->Add(m_dataview, 1, wxEXPAND | wxBOTTOM);
m_dest_folder = boost::filesystem::path("C:\\Users\\User\\Downloads"); m_dest_folder = boost::filesystem::path("C:\\Users\\User\\Downloads");
m_log_label = new wxStaticText(this, wxID_ANY, "Log:"); //m_log_label = new wxStaticText(this, wxID_ANY, "Log:");
auto* sizer = new wxBoxSizer(wxVERTICAL);
//sizer->Add(m_log_label, wxEXPAND); ////sizer->Add(m_log_label, wxEXPAND);
sizer->Add(dataview, 1, wxEXPAND | wxBOTTOM); //
SetSizer(sizer);
wxBoxSizer* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
wxButton* btn_run = new wxButton(this, wxID_OK, "Run");
btn_run->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { on_open_in_slicer(evt); });
btn_sizer->Add(btn_run, 0, wxLEFT | wxALIGN_CENTER_VERTICAL);
wxButton* btn_run_new = new wxButton(this, wxID_EDIT, "Run new");
btn_run_new->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { on_open_in_new_slicer(evt); });
btn_sizer->Add(btn_run_new, 0, wxLEFT | wxALIGN_CENTER_VERTICAL);
wxButton* btn_folder = new wxButton(this, wxID_EDIT, "Open");
btn_folder->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { on_open_in_explorer(evt); });
btn_sizer->Add(btn_folder, 0, wxLEFT | wxALIGN_CENTER_VERTICAL);
wxButton* btn_cancel = new wxButton(this, wxID_EDIT, "Cancel");
btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) { on_cancel_button(evt); });
btn_sizer->Add(btn_cancel, 0, wxLEFT | wxALIGN_CENTER_VERTICAL);
//main_sizer->Add(data_sizer);
//main_sizer->Add(btn_sizer);
data_sizer->Add(btn_sizer, 0, wxEXPAND);
SetSizer(data_sizer);
Bind(EVT_FILE_COMPLETE, &DownloadFrame::on_complete, this); Bind(EVT_FILE_COMPLETE, &DownloadFrame::on_complete, this);
Bind(EVT_FILE_PROGRESS, &DownloadFrame::on_progress, this); Bind(EVT_FILE_PROGRESS, &DownloadFrame::on_progress, this);
Bind(EVT_FILE_ERROR, &DownloadFrame::on_error, this); Bind(EVT_FILE_ERROR, &DownloadFrame::on_error, this);
Bind(EVT_FILE_NAME_CHANGE, &DownloadFrame::on_name_change, this);
} }
void DownloadFrame::start_download(wxString url) void DownloadFrame::start_download(wxString url)
@ -115,62 +199,177 @@ void DownloadFrame::start_download(wxString url)
if (url.starts_with("open?file=")) { if (url.starts_with("open?file=")) {
int id = get_next_id(); int id = get_next_id();
std::string escaped_url = FileGet::escape_url(boost::nowide::narrow(url.substr(10))); std::string escaped_url = FileGet::escape_url(boost::nowide::narrow(url.substr(10)));
log(std::to_string(id) + ": start " + escaped_url); //log(std::to_string(id) + ": start " + escaped_url);
escaped_url = "https://media.printables.com/media/prints/216267/gcodes/1974221_32d21613-b567-4328-8261-49b46d9dd249/01_big_trex_skull_with_threads_015mm_pla_mk3_2d.gcode";
m_downloads.emplace_back(std::make_unique<Download>(id, std::move(escaped_url), this, m_dest_folder)); m_downloads.emplace_back(std::make_unique<Download>(id, std::move(escaped_url), this, m_dest_folder));
m_downloads.back()->start(); //
wxVector<wxVariant> fields; wxVector<wxVariant> fields;
fields.push_back(wxVariant(std::to_wstring(id))); fields.push_back(wxVariant(std::to_wstring(id)));
fields.push_back(wxVariant(m_downloads.back()->get_filename())); fields.push_back(wxVariant(m_downloads.back()->get_filename()));
fields.push_back(wxVariant(0)); fields.push_back(wxVariant(0));
fields.push_back(wxVariant("Pending")); fields.push_back(wxVariant("Pending"));
dataview->AppendItem(fields); m_dataview->AppendItem(fields);
bool can_start = true;
for (size_t i = 0; i < m_downloads.size(); i++) {
if (m_downloads[i]->get_state() == DownloadState::DownloadOngoing) {
//can_start = false;
break;
}
}
if (can_start)
m_downloads.back()->start();
} else { } else {
log("wrong url: " + url); //log("wrong url: " + url);
} }
} }
void DownloadFrame::log(const wxString& msg) void DownloadFrame::log(const wxString& msg)
{ {
m_log_lines++; //m_log_lines++;
wxString old_log = m_log_label->GetLabel(); //wxString old_log = m_log_label->GetLabel();
if (m_log_lines > 10) { //if (m_log_lines > 10) {
size_t endline = old_log.Find('\n'); // size_t endline = old_log.Find('\n');
endline = old_log.find('\n', endline + 1); // endline = old_log.find('\n', endline + 1);
if (endline != wxString::npos) { // if (endline != wxString::npos) {
old_log = "Log:\n" + old_log.substr(endline + 1); // old_log = "Log:\n" + old_log.substr(endline + 1);
} // }
} //}
//m_log_label->SetLabel(old_log +"\n"+ msg); ////m_log_label->SetLabel(old_log +"\n"+ msg);
//printf("%s\n",old_log + "\n" + msg); ////printf("%s\n",old_log + "\n" + msg);
m_full_log += +"\n" + msg; //m_full_log += +"\n" + msg;
} }
void DownloadFrame::on_progress(wxCommandEvent& event) void DownloadFrame::on_progress(wxCommandEvent& event)
{ {
//log(std::to_string(event.GetInt()) + ": " + event.GetString()); //log(std::to_string(event.GetInt()) + ": " + event.GetString());
dataview->SetValue(std::stoi(boost::nowide::narrow(event.GetString())), event.GetInt() - 1, 2); m_dataview->SetValue(std::stoi(boost::nowide::narrow(event.GetString())), event.GetInt() - 1, 2);
dataview->SetValue("Downloading", event.GetInt() -1, 3); m_dataview->SetValue("Downloading", event.GetInt() -1, 3);
} }
void DownloadFrame::on_error(wxCommandEvent& event) void DownloadFrame::on_error(wxCommandEvent& event)
{ {
//log(std::to_string(event.GetInt()) + ": " + event.GetString()); set_download_state(event.GetInt(), DownloadState::DownloadError);
//SetStatusText(event.GetString().c_str()); m_dataview->SetValue("Error", event.GetInt() - 1, 3);
dataview->SetValue("Error", event.GetInt() - 1, 3);
} }
void DownloadFrame::on_complete(wxCommandEvent& event) void DownloadFrame::on_complete(wxCommandEvent& event)
{ {
dataview->SetValue("Done", event.GetInt() - 1, 3); set_download_state(event.GetInt(), DownloadState::DownloadDone);
m_instance_send->start_with_path(event.GetString()); m_dataview->SetValue("Done", event.GetInt() - 1, 3);
start_next();
} }
void DownloadFrame::on_name_change(wxCommandEvent& event)
{
m_dataview->SetValue(event.GetString(), event.GetInt() - 1, 1);
}
void DownloadFrame::start_next()
{
for (size_t i = 0; i < m_downloads.size(); i++) {
if (m_downloads[i]->get_state() == DownloadState::DownloadPending) {
m_downloads[i]->start();
break;
}
}
}
void DownloadFrame::on_open_in_slicer(wxCommandEvent& event)
{
int selected = m_dataview->GetSelectedRow();
if (selected == wxNOT_FOUND) { return; }
int id = std::stoi(boost::nowide::narrow(m_dataview->GetTextValue(selected,0)));
if (is_in_state(id, DownloadState::DownloadDone)) {
m_slicer_send->start_or_send(get_path_of(id));
}
}
void DownloadFrame::on_open_in_new_slicer(wxCommandEvent& event)
{
int selected = m_dataview->GetSelectedRow();
if (selected == wxNOT_FOUND) { return; }
int id = std::stoi(boost::nowide::narrow(m_dataview->GetTextValue(selected, 0)));
if (is_in_state(id, DownloadState::DownloadDone)) {
m_slicer_send->start_with_path(get_path_of(id));
}
}
void DownloadFrame::on_open_in_explorer(wxCommandEvent& event)
{
int selected = m_dataview->GetSelectedRow();
if (selected == wxNOT_FOUND) { return; }
int id = std::stoi(boost::nowide::narrow(m_dataview->GetTextValue(selected, 0)));
if (is_in_state(id, DownloadState::DownloadDone)) {
open_folder(get_folder_path_of(id));
}
}
void DownloadFrame::on_cancel_button(wxCommandEvent& event)
{
int selected = m_dataview->GetSelectedRow();
if (selected == wxNOT_FOUND) { return; }
int id = std::stoi(boost::nowide::narrow(m_dataview->GetTextValue(selected, 0)));
if(cancel_download(id))
m_dataview->SetValue("Canceled", id - 1, 3);
}
void DownloadFrame::set_download_state(int id, DownloadState state)
{
for( size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
m_downloads[i]->set_state(state);
return;
}
}
}
bool DownloadFrame::is_in_state(int id, DownloadState state) const
{
for (size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
return m_downloads[i]->get_state();
}
}
}
bool DownloadFrame::cancel_download(int id)
{
for (size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
if (m_downloads[i]->get_state() == DownloadState::DownloadOngoing) {
m_downloads[i]->cancel();
return true;
}
return false;
}
}
return false;
}
wxString DownloadFrame::get_path_of(int id) const
{
for (size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
return m_downloads[i]->get_final_path().string();
}
}
}
wxString DownloadFrame::get_folder_path_of(int id) const
{
for (size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
return m_downloads[i]->get_final_path().parent_path().string();
}
}
}
void DownloadFrame::handle_message(const wxString& msg) void DownloadFrame::handle_message(const wxString& msg)
{ {
log("recieved: " + msg); //log("recieved: " + msg);
start_download(msg); start_download(msg);
} }

View File

@ -24,8 +24,20 @@ private:
void on_progress(wxCommandEvent& event); void on_progress(wxCommandEvent& event);
void on_error(wxCommandEvent& event); void on_error(wxCommandEvent& event);
void on_complete(wxCommandEvent& event); void on_complete(wxCommandEvent& event);
void on_name_change(wxCommandEvent& event);
void on_open_in_slicer(wxCommandEvent& event);
void on_open_in_new_slicer(wxCommandEvent& event);
void on_open_in_explorer(wxCommandEvent& event);
void on_cancel_button(wxCommandEvent& event);
void start_next();
void set_download_state(int id, DownloadState state);
bool is_in_state(int id, DownloadState state) const;
bool cancel_download(int id);
wxString get_path_of(int id) const;
wxString get_folder_path_of(int id) const;
int m_next_id { 0 }; int m_next_id { 0 };
int get_next_id() {return ++m_next_id; } int get_next_id() {return ++m_next_id; }
@ -33,12 +45,12 @@ private:
size_t m_log_lines { 0 }; size_t m_log_lines { 0 };
wxString m_full_log; wxString m_full_log;
wxDataViewListCtrl* dataview; wxDataViewListCtrl* m_dataview;
wxString m_url; wxString m_url;
wxString m_path_to_slicer; wxString m_path_to_slicer;
std::unique_ptr<SlicerSend> m_instance_send; std::unique_ptr<SlicerSend> m_slicer_send;
boost::filesystem::path m_dest_folder; boost::filesystem::path m_dest_folder;

View File

@ -8,6 +8,8 @@
namespace Downloader { namespace Downloader {
const size_t DOWNLOAD_MAX_CHUNK_SIZE = 10 * 1024 * 1024;
const size_t DOWNLOAD_SIZE_LIMIT = 1024 * 1024 * 1024;
std::string FileGet::escape_url(const std::string& unescaped) std::string FileGet::escape_url(const std::string& unescaped)
{ {
@ -41,6 +43,9 @@ wxDEFINE_EVENT(EVT_FILE_COMPLETE, wxCommandEvent);
wxDEFINE_EVENT(EVT_FILE_ERROR, wxCommandEvent); wxDEFINE_EVENT(EVT_FILE_ERROR, wxCommandEvent);
// int = DOWNLOAD ID; string = progress percent // int = DOWNLOAD ID; string = progress percent
wxDEFINE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent); wxDEFINE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent);
// int = DOWNLOAD ID; string = name
wxDEFINE_EVENT(EVT_FILE_NAME_CHANGE, wxCommandEvent);
struct FileGet::priv struct FileGet::priv
{ {
@ -73,10 +78,39 @@ void FileGet::priv::get_perform()
assert(!m_filename.empty()); assert(!m_filename.empty());
assert(boost::filesystem::is_directory(m_dest_folder)); assert(boost::filesystem::is_directory(m_dest_folder));
// open dest file
boost::filesystem::path dest_path = m_dest_folder / m_filename;
std::string extension = boost::filesystem::extension(dest_path);
std::string just_filename = m_filename.substr(0, m_filename.size() - extension.size());
std::string final_filename = just_filename;
size_t version = 0;
while (boost::filesystem::exists(m_dest_folder / (final_filename + extension)) || boost::filesystem::exists(m_dest_folder / (final_filename + extension + "." + std::to_string(get_current_pid()) + ".download")))
{
++version;
final_filename = just_filename + "(" + std::to_string(version) + ")";
}
m_filename = final_filename + extension;
boost::filesystem::path tmp_path = m_dest_folder / (m_filename + "." + std::to_string(get_current_pid()) + ".download");
dest_path = m_dest_folder / m_filename;
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_NAME_CHANGE);
evt->SetString(boost::nowide::widen(m_filename));
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
// open file for writting
FILE* file = fopen(tmp_path.string().c_str(), "wb");
size_t written = 0;
Downloader::Http::get(m_url) Downloader::Http::get(m_url)
//.size_limit(size_limit) .size_limit(DOWNLOAD_SIZE_LIMIT) //more?
.on_progress([&](Downloader::Http::Progress progress, bool& cancel) { .on_progress([&](Downloader::Http::Progress progress, bool& cancel) {
if (m_cancel) { if (m_cancel) {
fclose(file);
// remove canceled file
std::remove(tmp_path.string().c_str());
cancel = true; cancel = true;
return; return;
// TODO: send canceled event? // TODO: send canceled event?
@ -84,12 +118,32 @@ void FileGet::priv::get_perform()
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_PROGRESS); wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_PROGRESS);
if (progress.dlnow == 0) if (progress.dlnow == 0)
evt->SetString("0"); evt->SetString("0");
else else {
if (progress.dlnow - written > DOWNLOAD_MAX_CHUNK_SIZE || progress.dlnow == progress.dltotal) {
try
{
std::string part_for_write = progress.buffer.substr(written, progress.dlnow);
fwrite(part_for_write.c_str(), 1, part_for_write.size(), file);
}
catch (const std::exception&)
{
// fclose(file); do it?
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR);
evt->SetString("Failed to write progress.");
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
cancel = true;
return;
}
written = progress.dlnow;
}
evt->SetString(std::to_string(progress.dlnow * 100 / progress.dltotal)); evt->SetString(std::to_string(progress.dlnow * 100 / progress.dltotal));
}
evt->SetInt(m_id); evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt); m_evt_handler->QueueEvent(evt);
}) })
.on_error([&](std::string body, std::string error, unsigned http_status) { .on_error([&](std::string body, std::string error, unsigned http_status) {
fclose(file);
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR); wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR);
evt->SetString(error); evt->SetString(error);
evt->SetInt(m_id); evt->SetInt(m_id);
@ -102,30 +156,18 @@ void FileGet::priv::get_perform()
//if (body_size != expected_size) { //if (body_size != expected_size) {
// return; // return;
//} //}
boost::filesystem::path dest_path = m_dest_folder / m_filename;
std::string extension = boost::filesystem::extension(dest_path);
std::string just_filename = m_filename.substr(0, m_filename.size() - extension.size());
std::string final_filename = just_filename;
size_t version = 0;
while (boost::filesystem::exists(m_dest_folder / (final_filename + extension)))
{
++version;
final_filename = just_filename + "("+std::to_string(version)+")";
}
m_filename = final_filename + extension;
boost::filesystem::path tmp_path = m_dest_folder / (m_filename + "." + std::to_string(get_current_pid()) + ".download");
dest_path = m_dest_folder / m_filename;
try try
{ {
boost::nowide::fstream file(tmp_path.string(), std::ios::out | std::ios::binary | std::ios::trunc); if (written < body.size())
file.write(body.c_str(), body.size()); {
file.close(); // this code should never be entered. As there should be on_progress call after last bit downloaded.
std::string part_for_write = body.substr(written);
fwrite(part_for_write.c_str(), 1, part_for_write.size(), file);
}
fclose(file);
boost::filesystem::rename(tmp_path, dest_path); boost::filesystem::rename(tmp_path, dest_path);
} }
catch (const std::exception&) catch (const std::exception& e)
{ {
//TODO: report? //TODO: report?
//error_message = GUI::format("Failed to write and move %1% to %2%", tmp_path, dest_path); //error_message = GUI::format("Failed to write and move %1% to %2%", tmp_path, dest_path);

View File

@ -30,6 +30,7 @@ wxDECLARE_EVENT(EVT_FILE_COMPLETE, wxCommandEvent);
wxDECLARE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent); wxDECLARE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent);
// int = DOWNLOAD ID; string = progress percent // int = DOWNLOAD ID; string = progress percent
wxDECLARE_EVENT(EVT_FILE_ERROR, wxCommandEvent); wxDECLARE_EVENT(EVT_FILE_ERROR, wxCommandEvent);
// int = DOWNLOAD ID; string = name
wxDECLARE_EVENT(EVT_FILE_NAME_CHANGE, wxCommandEvent);
} }
#endif #endif

View File

@ -225,7 +225,7 @@ int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_o
bool cb_cancel = false; bool cb_cancel = false;
if (self->progressfn) { if (self->progressfn) {
Progress progress(dltotal, dlnow, ultotal, ulnow); Progress progress(dltotal, dlnow, ultotal, ulnow, self->buffer);
self->progressfn(progress, cb_cancel); self->progressfn(progress, cb_cancel);
} }
@ -370,7 +370,7 @@ void Http::priv::http_perform()
if (res == CURLE_ABORTED_BY_CALLBACK) { if (res == CURLE_ABORTED_BY_CALLBACK) {
if (cancel) { if (cancel) {
// The abort comes from the request being cancelled programatically // The abort comes from the request being cancelled programatically
Progress dummyprogress(0, 0, 0, 0); Progress dummyprogress(0, 0, 0, 0, std::string());
bool cancel = true; bool cancel = true;
if (progressfn) { progressfn(dummyprogress, cancel); } if (progressfn) { progressfn(dummyprogress, cancel); }
} else { } else {

View File

@ -22,8 +22,10 @@ public:
size_t ultotal; // Total bytes to upload size_t ultotal; // Total bytes to upload
size_t ulnow; // Bytes uploaded so far size_t ulnow; // Bytes uploaded so far
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) : const std::string& buffer; // reference to buffer containing all data
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow)
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow, const std::string& buffer) :
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow), buffer(buffer)
{} {}
}; };

View File

@ -70,9 +70,9 @@ namespace {
#ifdef _WIN32 #ifdef _WIN32
static HWND l_prusa_slicer_hwnd; static HWND l_prusa_slicer_hwnd;
static HWND l_downloader_hwnd; static HWND l_downloader_hwnd;
BOOL CALLBACK EnumWindowsProcSlicer(_In_ HWND hwnd, _In_ LPARAM lParam) BOOL CALLBACK EnumWindowsProcSlicer(_In_ HWND hwnd, _In_ LPARAM lParam)
{ {
//checks for other instances of prusaslicer, if found brings it to front and return false to stop enumeration and quit this instance //checks for other instances of prusaslicer, if found brings it to front and return false to cancel enumeration and quit this instance
//search is done by classname(wxWindowNR is wxwidgets thing, so probably not unique) and name in window upper panel //search is done by classname(wxWindowNR is wxwidgets thing, so probably not unique) and name in window upper panel
//other option would be do a mutex and check for its existence //other option would be do a mutex and check for its existence
//BOOST_LOG_TRIVIAL(error) << "ewp: version: " << l_version_wstring; //BOOST_LOG_TRIVIAL(error) << "ewp: version: " << l_version_wstring;
@ -136,9 +136,9 @@ bool send_message_slicer(const wxString& message)
} }
BOOL CALLBACK EnumWindowsProcDownloader(_In_ HWND hwnd, _In_ LPARAM lParam) BOOL CALLBACK EnumWindowsProcDownloader(_In_ HWND hwnd, _In_ LPARAM lParam)
{ {
//checks for other instances of prusaslicer, if found brings it to front and return false to stop enumeration and quit this instance //checks for other instances of prusaslicer, if found brings it to front and return false to cancel enumeration and quit this instance
//search is done by classname(wxWindowNR is wxwidgets thing, so probably not unique) and name in window upper panel //search is done by classname(wxWindowNR is wxwidgets thing, so probably not unique) and name in window upper panel
//other option would be do a mutex and check for its existence //other option would be do a mutex and check for its existence
//BOOST_LOG_TRIVIAL(error) << "ewp: version: " << l_version_wstring; //BOOST_LOG_TRIVIAL(error) << "ewp: version: " << l_version_wstring;
@ -153,7 +153,7 @@ BOOL CALLBACK EnumWindowsProcDownloader(_In_ HWND hwnd, _In_ LPARAM lParam)
return true; return true;
std::wstring classNameString(className); std::wstring classNameString(className);
std::wstring wndTextString(wndText); std::wstring wndTextString(wndText);
if (wndTextString.find(L"PrusaSlicer-Downloader") != std::wstring::npos && classNameString == L"wxWindowNR") { if (wndTextString.find(L"Downloader") != std::wstring::npos && classNameString == L"wxWindowNR") {
//check if other instances has same instance hash //check if other instances has same instance hash
//if not it is not same version(binary) as this version //if not it is not same version(binary) as this version
HANDLE handle = GetProp(hwnd, L"Instance_Hash_Minor"); HANDLE handle = GetProp(hwnd, L"Instance_Hash_Minor");
@ -210,6 +210,10 @@ bool execute_command(const wxString& command)
#endif #endif
} }
// ------ SlicerSend ----------------
bool SlicerSend::get_instance_exists() const bool SlicerSend::get_instance_exists() const
{ {
return !EnumWindows(EnumWindowsProcSlicer, 0); return !EnumWindows(EnumWindowsProcSlicer, 0);
@ -219,6 +223,7 @@ bool SlicerSend::send_path(const wxString& path) const
std::string escaped = escape_strings_cstyle({ "prusa-downloader", boost::nowide::narrow(path) }); std::string escaped = escape_strings_cstyle({ "prusa-downloader", boost::nowide::narrow(path) });
return send_message_slicer(boost::nowide::widen(escaped)); return send_message_slicer(boost::nowide::widen(escaped));
} }
bool SlicerSend::start_with_path(const wxString& path) const bool SlicerSend::start_with_path(const wxString& path) const
{ {
// "C:\\Users\\User\\Downloads\\PrusaSlicer-2.4.2+win64-202204251110\\prusa-slicer.exe " // "C:\\Users\\User\\Downloads\\PrusaSlicer-2.4.2+win64-202204251110\\prusa-slicer.exe "
@ -227,6 +232,17 @@ bool SlicerSend::start_with_path(const wxString& path) const
return execute_command("C:\\Users\\User\\Downloads\\PrusaSlicer-2.4.2+win64-202204251110\\prusa-slicer.exe " + boost::nowide::widen(escaped)); return execute_command("C:\\Users\\User\\Downloads\\PrusaSlicer-2.4.2+win64-202204251110\\prusa-slicer.exe " + boost::nowide::widen(escaped));
} }
bool SlicerSend::start_or_send(const wxString& path) const
{
if (send_path(path))
return true;
return start_with_path(path);
}
// ------ DownloaderSend ----------------
bool DownloaderSend::get_instance_exists() const bool DownloaderSend::get_instance_exists() const
{ {
return !EnumWindows(EnumWindowsProcDownloader, 0); return !EnumWindows(EnumWindowsProcDownloader, 0);
@ -236,4 +252,6 @@ bool DownloaderSend::send_url(const wxString& url) const
//std::string escaped = escape_strings_cstyle({ boost::nowide::narrow(url) }); //std::string escaped = escape_strings_cstyle({ boost::nowide::narrow(url) });
return send_message_downloader(url); return send_message_downloader(url);
} }
} }

View File

@ -11,6 +11,7 @@ public:
bool get_instance_exists() const; bool get_instance_exists() const;
bool send_path(const wxString& path) const; bool send_path(const wxString& path) const;
bool start_with_path(const wxString& path) const; bool start_with_path(const wxString& path) const;
bool start_or_send(const wxString& path) const;
}; };
class DownloaderSend class DownloaderSend