Octoprint (#804)
* Octoprint progress dialog * Fix curl version on Windows
This commit is contained in:
parent
00324a14b8
commit
b0840065ed
@ -1,8 +1,9 @@
|
|||||||
# Building Slic3r PE on Microsoft Windows
|
# Building Slic3r PE on Microsoft Windows
|
||||||
|
|
||||||
The currently supported way of building Slic3r PE on Windows is with MS Visual Studio 2013
|
The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013
|
||||||
using our Perl binary distribution (compiled from official Perl sources).
|
using our Perl binary distribution (compiled from official Perl sources).
|
||||||
You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/).
|
You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/).
|
||||||
|
CMake installer can be downloaded from [the official website](https://cmake.org/download/).
|
||||||
|
|
||||||
Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work
|
Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work
|
||||||
and cannot provide guidance.
|
and cannot provide guidance.
|
||||||
@ -26,8 +27,8 @@ Apart from wxWidgets and Perl, you will also need additional dependencies:
|
|||||||
|
|
||||||
We have prepared a binary package of the listed libraries:
|
We have prepared a binary package of the listed libraries:
|
||||||
|
|
||||||
- 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-32.7z)
|
- 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-32.7z)
|
||||||
- 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-64.7z)
|
- 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-64.7z)
|
||||||
|
|
||||||
It is recommended you unpack this package into `C:\local\` as the environment
|
It is recommended you unpack this package into `C:\local\` as the environment
|
||||||
setup script expects it there.
|
setup script expects it there.
|
||||||
|
@ -37,7 +37,7 @@ if ($destdir -eq "") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$BOOST = 'boost_1_63_0'
|
$BOOST = 'boost_1_63_0'
|
||||||
$CURL = 'curl-7.28.0'
|
$CURL = 'curl-7.58.0'
|
||||||
$TBB_SHA = 'a0dc9bf76d0120f917b641ed095360448cabc85b'
|
$TBB_SHA = 'a0dc9bf76d0120f917b641ed095360448cabc85b'
|
||||||
$TBB = "tbb-$TBB_SHA"
|
$TBB = "tbb-$TBB_SHA"
|
||||||
|
|
||||||
|
@ -1481,7 +1481,11 @@ sub on_export_completed {
|
|||||||
# Send $self->{send_gcode_file} to OctoPrint.
|
# Send $self->{send_gcode_file} to OctoPrint.
|
||||||
if ($send_gcode) {
|
if ($send_gcode) {
|
||||||
my $op = Slic3r::OctoPrint->new($self->{config});
|
my $op = Slic3r::OctoPrint->new($self->{config});
|
||||||
$op->send_gcode($self->GetId(), $PROGRESS_BAR_EVENT, $ERROR_EVENT, $self->{send_gcode_file});
|
if ($op->send_gcode($self->{send_gcode_file})) {
|
||||||
|
$self->statusbar->SetStatusText(L("OctoPrint upload finished."));
|
||||||
|
} else {
|
||||||
|
$self->statusbar->SetStatusText("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{print_file} = undef;
|
$self->{print_file} = undef;
|
||||||
|
@ -36,16 +36,20 @@ struct Http::priv
|
|||||||
::curl_slist *headerlist;
|
::curl_slist *headerlist;
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
size_t limit;
|
size_t limit;
|
||||||
|
bool cancel;
|
||||||
|
|
||||||
std::thread io_thread;
|
std::thread io_thread;
|
||||||
Http::CompleteFn completefn;
|
Http::CompleteFn completefn;
|
||||||
Http::ErrorFn errorfn;
|
Http::ErrorFn errorfn;
|
||||||
|
Http::ProgressFn progressfn;
|
||||||
|
|
||||||
priv(const std::string &url);
|
priv(const std::string &url);
|
||||||
~priv();
|
~priv();
|
||||||
|
|
||||||
static bool ca_file_supported(::CURL *curl);
|
static bool ca_file_supported(::CURL *curl);
|
||||||
static size_t writecb(void *data, size_t size, size_t nmemb, void *userp);
|
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 curl_error(CURLcode curlcode);
|
||||||
std::string body_size_error();
|
std::string body_size_error();
|
||||||
void http_perform();
|
void http_perform();
|
||||||
@ -55,7 +59,8 @@ Http::priv::priv(const std::string &url) :
|
|||||||
curl(::curl_easy_init()),
|
curl(::curl_easy_init()),
|
||||||
form(nullptr),
|
form(nullptr),
|
||||||
form_end(nullptr),
|
form_end(nullptr),
|
||||||
headerlist(nullptr)
|
headerlist(nullptr),
|
||||||
|
cancel(false)
|
||||||
{
|
{
|
||||||
if (curl == nullptr) {
|
if (curl == nullptr) {
|
||||||
throw std::runtime_error(std::string("Could not construct Curl object"));
|
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;
|
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)
|
std::string Http::priv::curl_error(CURLcode curlcode)
|
||||||
{
|
{
|
||||||
return (boost::format("%1% (%2%)")
|
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_WRITEFUNCTION, writecb);
|
||||||
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this));
|
::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
|
#ifndef NDEBUG
|
||||||
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
#endif
|
#endif
|
||||||
@ -149,16 +182,16 @@ void Http::priv::http_perform()
|
|||||||
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
|
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
|
||||||
|
|
||||||
if (res != CURLE_OK) {
|
if (res != CURLE_OK) {
|
||||||
std::string error;
|
if (res == CURLE_ABORTED_BY_CALLBACK) {
|
||||||
if (res == CURLE_WRITE_ERROR) {
|
Progress dummyprogress(0, 0, 0, 0);
|
||||||
error = std::move(body_size_error());
|
bool cancel = true;
|
||||||
} else {
|
if (progressfn) { progressfn(dummyprogress, cancel); }
|
||||||
error = std::move(curl_error(res));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (errorfn) {
|
|
||||||
errorfn(std::move(buffer), std::move(error), http_status);
|
|
||||||
}
|
}
|
||||||
|
else if (res == CURLE_WRITE_ERROR) {
|
||||||
|
if (errorfn) { errorfn(std::move(buffer), std::move(body_size_error()), http_status); }
|
||||||
|
} else {
|
||||||
|
if (errorfn) { errorfn(std::move(buffer), std::move(curl_error(res)), http_status); }
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
if (completefn) {
|
if (completefn) {
|
||||||
completefn(std::move(buffer), http_status);
|
completefn(std::move(buffer), http_status);
|
||||||
@ -258,6 +291,12 @@ Http& Http::on_error(ErrorFn fn)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Http& Http::on_progress(ProgressFn fn)
|
||||||
|
{
|
||||||
|
if (p) { p->progressfn = std::move(fn); }
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Http::Ptr Http::perform()
|
Http::Ptr Http::perform()
|
||||||
{
|
{
|
||||||
auto self = std::make_shared<Http>(std::move(*this));
|
auto self = std::make_shared<Http>(std::move(*this));
|
||||||
@ -277,6 +316,11 @@ void Http::perform_sync()
|
|||||||
if (p) { p->http_perform(); }
|
if (p) { p->http_perform(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Http::cancel()
|
||||||
|
{
|
||||||
|
if (p) { p->cancel = true; }
|
||||||
|
}
|
||||||
|
|
||||||
Http Http::get(std::string url)
|
Http Http::get(std::string url)
|
||||||
{
|
{
|
||||||
return std::move(Http{std::move(url)});
|
return std::move(Http{std::move(url)});
|
||||||
@ -297,5 +341,16 @@ bool Http::ca_file_supported()
|
|||||||
return res;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,22 @@ class Http : public std::enable_shared_from_this<Http> {
|
|||||||
private:
|
private:
|
||||||
struct priv;
|
struct priv;
|
||||||
public:
|
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::shared_ptr<Http> Ptr;
|
||||||
typedef std::function<void(std::string /* body */, unsigned /* http_status */)> CompleteFn;
|
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(std::string /* body */, std::string /* error */, unsigned /* http_status */)> ErrorFn;
|
||||||
|
typedef std::function<void(Progress, bool& /* cancel */)> ProgressFn;
|
||||||
|
|
||||||
Http(Http &&other);
|
Http(Http &&other);
|
||||||
|
|
||||||
@ -37,9 +50,11 @@ public:
|
|||||||
|
|
||||||
Http& on_complete(CompleteFn fn);
|
Http& on_complete(CompleteFn fn);
|
||||||
Http& on_error(ErrorFn fn);
|
Http& on_error(ErrorFn fn);
|
||||||
|
Http& on_progress(ProgressFn fn);
|
||||||
|
|
||||||
Ptr perform();
|
Ptr perform();
|
||||||
void perform_sync();
|
void perform_sync();
|
||||||
|
void cancel();
|
||||||
|
|
||||||
static bool ca_file_supported();
|
static bool ca_file_supported();
|
||||||
private:
|
private:
|
||||||
@ -48,6 +63,8 @@ private:
|
|||||||
std::unique_ptr<priv> p;
|
std::unique_ptr<priv> p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream &, const Http::Progress &);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include "OctoPrint.hpp"
|
#include "OctoPrint.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <algorithm>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
|
#include <wx/progdlg.h>
|
||||||
|
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
@ -39,36 +40,53 @@ bool OctoPrint::test(wxString &msg) const
|
|||||||
return res;
|
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")));
|
auto http = Http::post(std::move(make_url("api/files/local")));
|
||||||
set_auth(http);
|
set_auth(http);
|
||||||
http.form_add("print", print ? "true" : "false")
|
http.form_add("print", print ? "true" : "false")
|
||||||
.form_add_file("file", filename)
|
.form_add_file("file", filename)
|
||||||
.on_complete([=](std::string body, unsigned status) {
|
.on_complete([&](std::string body, unsigned status) {
|
||||||
wxWindow *window = wxWindow::FindWindowById(windowId);
|
progress_dialog.Update(PROGRESS_RANGE);
|
||||||
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_error([=](std::string body, std::string error, unsigned status) {
|
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||||
wxWindow *window = wxWindow::FindWindowById(windowId);
|
auto errormsg = wxString::Format("%s: %s", errortitle, format_error(error, status));
|
||||||
if (window == nullptr) { return; }
|
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||||
|
res = false;
|
||||||
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);
|
|
||||||
})
|
})
|
||||||
.perform();
|
.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_sync();
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctoPrint::set_auth(Http &http) const
|
void OctoPrint::set_auth(Http &http) const
|
||||||
|
@ -17,7 +17,7 @@ public:
|
|||||||
OctoPrint(DynamicPrintConfig *config);
|
OctoPrint(DynamicPrintConfig *config);
|
||||||
|
|
||||||
bool test(wxString &curl_msg) const;
|
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:
|
private:
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string apikey;
|
std::string apikey;
|
||||||
|
@ -9,5 +9,5 @@
|
|||||||
OctoPrint(DynamicPrintConfig *config);
|
OctoPrint(DynamicPrintConfig *config);
|
||||||
~OctoPrint();
|
~OctoPrint();
|
||||||
|
|
||||||
void send_gcode(int windowId, int completeEvt, int errorEvt, std::string filename, bool print = false) const;
|
bool send_gcode(std::string filename, bool print = false) const;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user