PrusaSlicer-NonPlainar/src/slic3r/Utils/PrintHost.cpp

178 lines
4.8 KiB
C++
Raw Normal View History

#include "PrintHost.hpp"
2018-12-11 09:33:11 +00:00
#include <vector>
#include <thread>
#include <boost/optional.hpp>
#include <boost/log/trivial.hpp>
#include <boost/filesystem.hpp>
#include <wx/app.h>
2018-12-11 09:33:11 +00:00
#include "libslic3r/PrintConfig.hpp"
2018-12-11 09:33:11 +00:00
#include "libslic3r/Channel.hpp"
#include "OctoPrint.hpp"
#include "Duet.hpp"
#include "../GUI/PrintHostDialogs.hpp"
2018-12-11 09:33:11 +00:00
namespace fs = boost::filesystem;
2018-12-11 09:33:11 +00:00
using boost::optional;
using Slic3r::GUI::PrintHostQueueDialog;
namespace Slic3r {
2018-08-21 09:10:32 +00:00
PrintHost::~PrintHost() {}
PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
{
2018-12-18 13:34:16 +00:00
const auto opt = config->option<ConfigOptionEnum<PrintHostType>>("host_type");
if (opt == nullptr) { return nullptr; }
switch (opt->value) {
case htOctoPrint: return new OctoPrint(config);
case htSL1: return new SL1Host(config);
case htDuet: return new Duet(config);
default: return nullptr;
2018-12-11 09:33:11 +00:00
}
}
struct PrintHostJobQueue::priv
{
// XXX: comment on how bg thread works
PrintHostJobQueue *q;
Channel<PrintHostJob> channel_jobs;
Channel<size_t> channel_cancels;
size_t job_id = 0;
int prev_progress = -1;
2018-12-11 09:33:11 +00:00
std::thread bg_thread;
bool bg_exit = false;
PrintHostQueueDialog *queue_dialog;
priv(PrintHostJobQueue *q) : q(q) {}
void start_bg_thread();
void bg_thread_main();
void progress_fn(Http::Progress progress, bool &cancel);
void error_fn(std::string body, std::string error, unsigned http_status);
void perform_job(PrintHostJob the_job);
2018-12-11 09:33:11 +00:00
};
PrintHostJobQueue::PrintHostJobQueue(PrintHostQueueDialog *queue_dialog)
: p(new priv(this))
2018-12-11 09:33:11 +00:00
{
p->queue_dialog = queue_dialog;
2018-12-11 09:33:11 +00:00
}
PrintHostJobQueue::~PrintHostJobQueue()
{
if (p && p->bg_thread.joinable()) {
p->bg_exit = true;
p->channel_jobs.push(PrintHostJob()); // Push an empty job to wake up bg_thread in case it's sleeping
p->bg_thread.detach(); // Let the background thread go, it should exit on its own
}
}
void PrintHostJobQueue::priv::start_bg_thread()
{
if (bg_thread.joinable()) { return; }
std::shared_ptr<priv> p2 = q->p;
bg_thread = std::thread([p2]() {
p2->bg_thread_main();
});
}
void PrintHostJobQueue::priv::bg_thread_main()
{
// bg thread entry point
try {
// Pick up jobs from the job channel:
while (! bg_exit) {
auto job = channel_jobs.pop(); // Sleeps in a cond var if there are no jobs
if (! job.cancelled) {
perform_job(std::move(job));
}
job_id++;
}
} catch (...) {
wxTheApp->OnUnhandledException();
}
}
void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel)
{
if (bg_exit) {
cancel = true;
return;
}
if (channel_cancels.size_hint() > 0) {
// Lock both queues
auto cancels = channel_cancels.lock_rw();
auto jobs = channel_jobs.lock_rw();
for (size_t cancel_id : *cancels) {
if (cancel_id == job_id) {
cancel = true;
} else if (cancel_id > job_id) {
jobs->at(cancel_id - job_id).cancelled = true;
}
}
cancels->clear();
}
int gui_progress = progress.ultotal > 0 ? 100*progress.ulnow / progress.ultotal : 0;
if (gui_progress != prev_progress) {
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, gui_progress);
wxQueueEvent(queue_dialog, evt);
prev_progress = gui_progress;
}
}
void PrintHostJobQueue::priv::error_fn(std::string body, std::string error, unsigned http_status)
{
// TODO
}
void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
{
if (bg_exit || the_job.empty()) { return; }
BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%1%`")
% the_job.upload_data.upload_path
% the_job.printhost->get_host();
const fs::path gcode_path = the_job.upload_data.source_path;
the_job.printhost->upload(std::move(the_job.upload_data),
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
[this](std::string body, std::string error, unsigned http_status) { this->error_fn(std::move(body), std::move(error), http_status); }
);
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100);
wxQueueEvent(queue_dialog, evt);
boost::system::error_code ec;
fs::remove(gcode_path, ec);
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("PrintHostJobQueue: Error removing file `%1%`: %2%") % gcode_path % ec;
}
}
void PrintHostJobQueue::enqueue(PrintHostJob job)
{
p->start_bg_thread();
p->queue_dialog->append_job(job);
p->channel_jobs.push(std::move(job));
}
2018-08-21 09:10:32 +00:00
}