diff options
author | Vojtech Kral <vojtech@kral.hk> | 2018-04-04 12:18:22 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2018-04-04 12:18:22 +0300 |
commit | b0840065ed84f4006207b38de3c9c6a5e15a7071 (patch) | |
tree | 3da655b0f6ca247d0f567831a978a73c68246978 /xs/src/slic3r/Utils | |
parent | 00324a14b84f47cc6ae1dc92e6582ee6b6171e03 (diff) |
Octoprint (#804)
* Octoprint progress dialog
* Fix curl version on Windows
Diffstat (limited to 'xs/src/slic3r/Utils')
-rw-r--r-- | xs/src/slic3r/Utils/Http.cpp | 73 | ||||
-rw-r--r-- | xs/src/slic3r/Utils/Http.hpp | 17 | ||||
-rw-r--r-- | xs/src/slic3r/Utils/OctoPrint.cpp | 66 | ||||
-rw-r--r-- | xs/src/slic3r/Utils/OctoPrint.hpp | 2 |
4 files changed, 124 insertions, 34 deletions
diff --git a/xs/src/slic3r/Utils/Http.cpp b/xs/src/slic3r/Utils/Http.cpp index de28904e2..0826284d8 100644 --- a/xs/src/slic3r/Utils/Http.cpp +++ b/xs/src/slic3r/Utils/Http.cpp @@ -36,16 +36,20 @@ struct Http::priv ::curl_slist *headerlist; std::string buffer; size_t limit; + bool cancel; std::thread io_thread; Http::CompleteFn completefn; Http::ErrorFn errorfn; + Http::ProgressFn progressfn; priv(const std::string &url); ~priv(); static bool ca_file_supported(::CURL *curl); static size_t writecb(void *data, size_t size, size_t nmemb, void *userp); + static int xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); + static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow); std::string curl_error(CURLcode curlcode); std::string body_size_error(); void http_perform(); @@ -55,7 +59,8 @@ Http::priv::priv(const std::string &url) : curl(::curl_easy_init()), form(nullptr), form_end(nullptr), - headerlist(nullptr) + headerlist(nullptr), + cancel(false) { if (curl == nullptr) { throw std::runtime_error(std::string("Could not construct Curl object")); @@ -112,6 +117,24 @@ size_t Http::priv::writecb(void *data, size_t size, size_t nmemb, void *userp) return realsize; } +int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +{ + auto self = static_cast<priv*>(userp); + bool cb_cancel = false; + + if (self->progressfn) { + Progress progress(dltotal, dlnow, ultotal, ulnow); + self->progressfn(progress, cb_cancel); + } + + return self->cancel || cb_cancel; +} + +int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow) +{ + return xfercb(userp, dltotal, dlnow, ultotal, ulnow); +} + std::string Http::priv::curl_error(CURLcode curlcode) { return (boost::format("%1% (%2%)") @@ -132,6 +155,16 @@ void Http::priv::http_perform() ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this)); + ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); +#if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 32 + ::curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xfercb); + ::curl_easy_setopt(curl, CURLOPT_XFERINFODATA, static_cast<void*>(this)); + (void)xfercb_legacy; // prevent unused function warning +#else + ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, xfercb); + ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, static_cast<void*>(this)); +#endif + #ifndef NDEBUG ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif @@ -149,16 +182,16 @@ void Http::priv::http_perform() ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status); if (res != CURLE_OK) { - std::string error; - if (res == CURLE_WRITE_ERROR) { - error = std::move(body_size_error()); + if (res == CURLE_ABORTED_BY_CALLBACK) { + Progress dummyprogress(0, 0, 0, 0); + bool cancel = true; + if (progressfn) { progressfn(dummyprogress, cancel); } + } + else if (res == CURLE_WRITE_ERROR) { + if (errorfn) { errorfn(std::move(buffer), std::move(body_size_error()), http_status); } } else { - error = std::move(curl_error(res)); + if (errorfn) { errorfn(std::move(buffer), std::move(curl_error(res)), http_status); } }; - - if (errorfn) { - errorfn(std::move(buffer), std::move(error), http_status); - } } else { if (completefn) { completefn(std::move(buffer), http_status); @@ -258,6 +291,12 @@ Http& Http::on_error(ErrorFn fn) return *this; } +Http& Http::on_progress(ProgressFn fn) +{ + if (p) { p->progressfn = std::move(fn); } + return *this; +} + Http::Ptr Http::perform() { auto self = std::make_shared<Http>(std::move(*this)); @@ -277,6 +316,11 @@ void Http::perform_sync() if (p) { p->http_perform(); } } +void Http::cancel() +{ + if (p) { p->cancel = true; } +} + Http Http::get(std::string url) { return std::move(Http{std::move(url)}); @@ -297,5 +341,16 @@ bool Http::ca_file_supported() return res; } +std::ostream& operator<<(std::ostream &os, const Http::Progress &progress) +{ + os << "Http::Progress(" + << "dltotal = " << progress.dltotal + << ", dlnow = " << progress.dlnow + << ", ultotal = " << progress.ultotal + << ", ulnow = " << progress.ulnow + << ")"; + return os; +} + } diff --git a/xs/src/slic3r/Utils/Http.hpp b/xs/src/slic3r/Utils/Http.hpp index 6ac5fcce1..7ed8196e6 100644 --- a/xs/src/slic3r/Utils/Http.hpp +++ b/xs/src/slic3r/Utils/Http.hpp @@ -14,9 +14,22 @@ class Http : public std::enable_shared_from_this<Http> { private: struct priv; public: + struct Progress + { + size_t dltotal; + size_t dlnow; + size_t ultotal; + size_t ulnow; + + Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) : + dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow) + {} + }; + typedef std::shared_ptr<Http> Ptr; typedef std::function<void(std::string /* body */, unsigned /* http_status */)> CompleteFn; typedef std::function<void(std::string /* body */, std::string /* error */, unsigned /* http_status */)> ErrorFn; + typedef std::function<void(Progress, bool& /* cancel */)> ProgressFn; Http(Http &&other); @@ -37,9 +50,11 @@ public: Http& on_complete(CompleteFn fn); Http& on_error(ErrorFn fn); + Http& on_progress(ProgressFn fn); Ptr perform(); void perform_sync(); + void cancel(); static bool ca_file_supported(); private: @@ -48,6 +63,8 @@ private: std::unique_ptr<priv> p; }; +std::ostream& operator<<(std::ostream &, const Http::Progress &); + } diff --git a/xs/src/slic3r/Utils/OctoPrint.cpp b/xs/src/slic3r/Utils/OctoPrint.cpp index 5bf51f470..e63a16c38 100644 --- a/xs/src/slic3r/Utils/OctoPrint.cpp +++ b/xs/src/slic3r/Utils/OctoPrint.cpp @@ -1,10 +1,11 @@ #include "OctoPrint.hpp" -#include <iostream> +#include <algorithm> #include <boost/format.hpp> #include <wx/frame.h> #include <wx/event.h> +#include <wx/progdlg.h> #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" @@ -39,36 +40,53 @@ bool OctoPrint::test(wxString &msg) const return res; } -void OctoPrint::send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print) const +bool OctoPrint::send_gcode(const std::string &filename, bool print) const { + enum { PROGRESS_RANGE = 1000 }; + + const auto errortitle = _(L("Error while uploading to the OctoPrint server")); + + wxProgressDialog progress_dialog( + _(L("OctoPrint upload")), + _(L("Sending G-code file to the OctoPrint server...")), + PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); + progress_dialog.Pulse(); + + wxString test_msg; + if (!test(test_msg)) { + auto errormsg = wxString::Format("%s: %s", errortitle, test_msg); + GUI::show_error(&progress_dialog, std::move(errormsg)); + return false; + } + + bool res = true; + auto http = Http::post(std::move(make_url("api/files/local"))); set_auth(http); http.form_add("print", print ? "true" : "false") .form_add_file("file", filename) - .on_complete([=](std::string body, unsigned status) { - wxWindow *window = wxWindow::FindWindowById(windowId); - if (window == nullptr) { return; } - - wxCommandEvent* evt = new wxCommandEvent(completeEvt); - evt->SetString(_(L("G-code file successfully uploaded to the OctoPrint server"))); - evt->SetInt(100); - wxQueueEvent(window, evt); + .on_complete([&](std::string body, unsigned status) { + progress_dialog.Update(PROGRESS_RANGE); + }) + .on_error([&](std::string body, std::string error, unsigned status) { + auto errormsg = wxString::Format("%s: %s", errortitle, format_error(error, status)); + GUI::show_error(&progress_dialog, std::move(errormsg)); + res = false; }) - .on_error([=](std::string body, std::string error, unsigned status) { - wxWindow *window = wxWindow::FindWindowById(windowId); - if (window == nullptr) { return; } - - wxCommandEvent* evt_complete = new wxCommandEvent(completeEvt); - evt_complete->SetInt(100); - wxQueueEvent(window, evt_complete); - - wxCommandEvent* evt_error = new wxCommandEvent(errorEvt); - evt_error->SetString(wxString::Format("%s: %s", - _(L("Error while uploading to the OctoPrint server")), - format_error(error, status))); - wxQueueEvent(window, evt_error); + .on_progress([&](Http::Progress progress, bool &cancel) { + if (cancel) { + // Upload was canceled + res = false; + } else if (progress.ultotal > 0) { + int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal; + cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1)); // Cap the value to prevent premature dialog closing + } else { + cancel = !progress_dialog.Pulse(); + } }) - .perform(); + .perform_sync(); + + return res; } void OctoPrint::set_auth(Http &http) const diff --git a/xs/src/slic3r/Utils/OctoPrint.hpp b/xs/src/slic3r/Utils/OctoPrint.hpp index 1f544295c..744b4fcc1 100644 --- a/xs/src/slic3r/Utils/OctoPrint.hpp +++ b/xs/src/slic3r/Utils/OctoPrint.hpp @@ -17,7 +17,7 @@ public: OctoPrint(DynamicPrintConfig *config); bool test(wxString &curl_msg) const; - void send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print = false) const; + bool send_gcode(const std::string &filename, bool print = false) const; private: std::string host; std::string apikey; |