#include "FlashAir.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/MsgDialog.hpp" #include "Http.hpp" namespace fs = boost::filesystem; namespace pt = boost::property_tree; namespace Slic3r { FlashAir::FlashAir(DynamicPrintConfig *config) : host(config->opt_string("print_host")) {} const char* FlashAir::get_name() const { return "FlashAir"; } bool FlashAir::test(wxString &msg) const { // Since the request is performed synchronously here, // it is ok to refer to `msg` from within the closure const char *name = get_name(); bool res = false; auto url = make_url("command.cgi", "op", "118"); BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get upload enabled at: %2%") % name % url; auto http = Http::get(std::move(url)); http.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting upload enabled: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; res = false; msg = format_error(body, error, status); }) .on_complete([&](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got upload enabled: %2%") % name % body; res = boost::starts_with(body, "1"); if (! res) { msg = _(L("Upload not enabled on FlashAir card.")); } }) .perform_sync(); return res; } wxString FlashAir::get_test_ok_msg () const { return _(L("Connection to FlashAir works correctly and upload is enabled.")); } wxString FlashAir::get_test_failed_msg (wxString &msg) const { return GUI::from_u8((boost::format("%s: %s\n%s") % _utf8(L("Could not connect to FlashAir")) % std::string(msg.ToUTF8()) % _utf8(L("Note: FlashAir with firmware 2.00.02 or newer and activated upload function is required."))).str()); } bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { const char *name = get_name(); const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); wxString test_msg; if (! test(test_msg)) { error_fn(std::move(test_msg)); return false; } bool res = false; std::string strDest = upload_parent_path.string(); if (strDest.front()!='/') // Needs a leading / else root uploads fail. { strDest.insert(0,"/"); } auto urlPrepare = make_url("upload.cgi", "WRITEPROTECT=ON&FTIME", timestamp_str()); auto urlSetDir = make_url("upload.cgi","UPDIR",strDest); auto urlUpload = make_url("upload.cgi"); BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3% / %4%, filename: %5%") % name % upload_data.source_path % urlPrepare % urlUpload % upload_filename.string(); // set filetime for upload and make card writeprotect to prevent filesystem damage auto httpPrepare = Http::get(std::move(urlPrepare)); httpPrepare.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error preparing upload: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; error_fn(format_error(body, error, status)); res = false; }) .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got prepare result: %2%") % name % body; res = boost::icontains(body, "SUCCESS"); if (! res) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Request completed but no SUCCESS message was received.") % name; error_fn(format_error(body, L("Unknown error occured"), 0)); } }) .perform_sync(); if(! res ) { return res; } // start file upload auto httpDir = Http::get(std::move(urlSetDir)); httpDir.on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error setting upload dir: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; error_fn(format_error(body, error, status)); res = false; }) .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got dir select result: %2%") % name % body; res = boost::icontains(body, "SUCCESS"); if (! res) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Request completed but no SUCCESS message was received.") % name; error_fn(format_error(body, L("Unknown error occured"), 0)); } }) .perform_sync(); if(! res ) { return res; } auto http = Http::post(std::move(urlUpload)); http.form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: File uploaded: HTTP %2%: %3%") % name % status % body; res = boost::icontains(body, "SUCCESS"); if (! res) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Request completed but no SUCCESS message was received.") % name; error_fn(format_error(body, L("Unknown error occured"), 0)); } }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file: %2%, HTTP %3%, body: `%4%`") % name % error % status % body; error_fn(format_error(body, error, status)); res = false; }) .on_progress([&](Http::Progress progress, bool &cancel) { prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Upload canceled") % name; res = false; } }) .perform_sync(); return res; } std::string FlashAir::timestamp_str() const { auto t = std::time(nullptr); auto tm = *std::localtime(&t); unsigned long fattime = ((tm.tm_year - 80) << 25) | ((tm.tm_mon + 1) << 21) | (tm.tm_mday << 16) | (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); return (boost::format("%1$#x") % fattime).str(); } std::string FlashAir::make_url(const std::string &path) const { if (host.find("http://") == 0 || host.find("https://") == 0) { if (host.back() == '/') { return (boost::format("%1%%2%") % host % path).str(); } else { return (boost::format("%1%/%2%") % host % path).str(); } } else { if (host.back() == '/') { return (boost::format("http://%1%%2%") % host % path).str(); } else { return (boost::format("http://%1%/%2%") % host % path).str(); } } } std::string FlashAir::make_url(const std::string &path, const std::string &arg, const std::string &val) const { if (host.find("http://") == 0 || host.find("https://") == 0) { if (host.back() == '/') { return (boost::format("%1%%2%?%3%=%4%") % host % path % arg % val).str(); } else { return (boost::format("%1%/%2%?%3%=%4%") % host % path % arg % val).str(); } } else { if (host.back() == '/') { return (boost::format("http://%1%%2%?%3%=%4%") % host % path % arg % val).str(); } else { return (boost::format("http://%1%/%2%?%3%=%4%") % host % path % arg % val).str(); } } } }