From 8c941df4e8c7e298a24eeba17b1837576fb55fad Mon Sep 17 00:00:00 2001 From: Kenneth Jiang Date: Tue, 27 Feb 2024 06:04:51 -0800 Subject: [PATCH] Support for Obico cloud integration (#4116) support obico (#3) Add printer support for Obico cloud. --------- Co-authored-by: zzh --- src/libslic3r/PrintConfig.cpp | 5 +- src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/CMakeLists.txt | 4 + src/slic3r/GUI/PhysicalPrinterDialog.cpp | 77 ++++++++ src/slic3r/GUI/PhysicalPrinterDialog.hpp | 1 + src/slic3r/GUI/PrinterCloudAuthDialog.cpp | 105 +++++++++++ src/slic3r/GUI/PrinterCloudAuthDialog.hpp | 51 +++++ src/slic3r/Utils/Obico.cpp | 218 ++++++++++++++++++++++ src/slic3r/Utils/Obico.hpp | 51 +++++ src/slic3r/Utils/PrintHost.cpp | 2 + src/slic3r/Utils/PrintHost.hpp | 5 + 11 files changed, 519 insertions(+), 2 deletions(-) create mode 100644 src/slic3r/GUI/PrinterCloudAuthDialog.cpp create mode 100644 src/slic3r/GUI/PrinterCloudAuthDialog.hpp create mode 100644 src/slic3r/Utils/Obico.cpp create mode 100644 src/slic3r/Utils/Obico.hpp diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0068e33b9ba..f07b0de3ae0 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -102,7 +102,8 @@ static t_config_enum_values s_keys_map_PrintHostType { { "flashair", htFlashAir }, { "astrobox", htAstroBox }, { "repetier", htRepetier }, - { "mks", htMKS } + { "mks", htMKS }, + { "obico", htObico } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType) @@ -3038,6 +3039,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_values.push_back("astrobox"); def->enum_values.push_back("repetier"); def->enum_values.push_back("mks"); + def->enum_values.push_back("obico"); def->enum_labels.push_back("PrusaLink"); def->enum_labels.push_back("PrusaConnect"); def->enum_labels.push_back("Octo/Klipper"); @@ -3046,6 +3048,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_labels.push_back("AstroBox"); def->enum_labels.push_back("Repetier"); def->enum_labels.push_back("MKS"); + def->enum_labels.push_back("Obico"); def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(htOctoPrint)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 4d1d8112acb..b4955abc840 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -59,7 +59,7 @@ enum class FuzzySkinType { }; enum PrintHostType { - htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS + htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htObico }; enum AuthorizationType { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 39f37e89b20..0b1526f1ee6 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -524,6 +524,10 @@ set(SLIC3R_GUI_SOURCES GUI/calib_dlg.cpp Utils/CalibUtils.cpp Utils/CalibUtils.hpp + GUI/PrinterCloudAuthDialog.cpp + GUI/PrinterCloudAuthDialog.hpp + Utils/Obico.cpp + Utils/Obico.hpp ) if (WIN32) diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index bfd47e9835a..7b754644964 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -1,10 +1,12 @@ #include "PhysicalPrinterDialog.hpp" #include "PresetComboBoxes.hpp" +#include "PrinterCloudAuthDialog.hpp" #include #include #include #include +#include #include #include @@ -124,6 +126,8 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr this->update(); if (opt_key == "print_host") this->update_printhost_buttons(); + if (opt_key == "printhost_port") + this->update_ports(); }; m_optgroup->append_single_option_line("host_type"); @@ -161,12 +165,31 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr show_error(this, text); return; } + wxString msg; bool result; { // Show a wait cursor during the connection test, as it is blocking UI. wxBusyCursor wait; result = host->test(msg); + + if (!result && host->is_cloud()) { + PrinterCloudAuthDialog dlg(this->GetParent(), host.get()); + dlg.ShowModal(); + + auto api_key = dlg.GetApiKey(); + m_config->opt_string("printhost_apikey") = api_key; + result = !api_key.empty(); + if (result) { + if (Field* print_host_webui_field = this->m_optgroup->get_field("printhost_apikey"); print_host_webui_field) { + if (TextInput* temp_input = dynamic_cast(print_host_webui_field->getWindow()); temp_input) { + if (wxTextCtrl* temp = temp_input->GetTextCtrl()) { + temp->SetValue(wxString(api_key)); + } + } + } + } + } } if (result) show_info(this, host->get_test_ok_msg(), _L("Success!")); @@ -311,6 +334,42 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr update(); } +void PhysicalPrinterDialog::update_ports() { + const PrinterTechnology tech = Preset::printer_technology(*m_config); + if (tech == ptFFF) { + const auto opt = m_config->option>("host_type"); + if (opt->value == htObico) { + auto build_web_ui = [](DynamicPrintConfig* config) { + auto host = config->opt_string("print_host"); + auto port = config->opt_string("printhost_port"); + auto api_key = config->opt_string("printhost_apikey"); + if (host.empty() || port.empty()) { + return std::string(); + } + boost::regex re("\\[(\\d+)\\]"); + boost::smatch match; + if (!boost::regex_search(port, match, re)) + return std::string(); + if (match.size() <= 1) { + return std::string(); + } + boost::format urlFormat("%1%/printers/%2%/control"); + urlFormat % host % match[1]; + return urlFormat.str(); + }; + auto url = build_web_ui(m_config); + if (Field* print_host_webui_field = m_optgroup->get_field("print_host_webui"); print_host_webui_field) { + if (TextInput* temp_input = dynamic_cast(print_host_webui_field->getWindow()); temp_input) { + if (wxTextCtrl* temp = temp_input->GetTextCtrl()) { + temp->SetValue(wxString(url)); + m_config->opt_string("print_host_webui") = url; + } + } + } + } + } +} + void PhysicalPrinterDialog::update_printhost_buttons() { std::unique_ptr host(PrintHost::get_print_host(m_config)); @@ -415,6 +474,12 @@ void PhysicalPrinterDialog::update(bool printer_change) if (wxTextCtrl* temp = dynamic_cast(printhost_field->getWindow()); temp && temp->GetValue() == L"https://connect.prusa3d.com") { temp->SetValue(wxString()); } + + if (TextInput* temp_input = dynamic_cast(printhost_field->getWindow()); temp_input) { + if (wxTextCtrl* temp = temp_input->GetTextCtrl(); temp &&temp->GetValue() == L"https://app.obico.io") { + temp->SetValue(wxString()); + } + } } if (opt->value == htPrusaLink) { // PrusaConnect does NOT allow http digest m_optgroup->show_field("printhost_authorization_type"); @@ -436,6 +501,18 @@ void PhysicalPrinterDialog::update(bool printer_change) } } } + + if (opt->value == htObico) { + supports_multiple_printers = true; + if (Field* printhost_field = m_optgroup->get_field("print_host"); printhost_field) { + if (TextInput* temp_input = dynamic_cast(printhost_field->getWindow()); temp_input) { + if (wxTextCtrl* temp = temp_input->GetTextCtrl(); temp && temp->GetValue().IsEmpty()) { + temp->SetValue(L"https://app.obico.io"); + m_config->opt_string("print_host") = "https://app.obico.io"; + } + } + } + } } else { m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false); diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp index 93cd3f4aa90..9a38e7d8dbf 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp @@ -61,6 +61,7 @@ class PhysicalPrinterDialog : public DPIDialog void update_preset_input(); void update_printhost_buttons(); void update_printers(); + void update_ports(); protected: void on_dpi_changed(const wxRect& suggested_rect) override; diff --git a/src/slic3r/GUI/PrinterCloudAuthDialog.cpp b/src/slic3r/GUI/PrinterCloudAuthDialog.cpp new file mode 100644 index 00000000000..f46aa3c2bf6 --- /dev/null +++ b/src/slic3r/GUI/PrinterCloudAuthDialog.cpp @@ -0,0 +1,105 @@ +#include "PrinterCloudAuthDialog.hpp" +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include "MainFrame.hpp" +#include + +#include +#include +//------------------------------------------ +// PrinterCloundAuthDialog +//------------------------------------------ +namespace Slic3r { namespace GUI { + +PrinterCloudAuthDialog::PrinterCloudAuthDialog(wxWindow* parent, PrintHost* host) + : wxDialog((wxWindow*) (wxGetApp().mainframe), wxID_ANY, "Login"), m_host(host) +{ + SetBackgroundColour(*wxWHITE); + // Url + host->get_login_url(m_TargetUrl); + BOOST_LOG_TRIVIAL(info) << "login url = " << m_TargetUrl.ToStdString(); + + // Create the webview + m_browser = WebView::CreateWebView(this, m_TargetUrl); + if (m_browser == nullptr) { + wxLogError("Could not init m_browser"); + return; + } + m_browser->Hide(); + m_browser->SetSize(0, 0); + + // Connect the webview events + Bind(wxEVT_WEBVIEW_NAVIGATING, &PrinterCloudAuthDialog::OnNavigationRequest, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NAVIGATED, &PrinterCloudAuthDialog::OnNavigationComplete, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_LOADED, &PrinterCloudAuthDialog::OnDocumentLoaded, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NEWWINDOW, &PrinterCloudAuthDialog::OnNewWindow, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterCloudAuthDialog::OnScriptMessage, this, m_browser->GetId()); + + // UI + SetTitle(_L("Login")); + // Set a more sensible size for web browsing + wxSize pSize = FromDIP(wxSize(650, 840)); + SetSize(pSize); + + int screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL); + int screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL); + int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0; + wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY); + Move(tmpPT); +} + +PrinterCloudAuthDialog::~PrinterCloudAuthDialog() {} + +void PrinterCloudAuthDialog::OnNavigationRequest(wxWebViewEvent& evt) +{ + //todo +} + +void PrinterCloudAuthDialog::OnNavigationComplete(wxWebViewEvent& evt) +{ + m_browser->Show(); + Layout(); + //fortest + //WebView::RunScript(m_browser, "window.wx.postMessage('This is a web message')"); +} + +void PrinterCloudAuthDialog::OnDocumentLoaded(wxWebViewEvent& evt) +{ + // todo +} + +void PrinterCloudAuthDialog::OnNewWindow(wxWebViewEvent& evt) { + +} + +void PrinterCloudAuthDialog::OnScriptMessage(wxWebViewEvent& evt) +{ + wxString str_input = evt.GetString(); + try { + json j = json::parse(into_u8(str_input)); + wxString strCmd = j["command"]; + if (strCmd == "login_token") { + auto token = j["data"]["token"]; + m_host->set_api_key(token); + m_apikey = token; + } + Close(); + } catch (std::exception& e) { + wxMessageBox(e.what(), "parse json failed", wxICON_WARNING); + Close(); + } +} + +} +} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/PrinterCloudAuthDialog.hpp b/src/slic3r/GUI/PrinterCloudAuthDialog.hpp new file mode 100644 index 00000000000..9da01b32066 --- /dev/null +++ b/src/slic3r/GUI/PrinterCloudAuthDialog.hpp @@ -0,0 +1,51 @@ +#ifndef slic3r_GUI_PrinterCloudAuthDialog_hpp_ +#define slic3r_GUI_PrinterCloudAuthDialog_hpp_ + +#include +#include +#include +#include +#include +#include +#include "wx/webview.h" + +#if wxUSE_WEBVIEW_IE +#include "wx/msw/webview_ie.h" +#endif +#if wxUSE_WEBVIEW_EDGE +#include "wx/msw/webview_edge.h" +#endif + +#include "GUI_Utils.hpp" +#include "PrintHost.hpp" + +namespace Slic3r { namespace GUI { + +class PrinterCloudAuthDialog : public wxDialog +{ +protected: + wxWebView* m_browser; + wxString m_TargetUrl; + + wxString m_javascript; + wxString m_response_js; + PrintHost* m_host; + std::string m_apikey; + +public: + PrinterCloudAuthDialog(wxWindow* parent, PrintHost* host); + ~PrinterCloudAuthDialog(); + + std::string GetApiKey() { return m_apikey; }; + + void OnNavigationRequest(wxWebViewEvent& evt); + void OnNavigationComplete(wxWebViewEvent& evt); + void OnDocumentLoaded(wxWebViewEvent& evt); + void OnNewWindow(wxWebViewEvent& evt); + void OnScriptMessage(wxWebViewEvent& evt); + +}; + +}} // namespace Slic3r::GUI + +#endif \ No newline at end of file diff --git a/src/slic3r/Utils/Obico.cpp b/src/slic3r/Utils/Obico.cpp new file mode 100644 index 00000000000..edd439f3bb9 --- /dev/null +++ b/src/slic3r/Utils/Obico.cpp @@ -0,0 +1,218 @@ +#include "Obico.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/format.hpp" +#include "Http.hpp" +#include "libslic3r/AppConfig.hpp" +#include "Bonjour.hpp" +#include "slic3r/GUI/BonjourDialog.hpp" + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + + +namespace Slic3r { + +Obico::Obico(DynamicPrintConfig* config) : + m_host(config->opt_string("print_host")), + m_web_ui(config->opt_string("print_host_webui")), + m_cafile(config->opt_string("printhost_cafile")), + m_port(config->opt_string("printhost_port")), + m_apikey(config->opt_string("printhost_apikey")), + m_ssl_revoke_best_effort(config->opt_bool("printhost_ssl_ignore_revoke")) +{} + +const char* Obico::get_name() const { return "Obico"; } + +void Obico::set_api_key(const std::string auth_api_key) { m_apikey = auth_api_key; } + +std::string Obico::get_host() const { + return m_host; +} +void Obico::set_auth(Http& http) const +{ + http.header("Authorization", "Bearer " + m_apikey); + if (!m_cafile.empty()) { + http.ca_file(m_cafile); + } +} + +bool Obico::get_login_url(wxString& auth_url) const +{ + auth_url = make_url("o/authorize?response_type=token&client_id=OrcaSlicer&hide_navbar=true"); + return true; +} + +wxString Obico::get_test_ok_msg() const { return _(L("Connected to Obico successfully!")); } + +wxString Obico::get_test_failed_msg(wxString& msg) const +{ + return GUI::format_wxstr("%s: %s", _L("Could not connect to Obico"), msg.Truncate(256)); +} + +bool Obico::test(wxString& msg) const +{ + if (m_apikey.empty()) { + return false; + } + + bool res = true; + const char* name = get_name(); + auto url = make_url("api/v1/version/"); + + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; + // Here we do not have to add custom "Host" header - the url contains host filled by user and libCurl will set the header by itself. + auto http = Http::get(std::move(url)); + set_auth(http); + http.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % + body; + res = false; + msg = format_error(body, error, status); + }) + .on_complete([&, this](std::string body, unsigned) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body; + }) +#ifdef WIN32 + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) + .on_ip_resolve([&](std::string address) { + // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. + // Remember resolved address to be reused at successive REST API call. + msg = GUI::from_u8(address); + }) +#endif // WIN32 + .perform_sync(); + + return res; +} + +bool Obico::get_printers(wxArrayString& printers) const +{ + const char* name = get_name(); + bool res = false; + auto url = make_url("api/v1/printers/"); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: List printers at: %2%") % name % url; + + auto http = Http::get(std::move(url)); + set_auth(http); + + http.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error listing printers: %2%, HTTP %3%, body: `%4%`") % name % error % status % + body; + }) + .on_complete([&](std::string body, unsigned http_status) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got printers: %2%, HTTP status: %3%") % name % body % http_status; + if (http_status != 200) + throw HostNetworkError(GUI::format(_L("HTTP status: %1%\nMessage body: \"%2%\""), http_status, body)); + + std::stringstream ss(body); + pt::ptree ptree; + try { + pt::read_json(ss, ptree); + } catch (const pt::ptree_error& err) { + throw HostNetworkError( + GUI::format(_L("Parsing of host response failed.\nMessage body: \"%1%\"\nError: \"%2%\""), body, err.what())); + } + + const auto error = ptree.get_optional("error"); + if (error) + throw HostNetworkError(*error); + + try { + BOOST_FOREACH (boost::property_tree::ptree::value_type& v, ptree) { + const auto name = v.second.get("name"); + const auto port = v.second.get("id"); + printers.push_back(Slic3r::GUI::from_u8(name + " [" + port + "]")); + } + } catch (const std::exception& err) { + throw HostNetworkError( + GUI::format(_L("Enumeration of host printers failed.\nMessage body: \"%1%\"\nError: \"%2%\""), body, err.what())); + } + res = true; + }) + .perform_sync(); + + return res; +} + +PrintHostPostUploadActions Obico::get_post_upload_actions() const { + return PrintHostPostUploadAction::StartPrint; +} + +bool Obico::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_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 = true; + auto url = make_url("api/v1/g_code_files/"); + + auto http = Http::post(url); // std::move(url)); + set_auth(http); + http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") + .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? + .form_add("printer_id", m_port) + .form_add("filename", upload_filename.string()) + .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; + }) + .on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file to %2%: %3%, HTTP %4%, body: `%5%`") % name % url % 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) << name << ": Upload canceled"; + res = false; + } + }) +#ifdef WIN32 + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) +#endif + .perform_sync(); + return res; +} + +std::string Obico::make_url(const std::string& path) const +{ + if (m_host.find("http://") == 0 || m_host.find("https://") == 0) { + if (m_host.back() == '/') { + return (boost::format("%1%%2%") % m_host % path).str(); + } else { + return (boost::format("%1%/%2%") % m_host % path).str(); + } + } else { + return (boost::format("http://%1%/%2%") % m_host % path).str(); + } +} +} diff --git a/src/slic3r/Utils/Obico.hpp b/src/slic3r/Utils/Obico.hpp new file mode 100644 index 00000000000..c8c6e3a73d9 --- /dev/null +++ b/src/slic3r/Utils/Obico.hpp @@ -0,0 +1,51 @@ +#ifndef slic3r_Obico_hpp_ +#define slic3r_Obico_hpp_ + +#include +#include +#include +#include + +#include "PrintHost.hpp" +#include "libslic3r/PrintConfig.hpp" + +namespace Slic3r { + +class DynamicPrintConfig; +class Http; +class Obico : public PrintHost +{ +public: + Obico(DynamicPrintConfig* config); + ~Obico() override = default; + + const char* get_name() const override; + virtual bool can_test() const { return true; }; + bool has_auto_discovery() const override { return false; } + bool is_cloud() const override { return true; } + bool get_login_url(wxString& auth_url) const override; + void set_api_key(const std::string auth_api_key) override; + std::string get_host() const override; + + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString& msg) const override; + virtual bool test(wxString& curl_msg) const override; + bool get_printers(wxArrayString& printers) const override; + PrintHostPostUploadActions get_post_upload_actions() const; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; + +protected: + virtual void set_auth(Http& http) const; +private: + std::string m_host; + std::string m_port; + std::string m_apikey; + std::string m_cafile; + std::string m_web_ui; + bool m_ssl_revoke_best_effort; + + std::string make_url(const std::string& path) const; +}; +} // namespace Slic3r + +#endif \ No newline at end of file diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index c8f0e34bcaf..7b66f40800c 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -20,6 +20,7 @@ #include "Repetier.hpp" #include "MKS.hpp" #include "../GUI/PrintHostDialogs.hpp" +#include "Obico.hpp" namespace fs = boost::filesystem; using boost::optional; @@ -54,6 +55,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htPrusaLink: return new PrusaLink(config); case htPrusaConnect: return new PrusaConnect(config); case htMKS: return new MKS(config); + case htObico: return new Obico(config); default: return nullptr; } } else { diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index becaf138b49..ea5c8a3bafd 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -70,6 +70,11 @@ class PrintHost static PrintHost* get_print_host(DynamicPrintConfig *config); + //Support for cloud webui login + virtual bool is_cloud() const { return false; } + virtual bool get_login_url(wxString& auth_url) const { return false; } + virtual void set_api_key(const std::string auth_api_key) {} + protected: virtual wxString format_error(const std::string &body, const std::string &error, unsigned status) const; };