mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 20:51:12 -06:00 
			
		
		
		
	NEW: add Device view for third-party printers
cherry-picked from SoftFever Change-Id: I36b2fa0227886e4fac494c8b83e12f4fc0b04e17 Signed-off-by: Stone Li <stone.li@bambulab.com>
This commit is contained in:
		
							parent
							
								
									5f04066ac0
								
							
						
					
					
						commit
						efd65561a2
					
				
					 27 changed files with 1797 additions and 60 deletions
				
			
		
							
								
								
									
										25
									
								
								resources/web/device/css/dark.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								resources/web/device/css/dark.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | body { | ||||||
|  |     background-color:#4c4c54; | ||||||
|  |     font-family: Arial, sans-serif; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     height: 100vh; | ||||||
|  |     margin: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .container { | ||||||
|  |     text-align: center; | ||||||
|  |     padding: 30px; | ||||||
|  |     border-radius: 10px; | ||||||
|  |     background-color: #272727; | ||||||
|  |     box-shadow: 0 4px 6px rgba(39, 39, 39, 0.1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | h1 { | ||||||
|  |     color: #ffffff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | p { | ||||||
|  |     color: #ffffff; | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								resources/web/device/css/home.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								resources/web/device/css/home.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | body | ||||||
|  | { | ||||||
|  |     background-color:#eeeeee; | ||||||
|  |     font-family: Arial, sans-serif; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     height: 100vh; | ||||||
|  |     margin: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .container { | ||||||
|  |     text-align: center; | ||||||
|  |     padding: 30px; | ||||||
|  |     border-radius: 10px; | ||||||
|  |     background-color: #ffffff; | ||||||
|  |     box-shadow: 0 4px 6px rgba(39, 39, 39, 0.1); | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								resources/web/device/missing_connection.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								resources/web/device/missing_connection.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | <!doctype html> | ||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  | <meta charset="utf-8"> | ||||||
|  | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  | <title>Printer Connection Required</title> | ||||||
|  | <link rel="stylesheet" type="text/css" href="css/home.css" /> | ||||||
|  | <link rel="stylesheet" type="text/css" href="css/dark.css" /> | ||||||
|  | <script type="text/javascript" src="../data/text.js"></script>	 | ||||||
|  | <script type="text/javascript" src="../homepage/js/jquery-3.6.0.min.js"></script> | ||||||
|  | <script type="text/javascript" src="../homepage/js/json2.js"></script> | ||||||
|  | <script type="text/javascript" src="../homepage/js/globalapi.js"></script> | ||||||
|  | <script type="text/javascript" src="../homepage/js/home.js"></script> | ||||||
|  | </head> | ||||||
|  | <body onLoad="OnInit()"> | ||||||
|  |     <div class="container"> | ||||||
|  |         <h1 class="trans" tid="t93">Printer Connection</h1> | ||||||
|  |         <p class="trans" tid="t94">Please set up your printer connection to view the device.</p> | ||||||
|  |         <img src="setup_connection.gif" alt="Printer connection setup demonstration" style="max-width: 100%; height: auto; display: block;"/> | ||||||
|  |     </div> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/web/device/setup_connection.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/web/device/setup_connection.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 927 KiB | 
|  | @ -804,6 +804,7 @@ static std::vector<std::string> s_Preset_printer_options { | ||||||
|     "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", |     "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", | ||||||
|     //SoftFever
 |     //SoftFever
 | ||||||
|     "host_type", "print_host", "printhost_apikey", |     "host_type", "print_host", "printhost_apikey", | ||||||
|  |     "print_host_webui", | ||||||
|     "printhost_cafile","printhost_port","printhost_authorization_type", |     "printhost_cafile","printhost_port","printhost_authorization_type", | ||||||
|     "printhost_user", "printhost_password", "printhost_ssl_ignore_revoke" |     "printhost_user", "printhost_password", "printhost_ssl_ignore_revoke" | ||||||
| }; | }; | ||||||
|  | @ -1694,6 +1695,11 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset( | ||||||
| { | { | ||||||
|     // Load the preset over a default preset, so that the missing fields are filled in from the default preset.
 |     // Load the preset over a default preset, so that the missing fields are filled in from the default preset.
 | ||||||
|     DynamicPrintConfig cfg(this->default_preset_for(combined_config).config); |     DynamicPrintConfig cfg(this->default_preset_for(combined_config).config); | ||||||
|  |     // SoftFever: ignore print connection info from project
 | ||||||
|  |     cfg.erase("print_host"); | ||||||
|  |     cfg.erase("print_host_webui"); | ||||||
|  |     cfg.erase("printhost_apikey"); | ||||||
|  |     cfg.erase("printhost_cafile"); | ||||||
|     const auto        &keys = cfg.keys(); |     const auto        &keys = cfg.keys(); | ||||||
|     cfg.apply_only(combined_config, keys, true); |     cfg.apply_only(combined_config, keys, true); | ||||||
|     std::string                 &inherits = Preset::inherits(cfg); |     std::string                 &inherits = Preset::inherits(cfg); | ||||||
|  |  | ||||||
|  | @ -1552,6 +1552,9 @@ DynamicPrintConfig PresetBundle::full_config_secure() const | ||||||
| { | { | ||||||
|     DynamicPrintConfig config = this->full_config(); |     DynamicPrintConfig config = this->full_config(); | ||||||
|     //BBS example: config.erase("print_host");
 |     //BBS example: config.erase("print_host");
 | ||||||
|  |     config.erase("print_host_webui"); | ||||||
|  |     config.erase("printhost_apikey"); | ||||||
|  |     config.erase("printhost_cafile"); | ||||||
|     return config; |     return config; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -75,11 +75,11 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrinterTechnology) | ||||||
| static t_config_enum_values s_keys_map_PrintHostType{ | static t_config_enum_values s_keys_map_PrintHostType{ | ||||||
|     { "prusalink",      htPrusaLink }, |     { "prusalink",      htPrusaLink }, | ||||||
|     { "octoprint",      htOctoPrint }, |     { "octoprint",      htOctoPrint }, | ||||||
|     //{ "duet",           htDuet },
 |     { "duet",           htDuet }, | ||||||
|     //{ "flashair",       htFlashAir },
 |     { "flashair",       htFlashAir }, | ||||||
|     //{ "astrobox",       htAstroBox },
 |     { "astrobox",       htAstroBox }, | ||||||
|     //{ "repetier",       htRepetier },
 |     { "repetier",       htRepetier }, | ||||||
|     //{ "mks",            htMKS }
 |     { "mks",            htMKS } | ||||||
| }; | }; | ||||||
| CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType) | CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType) | ||||||
| 
 | 
 | ||||||
|  | @ -404,6 +404,14 @@ void PrintConfigDef::init_common_params() | ||||||
|     def->cli = ConfigOptionDef::nocli; |     def->cli = ConfigOptionDef::nocli; | ||||||
|     def->set_default_value(new ConfigOptionString("")); |     def->set_default_value(new ConfigOptionString("")); | ||||||
| 
 | 
 | ||||||
|  |     def = this->add("print_host_webui", coString); | ||||||
|  |     def->label = L("Device UI"); | ||||||
|  |     def->tooltip = L("Specify the URL of your device user interface if it's not same as print_host"); | ||||||
|  |     def->mode = comAdvanced; | ||||||
|  |     def->cli = ConfigOptionDef::nocli; | ||||||
|  |     def->set_default_value(new ConfigOptionString("")); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     def = this->add("printhost_apikey", coString); |     def = this->add("printhost_apikey", coString); | ||||||
|     def->label = L("API Key / Password"); |     def->label = L("API Key / Password"); | ||||||
|     def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain " |     def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain " | ||||||
|  | @ -2011,18 +2019,18 @@ void PrintConfigDef::init_fff_params() | ||||||
|     def->enum_keys_map = &ConfigOptionEnum<PrintHostType>::get_enum_values(); |     def->enum_keys_map = &ConfigOptionEnum<PrintHostType>::get_enum_values(); | ||||||
|     def->enum_values.push_back("prusalink"); |     def->enum_values.push_back("prusalink"); | ||||||
|     def->enum_values.push_back("octoprint"); |     def->enum_values.push_back("octoprint"); | ||||||
|     //def->enum_values.push_back("duet");
 |     def->enum_values.push_back("duet"); | ||||||
|     //def->enum_values.push_back("flashair");
 |     def->enum_values.push_back("flashair"); | ||||||
|     //def->enum_values.push_back("astrobox");
 |     def->enum_values.push_back("astrobox"); | ||||||
|     //def->enum_values.push_back("repetier");
 |     def->enum_values.push_back("repetier"); | ||||||
|     //def->enum_values.push_back("mks");
 |     def->enum_values.push_back("mks"); | ||||||
|     def->enum_labels.push_back("PrusaLink"); |     def->enum_labels.push_back("PrusaLink"); | ||||||
|     def->enum_labels.push_back("OctoPrint"); |     def->enum_labels.push_back("OctoPrint"); | ||||||
|     //def->enum_labels.push_back("Duet");
 |     def->enum_labels.push_back("Duet"); | ||||||
|     //def->enum_labels.push_back("FlashAir");
 |     def->enum_labels.push_back("FlashAir"); | ||||||
|     //def->enum_labels.push_back("AstroBox");
 |     def->enum_labels.push_back("AstroBox"); | ||||||
|     //def->enum_labels.push_back("Repetier");
 |     def->enum_labels.push_back("Repetier"); | ||||||
|     //def->enum_labels.push_back("MKS");
 |     def->enum_labels.push_back("MKS"); | ||||||
|     def->mode = comAdvanced; |     def->mode = comAdvanced; | ||||||
|     def->cli = ConfigOptionDef::nocli; |     def->cli = ConfigOptionDef::nocli; | ||||||
|     def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint)); |     def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint)); | ||||||
|  |  | ||||||
|  | @ -245,6 +245,8 @@ set(SLIC3R_GUI_SOURCES | ||||||
|     GUI/Monitor.hpp |     GUI/Monitor.hpp | ||||||
|     GUI/WebViewDialog.cpp |     GUI/WebViewDialog.cpp | ||||||
|     GUI/WebViewDialog.hpp |     GUI/WebViewDialog.hpp | ||||||
|  |     GUI/PrinterWebView.cpp | ||||||
|  |     GUI/PrinterWebView.hpp | ||||||
|     GUI/WebDownPluginDlg.hpp |     GUI/WebDownPluginDlg.hpp | ||||||
|     GUI/WebDownPluginDlg.cpp |     GUI/WebDownPluginDlg.cpp | ||||||
|     GUI/WebGuideDialog.hpp |     GUI/WebGuideDialog.hpp | ||||||
|  | @ -429,6 +431,17 @@ set(SLIC3R_GUI_SOURCES | ||||||
|     Utils/PrintHost.cpp |     Utils/PrintHost.cpp | ||||||
|     Utils/NetworkAgent.cpp |     Utils/NetworkAgent.cpp | ||||||
|     Utils/NetworkAgent.hpp |     Utils/NetworkAgent.hpp | ||||||
|  |     Utils/MKS.hpp | ||||||
|  |     Utils/MKS.cpp | ||||||
|  |     Utils/Duet.cpp | ||||||
|  |     Utils/Duet.hpp | ||||||
|  |     Utils/FlashAir.cpp | ||||||
|  |     Utils/FlashAir.hpp | ||||||
|  |     Utils/AstroBox.cpp | ||||||
|  |     Utils/AstroBox.hpp | ||||||
|  |     Utils/Repetier.cpp | ||||||
|  |     Utils/Repetier.hpp | ||||||
|  | 
 | ||||||
|     Utils/CalibUtils.cpp |     Utils/CalibUtils.cpp | ||||||
|     Utils/CalibUtils.hpp |     Utils/CalibUtils.hpp | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ wxDEFINE_EVENT(EVT_UPDATE_PRESET_CB, SimpleEvent); | ||||||
| // BBS: backup
 | // BBS: backup
 | ||||||
| wxDEFINE_EVENT(EVT_BACKUP_POST, wxCommandEvent); | wxDEFINE_EVENT(EVT_BACKUP_POST, wxCommandEvent); | ||||||
| wxDEFINE_EVENT(EVT_LOAD_URL, wxCommandEvent); | wxDEFINE_EVENT(EVT_LOAD_URL, wxCommandEvent); | ||||||
|  | wxDEFINE_EVENT(EVT_LOAD_PRINTER_URL, wxCommandEvent); | ||||||
| 
 | 
 | ||||||
| enum class ERescaleTarget | enum class ERescaleTarget | ||||||
| { | { | ||||||
|  | @ -925,16 +926,35 @@ void MainFrame::init_tabpanel() | ||||||
|     m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, [this](wxBookCtrlEvent& e) { |     m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, [this](wxBookCtrlEvent& e) { | ||||||
|         int old_sel = e.GetOldSelection(); |         int old_sel = e.GetOldSelection(); | ||||||
|         int new_sel = e.GetSelection(); |         int new_sel = e.GetSelection(); | ||||||
|         if (new_sel == tpMonitor) { |         if (wxGetApp().preset_bundle && | ||||||
|  |             wxGetApp().preset_bundle->printers.get_edited_preset().is_bbl_vendor_preset(wxGetApp().preset_bundle) && | ||||||
|  |             new_sel == tpMonitor) { | ||||||
|             if (!wxGetApp().getAgent()) { |             if (!wxGetApp().getAgent()) { | ||||||
|                 e.Veto(); |                 e.Veto(); | ||||||
|                 BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins")%old_sel %new_sel; |                 BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins") % | ||||||
|  |                     old_sel % new_sel; | ||||||
|                 if (m_plater) { |                 if (m_plater) { | ||||||
|                     wxCommandEvent *evt = new wxCommandEvent(EVT_INSTALL_PLUGIN_HINT); |                     wxCommandEvent* evt = new wxCommandEvent(EVT_INSTALL_PLUGIN_HINT); | ||||||
|                     wxQueueEvent(m_plater, evt); |                     wxQueueEvent(m_plater, evt); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         else { | ||||||
|  |             if (new_sel == tpMonitor && wxGetApp().preset_bundle != nullptr) { | ||||||
|  |                 auto cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; | ||||||
|  |                 wxString url; | ||||||
|  |                 if (cfg.has("print_host_webui") && !cfg.opt_string("print_host_webui").empty()) { | ||||||
|  |                     url = cfg.opt_string("print_host_webui"); | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     url = cfg.opt_string("print_host"); | ||||||
|  |                 } | ||||||
|  |                 if (url.empty()) { | ||||||
|  |                     wxString url = wxString::Format("file://%s/web/device/missing_connection.html", from_u8(resources_dir())); | ||||||
|  |                     m_printer_view->load_url(url); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| #ifdef __WXMSW__ | #ifdef __WXMSW__ | ||||||
|  | @ -1017,6 +1037,14 @@ void MainFrame::init_tabpanel() | ||||||
|     m_monitor->SetBackgroundColour(*wxWHITE); |     m_monitor->SetBackgroundColour(*wxWHITE); | ||||||
|     m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); |     m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); | ||||||
| 
 | 
 | ||||||
|  |     m_printer_view = new PrinterWebView(m_tabpanel); | ||||||
|  |     Bind(EVT_LOAD_PRINTER_URL, [this](wxCommandEvent &evt) { | ||||||
|  |         wxString url = evt.GetString(); | ||||||
|  |         //select_tab(MainFrame::tpMonitor);
 | ||||||
|  |         m_printer_view->load_url(url); | ||||||
|  |     }); | ||||||
|  |     m_printer_view->Hide(); | ||||||
|  | 
 | ||||||
|     m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); |     m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); | ||||||
|     m_project->SetBackgroundColour(*wxWHITE); |     m_project->SetBackgroundColour(*wxWHITE); | ||||||
|     m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); |     m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); | ||||||
|  | @ -1039,6 +1067,36 @@ void MainFrame::init_tabpanel() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | // SoftFever
 | ||||||
|  | void MainFrame::show_device(bool bBBLPrinter) { | ||||||
|  |   if (m_tabpanel->GetPage(tpMonitor) != m_monitor && | ||||||
|  |       m_tabpanel->GetPage(tpMonitor) != m_printer_view) { | ||||||
|  |     BOOST_LOG_TRIVIAL(error) << "Failed to find device tab"; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (bBBLPrinter) { | ||||||
|  |     if (m_tabpanel->GetPage(tpMonitor) != m_monitor) { | ||||||
|  |         m_printer_view->Hide(); | ||||||
|  |       m_tabpanel->RemovePage(tpMonitor); | ||||||
|  |       m_tabpanel->InsertPage(tpMonitor, m_monitor, _L("Device"), | ||||||
|  |                              std::string("tab_monitor_active"), | ||||||
|  |                              std::string("tab_monitor_active")); | ||||||
|  |       m_tabpanel->SetSelection(tp3DEditor); | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     if (m_tabpanel->GetPage(tpMonitor) != m_printer_view) { | ||||||
|  |       m_printer_view->Show(); | ||||||
|  |       m_tabpanel->RemovePage(tpMonitor); | ||||||
|  |       m_tabpanel->InsertPage(tpMonitor, m_printer_view, _L("Device"), | ||||||
|  |                           std::string("tab_monitor_active"), | ||||||
|  |                           std::string("tab_monitor_active")); | ||||||
|  |       m_tabpanel->SetSelection(tp3DEditor); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| bool MainFrame::preview_only_hint() | bool MainFrame::preview_only_hint() | ||||||
| { | { | ||||||
|     if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) { |     if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) { | ||||||
|  | @ -3244,6 +3302,34 @@ void MainFrame::load_url(wxString url) | ||||||
|     wxQueueEvent(this, evt); |     wxQueueEvent(this, evt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void MainFrame::load_printer_url(wxString url) | ||||||
|  | { | ||||||
|  |     BOOST_LOG_TRIVIAL(trace) << "load_printer_url:" << url; | ||||||
|  |     auto evt = new wxCommandEvent(EVT_LOAD_PRINTER_URL, this->GetId()); | ||||||
|  |     evt->SetString(url); | ||||||
|  |     wxQueueEvent(this, evt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MainFrame::load_printer_url() | ||||||
|  | { | ||||||
|  |     PresetBundle &preset_bundle = *wxGetApp().preset_bundle; | ||||||
|  |     if (preset_bundle.printers.get_edited_preset().is_bbl_vendor_preset(&preset_bundle)) | ||||||
|  |         return; | ||||||
|  |      | ||||||
|  |     auto cfg = preset_bundle.printers.get_edited_preset().config; | ||||||
|  |     wxString url = | ||||||
|  |         cfg.opt_string("print_host_webui").empty() ? cfg.opt_string("print_host") : cfg.opt_string("print_host_webui"); | ||||||
|  |     if (!url.empty()) { | ||||||
|  |         if (!url.Lower().starts_with("http")) | ||||||
|  |             url = wxString::Format("http://%s", url); | ||||||
|  | 
 | ||||||
|  |         load_printer_url(url); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool MainFrame::is_printer_view() const { return m_tabpanel->GetSelection() == TabPosition::tpMonitor; } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void MainFrame::refresh_plugin_tips() | void MainFrame::refresh_plugin_tips() | ||||||
| { | { | ||||||
|     if (m_webview != nullptr) |     if (m_webview != nullptr) | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| 
 | 
 | ||||||
| // BBS
 | // BBS
 | ||||||
| #include "BBLTopbar.hpp" | #include "BBLTopbar.hpp" | ||||||
|  | #include "PrinterWebView.hpp" | ||||||
| 
 | 
 | ||||||
| #define ENABEL_PRINT_ALL 0 | #define ENABEL_PRINT_ALL 0 | ||||||
| 
 | 
 | ||||||
|  | @ -328,8 +329,12 @@ public: | ||||||
| 
 | 
 | ||||||
|     //BBS
 |     //BBS
 | ||||||
|     void        load_url(wxString url); |     void        load_url(wxString url); | ||||||
|  |     void        load_printer_url(wxString url); | ||||||
|  |     void        load_printer_url(); | ||||||
|  |     bool        is_printer_view() const; | ||||||
|     void        refresh_plugin_tips(); |     void        refresh_plugin_tips(); | ||||||
|     void RunScript(wxString js); |     void RunScript(wxString js); | ||||||
|  |     void show_device(bool bBBLPrinter); | ||||||
| 
 | 
 | ||||||
|     // BBS. Replace title bar and menu bar with top bar.
 |     // BBS. Replace title bar and menu bar with top bar.
 | ||||||
|     BBLTopbar*            m_topbar{ nullptr }; |     BBLTopbar*            m_topbar{ nullptr }; | ||||||
|  | @ -343,6 +348,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     CalibrationPanel*     m_calibration{ nullptr }; |     CalibrationPanel*     m_calibration{ nullptr }; | ||||||
|     WebViewPanel*         m_webview { nullptr }; |     WebViewPanel*         m_webview { nullptr }; | ||||||
|  |     PrinterWebView*       m_printer_view{nullptr}; | ||||||
|     wxLogWindow*          m_log_window { nullptr }; |     wxLogWindow*          m_log_window { nullptr }; | ||||||
|     // BBS
 |     // BBS
 | ||||||
|     //wxBookCtrlBase*       m_tabpanel { nullptr };
 |     //wxBookCtrlBase*       m_tabpanel { nullptr };
 | ||||||
|  |  | ||||||
|  | @ -219,6 +219,10 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr | ||||||
|     host_line.append_widget(print_host_test); |     host_line.append_widget(print_host_test); | ||||||
|     m_optgroup->append_line(host_line); |     m_optgroup->append_line(host_line); | ||||||
| 
 | 
 | ||||||
|  |     option = m_optgroup->get_option("print_host_webui"); | ||||||
|  |     option.opt.width = Field::def_width_wider(); | ||||||
|  |     m_optgroup->append_single_option_line(option); | ||||||
|  | 
 | ||||||
|     m_optgroup->append_single_option_line("printhost_authorization_type"); |     m_optgroup->append_single_option_line("printhost_authorization_type"); | ||||||
| 
 | 
 | ||||||
|     option = m_optgroup->get_option("printhost_apikey"); |     option = m_optgroup->get_option("printhost_apikey"); | ||||||
|  | @ -233,7 +237,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr | ||||||
| 
 | 
 | ||||||
|     const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."); |     const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."); | ||||||
| 
 | 
 | ||||||
|     /*if (Http::ca_file_supported()) {
 |     if (Http::ca_file_supported()) { | ||||||
|         option = m_optgroup->get_option("printhost_cafile"); |         option = m_optgroup->get_option("printhost_cafile"); | ||||||
|         option.opt.width = Field::def_width_wider(); |         option.opt.width = Field::def_width_wider(); | ||||||
|         Line cafile_line = m_optgroup->create_single_option_line(option); |         Line cafile_line = m_optgroup->create_single_option_line(option); | ||||||
|  | @ -253,37 +257,37 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         cafile_line.append_widget(printhost_cafile_browse); |         cafile_line.append_widget(printhost_cafile_browse); | ||||||
|         //m_optgroup->append_line(cafile_line);
 |         m_optgroup->append_line(cafile_line); | ||||||
| 
 | 
 | ||||||
|         //Line cafile_hint{ "", "" };
 |         Line cafile_hint{ "", "" }; | ||||||
|         //cafile_hint.full_width = 1;
 |         cafile_hint.full_width = 1; | ||||||
|         //cafile_hint.widget = [ca_file_hint](wxWindow* parent) {
 |         cafile_hint.widget = [ca_file_hint](wxWindow* parent) { | ||||||
|         //    auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint);
 |             auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint); | ||||||
|         //    auto sizer = new wxBoxSizer(wxHORIZONTAL);
 |             auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||||
|         //    sizer->Add(txt);
 |             sizer->Add(txt); | ||||||
|         //    return sizer;
 |             return sizer; | ||||||
|         //};
 |         }; | ||||||
|         //m_optgroup->append_line(cafile_hint);
 |         m_optgroup->append_line(cafile_hint); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|          |          | ||||||
|         //Line line{ "", "" };
 |         Line line{ "", "" }; | ||||||
|         //line.full_width = 1;
 |         line.full_width = 1; | ||||||
| 
 | 
 | ||||||
|         //line.widget = [ca_file_hint](wxWindow* parent) {
 |         line.widget = [ca_file_hint](wxWindow* parent) { | ||||||
|         //    std::string info = _u8L("HTTPS CA File") + ":\n\t" +
 |             std::string info = _u8L("HTTPS CA File") + ":\n\t" + | ||||||
|         //        (boost::format(_u8L("On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain.")) % SLIC3R_APP_NAME).str() +
 |                 (boost::format(_u8L("On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain.")) % SLIC3R_APP_NAME).str() + | ||||||
|         //        "\n\t" + _u8L("To use a custom CA file, please import your CA file into Certificate Store / Keychain.");
 |                 "\n\t" + _u8L("To use a custom CA file, please import your CA file into Certificate Store / Keychain."); | ||||||
| 
 | 
 | ||||||
|         //    //auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\n\t%2%") % info % ca_file_hint).str()));
 |             //auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\n\t%2%") % info % ca_file_hint).str()));
 | ||||||
|         //    auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\t%2%") % info % ca_file_hint).str()));
 |             auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\t%2%") % info % ca_file_hint).str())); | ||||||
|         //    txt->SetFont(wxGetApp().normal_font());
 |             txt->SetFont(wxGetApp().normal_font()); | ||||||
|         //    auto sizer = new wxBoxSizer(wxHORIZONTAL);
 |             auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||||
|         //    sizer->Add(txt, 1, wxEXPAND);
 |             sizer->Add(txt, 1, wxEXPAND|wxALIGN_LEFT); | ||||||
|         //    return sizer;
 |             return sizer; | ||||||
|         //};
 |         }; | ||||||
|         //m_optgroup->append_line(line);
 |         m_optgroup->append_line(line); | ||||||
|     }*/ |     } | ||||||
| 
 | 
 | ||||||
|     for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" }) {         |     for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" }) {         | ||||||
|         option = m_optgroup->get_option(opt_key); |         option = m_optgroup->get_option(opt_key); | ||||||
|  | @ -292,9 +296,9 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
|     //option = m_optgroup->get_option("printhost_ssl_ignore_revoke");
 |     option = m_optgroup->get_option("printhost_ssl_ignore_revoke"); | ||||||
|     //option.opt.width = Field::def_width_wider();
 |     option.opt.width = Field::def_width_wider(); | ||||||
|     //m_optgroup->append_single_option_line(option);
 |     m_optgroup->append_single_option_line(option); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     m_optgroup->activate(); |     m_optgroup->activate(); | ||||||
|  |  | ||||||
|  | @ -1026,17 +1026,39 @@ void Sidebar::update_all_preset_comboboxes() | ||||||
| 
 | 
 | ||||||
|     bool is_bbl_preset = preset_bundle.printers.get_edited_preset().is_bbl_vendor_preset(&preset_bundle); |     bool is_bbl_preset = preset_bundle.printers.get_edited_preset().is_bbl_vendor_preset(&preset_bundle); | ||||||
| 
 | 
 | ||||||
|  |     auto p_mainframe = wxGetApp().mainframe; | ||||||
|  | 
 | ||||||
|  |     p_mainframe->show_device(is_bbl_preset); | ||||||
|     if (is_bbl_preset) { |     if (is_bbl_preset) { | ||||||
|         //only show connection button for not-BBL printer
 |         //only show connection button for not-BBL printer
 | ||||||
|         connection_btn->Hide(); |         connection_btn->Hide(); | ||||||
|         //only show sync-ams button for BBL printer
 |         //only show sync-ams button for BBL printer
 | ||||||
|         ams_btn->Show(); |         ams_btn->Show(); | ||||||
|         //update print button default value for bbl or third-party printer
 |         //update print button default value for bbl or third-party printer
 | ||||||
|         wxGetApp().mainframe->set_print_button_to_default(MainFrame::PrintSelectType::ePrintPlate); |         p_mainframe->set_print_button_to_default(MainFrame::PrintSelectType::ePrintPlate); | ||||||
|  |         m_bed_type_list->SelectAndNotify(btPC - 1); | ||||||
|  |         m_bed_type_list->Enable(); | ||||||
|     } else { |     } else { | ||||||
|         connection_btn->Show(); |         connection_btn->Show(); | ||||||
|         ams_btn->Hide(); |         ams_btn->Hide(); | ||||||
|         wxGetApp().mainframe->set_print_button_to_default(MainFrame::PrintSelectType::eSendGcode); |         p_mainframe->set_print_button_to_default(MainFrame::PrintSelectType::eSendGcode); | ||||||
|  |         auto cfg = preset_bundle.printers.get_edited_preset().config; | ||||||
|  |         wxString url; | ||||||
|  |         if (cfg.has("print_host_webui") && !cfg.opt_string("print_host_webui").empty()) { | ||||||
|  |             url = cfg.opt_string("print_host_webui"); | ||||||
|  |         } else { | ||||||
|  |             url = cfg.opt_string("print_host"); | ||||||
|  |         } | ||||||
|  |         if(!url.empty())  | ||||||
|  |         { | ||||||
|  |             if(!url.Lower().starts_with("http")) | ||||||
|  |                 url = wxString::Format("http://%s",url); | ||||||
|  | 
 | ||||||
|  |             p_mainframe->load_printer_url(url); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         m_bed_type_list->SelectAndNotify(btPEI - 1); | ||||||
|  |         m_bed_type_list->Disable(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Update the print choosers to only contain the compatible presets, update the dirty flags.
 |     // Update the print choosers to only contain the compatible presets, update the dirty flags.
 | ||||||
|  |  | ||||||
							
								
								
									
										123
									
								
								src/slic3r/GUI/PrinterWebView.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/slic3r/GUI/PrinterWebView.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | ||||||
|  | #include "PrinterWebView.hpp" | ||||||
|  | 
 | ||||||
|  | #include "I18N.hpp" | ||||||
|  | #include "slic3r/GUI/wxExtensions.hpp" | ||||||
|  | #include "slic3r/GUI/GUI_App.hpp" | ||||||
|  | #include "slic3r/GUI/MainFrame.hpp" | ||||||
|  | #include "libslic3r_version.h" | ||||||
|  | 
 | ||||||
|  | #include <wx/sizer.h> | ||||||
|  | #include <wx/toolbar.h> | ||||||
|  | #include <wx/textdlg.h> | ||||||
|  | 
 | ||||||
|  | #include <slic3r/GUI/Widgets/WebView.hpp> | ||||||
|  | 
 | ||||||
|  | namespace pt = boost::property_tree; | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | namespace GUI { | ||||||
|  | 
 | ||||||
|  | PrinterWebView::PrinterWebView(wxWindow *parent) | ||||||
|  |         : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) | ||||||
|  |  { | ||||||
|  | 
 | ||||||
|  |     wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); | ||||||
|  | 
 | ||||||
|  |       // Create the webview
 | ||||||
|  |     m_browser = WebView::CreateWebView(this, ""); | ||||||
|  |     if (m_browser == nullptr) { | ||||||
|  |         wxLogError("Could not init m_browser"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this); | ||||||
|  | 
 | ||||||
|  |     SetSizer(topsizer); | ||||||
|  | 
 | ||||||
|  |     topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); | ||||||
|  | 
 | ||||||
|  |     // Log backend information
 | ||||||
|  |     if (wxGetApp().get_mode() == comDevelop) { | ||||||
|  |         wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); | ||||||
|  |         wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(), | ||||||
|  |             wxWebView::GetBackendVersionInfo().ToString()); | ||||||
|  |         wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Zoom
 | ||||||
|  |     m_zoomFactor = 100; | ||||||
|  | 
 | ||||||
|  |     //Connect the idle events
 | ||||||
|  |     Bind(wxEVT_CLOSE_WINDOW, &PrinterWebView::OnClose, this); | ||||||
|  | 
 | ||||||
|  |  } | ||||||
|  | 
 | ||||||
|  | PrinterWebView::~PrinterWebView() | ||||||
|  | { | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Start"; | ||||||
|  |     SetEvtHandlerEnabled(false); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void PrinterWebView::load_url(wxString& url) | ||||||
|  | { | ||||||
|  | //    this->Show();
 | ||||||
|  | //    this->Raise();
 | ||||||
|  |     if (m_browser == nullptr) | ||||||
|  |         return; | ||||||
|  |     m_browser->LoadURL(url); | ||||||
|  |     //m_browser->SetFocus();
 | ||||||
|  |     UpdateState(); | ||||||
|  | } | ||||||
|  | /**
 | ||||||
|  |  * Method that retrieves the current state from the web control and updates the | ||||||
|  |  * GUI the reflect this current state. | ||||||
|  |  */ | ||||||
|  | void PrinterWebView::UpdateState() { | ||||||
|  |   // SetTitle(m_browser->GetCurrentTitle());
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PrinterWebView::OnClose(wxCloseEvent& evt) | ||||||
|  | { | ||||||
|  |     this->Hide(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PrinterWebView::OnError(wxWebViewEvent &evt) | ||||||
|  | { | ||||||
|  |     auto e = "unknown error"; | ||||||
|  |     switch (evt.GetInt()) { | ||||||
|  |       case wxWEBVIEW_NAV_ERR_CONNECTION: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_CONNECTION"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_CERTIFICATE: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_CERTIFICATE"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_AUTH: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_AUTH"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_SECURITY: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_SECURITY"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_NOT_FOUND: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_NOT_FOUND"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_REQUEST: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_REQUEST"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_USER_CANCELLED: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_USER_CANCELLED"; | ||||||
|  |         break; | ||||||
|  |       case wxWEBVIEW_NAV_ERR_OTHER: | ||||||
|  |         e = "wxWEBVIEW_NAV_ERR_OTHER"; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": error loading page %1% %2% %3% %4%") %evt.GetURL() %evt.GetTarget() %e %evt.GetString(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } // GUI
 | ||||||
|  | } // Slic3r
 | ||||||
							
								
								
									
										54
									
								
								src/slic3r/GUI/PrinterWebView.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/slic3r/GUI/PrinterWebView.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | #ifndef slic3r_PrinterWebView_hpp_ | ||||||
|  | #define slic3r_PrinterWebView_hpp_ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include "wx/artprov.h" | ||||||
|  | #include "wx/cmdline.h" | ||||||
|  | #include "wx/notifmsg.h" | ||||||
|  | #include "wx/settings.h" | ||||||
|  | #include "wx/webview.h" | ||||||
|  | 
 | ||||||
|  | #if wxUSE_WEBVIEW_EDGE | ||||||
|  | #include "wx/msw/webview_edge.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include "wx/webviewarchivehandler.h" | ||||||
|  | #include "wx/webviewfshandler.h" | ||||||
|  | #include "wx/numdlg.h" | ||||||
|  | #include "wx/infobar.h" | ||||||
|  | #include "wx/filesys.h" | ||||||
|  | #include "wx/fs_arc.h" | ||||||
|  | #include "wx/fs_mem.h" | ||||||
|  | #include "wx/stdpaths.h" | ||||||
|  | #include <wx/panel.h> | ||||||
|  | #include <wx/tbarbase.h> | ||||||
|  | #include "wx/textctrl.h" | ||||||
|  | #include <wx/timer.h> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | namespace GUI { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PrinterWebView : public wxPanel { | ||||||
|  | public: | ||||||
|  |     PrinterWebView(wxWindow *parent); | ||||||
|  |     virtual ~PrinterWebView(); | ||||||
|  | 
 | ||||||
|  |     void load_url(wxString& url); | ||||||
|  |     void UpdateState(); | ||||||
|  |     void OnClose(wxCloseEvent& evt); | ||||||
|  |     void OnError(wxWebViewEvent& evt); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 
 | ||||||
|  |     wxWebView* m_browser; | ||||||
|  |     long m_zoomFactor; | ||||||
|  | 
 | ||||||
|  |     // DECLARE_EVENT_TABLE()
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // GUI
 | ||||||
|  | } // Slic3r
 | ||||||
|  | 
 | ||||||
|  | #endif /* slic3r_Tab_hpp_ */ | ||||||
|  | @ -75,6 +75,10 @@ void ComboBox::SetSelection(int n) | ||||||
|     if (drop.selection >= 0) |     if (drop.selection >= 0) | ||||||
|         SetIcon(icons[drop.selection]); |         SetIcon(icons[drop.selection]); | ||||||
| } | } | ||||||
|  | void ComboBox::SelectAndNotify(int n) {  | ||||||
|  |     SetSelection(n); | ||||||
|  |     sendComboBoxEvent(); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void ComboBox::Rescale() | void ComboBox::Rescale() | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -43,6 +43,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     void SetSelection(int n) override; |     void SetSelection(int n) override; | ||||||
| 
 | 
 | ||||||
|  |     void SelectAndNotify(int n); | ||||||
|  | 
 | ||||||
|     virtual void Rescale() override; |     virtual void Rescale() override; | ||||||
| 
 | 
 | ||||||
|     wxString GetValue() const; |     wxString GetValue() const; | ||||||
|  |  | ||||||
							
								
								
									
										173
									
								
								src/slic3r/Utils/AstroBox.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/slic3r/Utils/AstroBox.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | ||||||
|  | #include "AstroBox.hpp" | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <sstream> | ||||||
|  | #include <exception> | ||||||
|  | #include <boost/format.hpp> | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/property_tree/ptree.hpp> | ||||||
|  | #include <boost/property_tree/json_parser.hpp> | ||||||
|  | #include <boost/algorithm/string/predicate.hpp> | ||||||
|  | 
 | ||||||
|  | #include <wx/progdlg.h> | ||||||
|  | 
 | ||||||
|  | #include "libslic3r/PrintConfig.hpp" | ||||||
|  | #include "slic3r/GUI/I18N.hpp" | ||||||
|  | #include "slic3r/GUI/GUI.hpp" | ||||||
|  | #include "Http.hpp" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace fs = boost::filesystem; | ||||||
|  | namespace pt = boost::property_tree; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | AstroBox::AstroBox(DynamicPrintConfig *config) : | ||||||
|  |     host(config->opt_string("print_host")), | ||||||
|  |     apikey(config->opt_string("printhost_apikey")), | ||||||
|  |     cafile(config->opt_string("printhost_cafile")) | ||||||
|  | {} | ||||||
|  | 
 | ||||||
|  | const char* AstroBox::get_name() const { return "AstroBox"; } | ||||||
|  | 
 | ||||||
|  | bool AstroBox::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 = true; | ||||||
|  |     auto url = make_url("api/version"); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version 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 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; | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 std::stringstream ss(body); | ||||||
|  |                 pt::ptree ptree; | ||||||
|  |                 pt::read_json(ss, ptree); | ||||||
|  | 
 | ||||||
|  |                 if (! ptree.get_optional<std::string>("api")) { | ||||||
|  |                     res = false; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const auto text = ptree.get_optional<std::string>("text"); | ||||||
|  |                 res = validate_version_text(text); | ||||||
|  |                 if (! res) { | ||||||
|  |                     msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "AstroBox")).str()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             catch (const std::exception &) { | ||||||
|  |                 res = false; | ||||||
|  |                 msg = "Could not parse server response"; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString AstroBox::get_test_ok_msg () const | ||||||
|  | { | ||||||
|  |     return _(L("Connection to AstroBox works correctly.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString AstroBox::get_test_failed_msg (wxString &msg) const | ||||||
|  | { | ||||||
|  |     return GUI::from_u8((boost::format("%s: %s\n\n%s") | ||||||
|  |         % _utf8(L("Could not connect to AstroBox")) | ||||||
|  |         % std::string(msg.ToUTF8()) | ||||||
|  |         % _utf8(L("Note: AstroBox version at least 1.1.0 is required."))).str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AstroBox::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 = true; | ||||||
|  | 
 | ||||||
|  |     auto url = make_url("api/files/local"); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%") | ||||||
|  |         % name | ||||||
|  |         % upload_data.source_path | ||||||
|  |         % url | ||||||
|  |         % upload_filename.string() | ||||||
|  |         % upload_parent_path.string() | ||||||
|  |         % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false"); | ||||||
|  | 
 | ||||||
|  |     auto http = Http::post(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_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: %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) << "AstroBox: Upload canceled"; | ||||||
|  |                 res = false; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AstroBox::validate_version_text(const boost::optional<std::string> &version_text) const | ||||||
|  | { | ||||||
|  |     return version_text ? boost::starts_with(*version_text, "AstroBox") : true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AstroBox::set_auth(Http &http) const | ||||||
|  | { | ||||||
|  |     http.header("X-Api-Key", apikey); | ||||||
|  | 
 | ||||||
|  |     if (! cafile.empty()) { | ||||||
|  |         http.ca_file(cafile); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string AstroBox::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 { | ||||||
|  |         return (boost::format("http://%1%/%2%") % host % path).str(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								src/slic3r/Utils/AstroBox.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/slic3r/Utils/AstroBox.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | ||||||
|  | #ifndef slic3r_AstroBox_hpp_ | ||||||
|  | #define slic3r_AstroBox_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <wx/string.h> | ||||||
|  | #include <boost/optional.hpp> | ||||||
|  | 
 | ||||||
|  | #include "PrintHost.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | class DynamicPrintConfig; | ||||||
|  | class Http; | ||||||
|  | 
 | ||||||
|  | class AstroBox : public PrintHost | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     AstroBox(DynamicPrintConfig *config); | ||||||
|  |     ~AstroBox() override = default; | ||||||
|  | 
 | ||||||
|  |     const char* get_name() const override; | ||||||
|  | 
 | ||||||
|  |     bool test(wxString &curl_msg) const override; | ||||||
|  |     wxString get_test_ok_msg () const override; | ||||||
|  |     wxString get_test_failed_msg (wxString &msg) const override; | ||||||
|  |     bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; | ||||||
|  |     bool has_auto_discovery() const override { return true; } | ||||||
|  |     bool can_test() const override { return true; } | ||||||
|  |     PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; } | ||||||
|  |     std::string get_host() const override { return host; } | ||||||
|  |      | ||||||
|  | protected: | ||||||
|  |     bool validate_version_text(const boost::optional<std::string> &version_text) const; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::string host; | ||||||
|  |     std::string apikey; | ||||||
|  |     std::string cafile; | ||||||
|  | 
 | ||||||
|  |     void set_auth(Http &http) const; | ||||||
|  |     std::string make_url(const std::string &path) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										286
									
								
								src/slic3r/Utils/Duet.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								src/slic3r/Utils/Duet.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,286 @@ | ||||||
|  | #include "Duet.hpp" | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <ctime> | ||||||
|  | #include <boost/filesystem/path.hpp> | ||||||
|  | #include <boost/format.hpp> | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/property_tree/ptree.hpp> | ||||||
|  | #include <boost/property_tree/json_parser.hpp> | ||||||
|  | 
 | ||||||
|  | #include <wx/frame.h> | ||||||
|  | #include <wx/event.h> | ||||||
|  | #include <wx/progdlg.h> | ||||||
|  | #include <wx/sizer.h> | ||||||
|  | #include <wx/stattext.h> | ||||||
|  | #include <wx/textctrl.h> | ||||||
|  | #include <wx/checkbox.h> | ||||||
|  | 
 | ||||||
|  | #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 { | ||||||
|  | 
 | ||||||
|  | Duet::Duet(DynamicPrintConfig *config) : | ||||||
|  | 	host(config->opt_string("print_host")), | ||||||
|  | 	password(config->opt_string("printhost_apikey")) | ||||||
|  | {} | ||||||
|  | 
 | ||||||
|  | const char* Duet::get_name() const { return "Duet"; } | ||||||
|  | 
 | ||||||
|  | bool Duet::test(wxString &msg) const | ||||||
|  | { | ||||||
|  | 	auto connectionType = connect(msg); | ||||||
|  | 	disconnect(connectionType); | ||||||
|  | 
 | ||||||
|  | 	return connectionType != ConnectionType::error; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString Duet::get_test_ok_msg () const | ||||||
|  | { | ||||||
|  | 	return _(L("Connection to Duet works correctly.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString Duet::get_test_failed_msg (wxString &msg) const | ||||||
|  | { | ||||||
|  |     return GUI::from_u8((boost::format("%s: %s") | ||||||
|  |                     % _utf8(L("Could not connect to Duet")) | ||||||
|  |                     % std::string(msg.ToUTF8())).str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const | ||||||
|  | { | ||||||
|  | 	wxString connect_msg; | ||||||
|  | 	auto connectionType = connect(connect_msg); | ||||||
|  | 	if (connectionType == ConnectionType::error) { | ||||||
|  | 		error_fn(std::move(connect_msg)); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool res = true; | ||||||
|  | 	bool dsf = (connectionType == ConnectionType::dsf); | ||||||
|  | 
 | ||||||
|  | 	auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType); | ||||||
|  | 	BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, post_action: %3%, command: %4%") | ||||||
|  | 		% upload_data.source_path | ||||||
|  | 		% upload_data.upload_path | ||||||
|  | 		% int(upload_data.post_action) | ||||||
|  | 		% upload_cmd; | ||||||
|  | 
 | ||||||
|  | 	auto http = (dsf ? Http::put(std::move(upload_cmd)) : Http::post(std::move(upload_cmd))); | ||||||
|  | 	if (dsf) { | ||||||
|  | 		http.set_put_body(upload_data.source_path); | ||||||
|  | 	} else { | ||||||
|  | 		http.set_post_body(upload_data.source_path); | ||||||
|  | 	} | ||||||
|  | 	http.on_complete([&](std::string body, unsigned status) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body; | ||||||
|  | 
 | ||||||
|  | 			int err_code = dsf ? (status == 201 ? 0 : 1) : get_err_code_from_body(body); | ||||||
|  | 			if (err_code != 0) { | ||||||
|  | 				BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Request completed but error code was received: %1%") % err_code; | ||||||
|  | 				error_fn(format_error(body, L("Unknown error occured"), 0)); | ||||||
|  | 				res = false; | ||||||
|  | 			} else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) { | ||||||
|  | 				wxString errormsg; | ||||||
|  | 				res = start_print(errormsg, upload_data.upload_path.string(), connectionType, false); | ||||||
|  | 				if (! res) { | ||||||
|  | 					error_fn(std::move(errormsg)); | ||||||
|  | 				} | ||||||
|  | 			} else if (upload_data.post_action == PrintHostPostUploadAction::StartSimulation) { | ||||||
|  | 				wxString errormsg; | ||||||
|  | 				res = start_print(errormsg, upload_data.upload_path.string(), connectionType, true); | ||||||
|  | 				if (! res) { | ||||||
|  | 					error_fn(std::move(errormsg)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 		.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % 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) << "Duet: Upload canceled"; | ||||||
|  | 				res = false; | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 		.perform_sync(); | ||||||
|  | 
 | ||||||
|  | 	disconnect(connectionType); | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Duet::ConnectionType Duet::connect(wxString &msg) const | ||||||
|  | { | ||||||
|  | 	auto res = ConnectionType::error; | ||||||
|  | 	auto url = get_connect_url(false); | ||||||
|  | 
 | ||||||
|  | 	auto http = Http::get(std::move(url)); | ||||||
|  | 	http.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 			auto dsfUrl = get_connect_url(true); | ||||||
|  | 			auto dsfHttp = Http::get(std::move(dsfUrl)); | ||||||
|  | 			dsfHttp.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 					BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body; | ||||||
|  | 					msg = format_error(body, error, status); | ||||||
|  | 				}) | ||||||
|  | 				.on_complete([&](std::string body, unsigned) { | ||||||
|  | 					res = ConnectionType::dsf; | ||||||
|  | 				}) | ||||||
|  | 				.perform_sync(); | ||||||
|  | 		}) | ||||||
|  | 		.on_complete([&](std::string body, unsigned) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body; | ||||||
|  | 
 | ||||||
|  | 			int err_code = get_err_code_from_body(body); | ||||||
|  | 			switch (err_code) { | ||||||
|  | 				case 0: | ||||||
|  | 					res = ConnectionType::rrf; | ||||||
|  | 					break; | ||||||
|  | 				case 1: | ||||||
|  | 					msg = format_error(body, L("Wrong password"), 0); | ||||||
|  | 					break; | ||||||
|  | 				case 2: | ||||||
|  | 					msg = format_error(body, L("Could not get resources to create a new connection"), 0); | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					msg = format_error(body, L("Unknown error occured"), 0); | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		}) | ||||||
|  | 		.perform_sync(); | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Duet::disconnect(ConnectionType connectionType) const | ||||||
|  | { | ||||||
|  | 	// we don't need to disconnect from DSF or if it failed anyway
 | ||||||
|  | 	if (connectionType != ConnectionType::rrf) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	auto url =  (boost::format("%1%rr_disconnect") | ||||||
|  | 			% get_base_url()).str(); | ||||||
|  | 
 | ||||||
|  | 	auto http = Http::get(std::move(url)); | ||||||
|  | 	http.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 		// we don't care about it, if disconnect is not working Duet will disconnect automatically after some time
 | ||||||
|  | 		BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error disconnecting: %1%, HTTP %2%, body: `%3%`") % error % status % body; | ||||||
|  | 	}) | ||||||
|  | 	.perform_sync(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Duet::get_upload_url(const std::string &filename, ConnectionType connectionType) const | ||||||
|  | { | ||||||
|  |     assert(connectionType != ConnectionType::error); | ||||||
|  | 
 | ||||||
|  | 	if (connectionType == ConnectionType::dsf) { | ||||||
|  | 		return (boost::format("%1%machine/file/gcodes/%2%") | ||||||
|  | 				% get_base_url() | ||||||
|  | 				% Http::url_encode(filename)).str(); | ||||||
|  | 	} else { | ||||||
|  | 		return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%") | ||||||
|  | 				% get_base_url() | ||||||
|  | 				% Http::url_encode(filename) | ||||||
|  | 				% timestamp_str()).str(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Duet::get_connect_url(const bool dsfUrl) const | ||||||
|  | { | ||||||
|  | 	if (dsfUrl)	{ | ||||||
|  | 		return (boost::format("%1%machine/status") | ||||||
|  | 				% get_base_url()).str(); | ||||||
|  | 	} else { | ||||||
|  | 		return (boost::format("%1%rr_connect?password=%2%&%3%") | ||||||
|  | 				% get_base_url() | ||||||
|  | 				% (password.empty() ? "reprap" : password) | ||||||
|  | 				% timestamp_str()).str(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Duet::get_base_url() const | ||||||
|  | { | ||||||
|  | 	if (host.find("http://") == 0 || host.find("https://") == 0) { | ||||||
|  | 		if (host.back() == '/') { | ||||||
|  | 			return host; | ||||||
|  | 		} else { | ||||||
|  | 			return (boost::format("%1%/") % host).str(); | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		return (boost::format("http://%1%/") % host).str(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Duet::timestamp_str() const | ||||||
|  | { | ||||||
|  | 	enum { BUFFER_SIZE = 32 }; | ||||||
|  | 
 | ||||||
|  | 	auto t = std::time(nullptr); | ||||||
|  | 	auto tm = *std::localtime(&t); | ||||||
|  | 
 | ||||||
|  | 	char buffer[BUFFER_SIZE]; | ||||||
|  | 	std::strftime(buffer, BUFFER_SIZE, "time=%Y-%m-%dT%H:%M:%S", &tm); | ||||||
|  | 
 | ||||||
|  | 	return std::string(buffer); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const | ||||||
|  | { | ||||||
|  |     assert(connectionType != ConnectionType::error); | ||||||
|  | 
 | ||||||
|  | 	bool res = false; | ||||||
|  | 	bool dsf = (connectionType == ConnectionType::dsf); | ||||||
|  | 
 | ||||||
|  | 	auto url = dsf | ||||||
|  | 		? (boost::format("%1%machine/code") | ||||||
|  | 			% get_base_url()).str() | ||||||
|  | 		: (boost::format(simulationMode | ||||||
|  | 				? "%1%rr_gcode?gcode=M37%%20P\"0:/gcodes/%2%\"" | ||||||
|  | 				: "%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"") | ||||||
|  | 			% get_base_url() | ||||||
|  | 			% Http::url_encode(filename)).str(); | ||||||
|  | 
 | ||||||
|  | 	auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url))); | ||||||
|  | 	if (dsf) { | ||||||
|  | 		http.set_post_body( | ||||||
|  | 				(boost::format(simulationMode | ||||||
|  | 						? "M37 P\"0:/gcodes/%1%\"" | ||||||
|  | 						: "M32 \"0:/gcodes/%1%\"") | ||||||
|  | 					% filename).str() | ||||||
|  | 				); | ||||||
|  | 	} | ||||||
|  | 	http.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body; | ||||||
|  | 			msg = format_error(body, error, status); | ||||||
|  | 		}) | ||||||
|  | 		.on_complete([&](std::string body, unsigned) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body; | ||||||
|  | 			res = true; | ||||||
|  | 		}) | ||||||
|  | 		.perform_sync(); | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Duet::get_err_code_from_body(const std::string &body) const | ||||||
|  | { | ||||||
|  | 	pt::ptree root; | ||||||
|  | 	std::istringstream iss (body); // wrap returned json to istringstream
 | ||||||
|  | 	pt::read_json(iss, root); | ||||||
|  | 
 | ||||||
|  | 	return root.get<int>("err", 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								src/slic3r/Utils/Duet.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/slic3r/Utils/Duet.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | #ifndef slic3r_Duet_hpp_ | ||||||
|  | #define slic3r_Duet_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <wx/string.h> | ||||||
|  | 
 | ||||||
|  | #include "PrintHost.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | class DynamicPrintConfig; | ||||||
|  | class Http; | ||||||
|  | 
 | ||||||
|  | class Duet : public PrintHost | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     explicit Duet(DynamicPrintConfig *config); | ||||||
|  | 	~Duet() override = default; | ||||||
|  | 
 | ||||||
|  | 	const char* get_name() const override; | ||||||
|  | 
 | ||||||
|  | 	bool test(wxString &curl_msg) const override; | ||||||
|  | 	wxString get_test_ok_msg() const override; | ||||||
|  | 	wxString get_test_failed_msg(wxString &msg) const override; | ||||||
|  | 	bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; | ||||||
|  | 	bool has_auto_discovery() const override { return false; } | ||||||
|  | 	bool can_test() const override { return true; } | ||||||
|  |     PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint | PrintHostPostUploadAction::StartSimulation; } | ||||||
|  | 	std::string get_host() const override { return host; } | ||||||
|  |     | ||||||
|  | private: | ||||||
|  | 	enum class ConnectionType { rrf, dsf, error }; | ||||||
|  | 	std::string host; | ||||||
|  | 	std::string password; | ||||||
|  | 
 | ||||||
|  | 	std::string get_upload_url(const std::string &filename, ConnectionType connectionType) const; | ||||||
|  | 	std::string get_connect_url(const bool dsfUrl) const; | ||||||
|  | 	std::string get_base_url() const; | ||||||
|  | 	std::string timestamp_str() const; | ||||||
|  | 	ConnectionType connect(wxString &msg) const; | ||||||
|  | 	void disconnect(ConnectionType connectionType) const; | ||||||
|  | 	bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const; | ||||||
|  | 	int get_err_code_from_body(const std::string &body) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										229
									
								
								src/slic3r/Utils/FlashAir.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/slic3r/Utils/FlashAir.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,229 @@ | ||||||
|  | #include "FlashAir.hpp" | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <ctime> | ||||||
|  | #include <boost/filesystem/path.hpp> | ||||||
|  | #include <boost/format.hpp> | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/algorithm/string/predicate.hpp> | ||||||
|  | 
 | ||||||
|  | #include <wx/frame.h> | ||||||
|  | #include <wx/event.h> | ||||||
|  | #include <wx/progdlg.h> | ||||||
|  | #include <wx/sizer.h> | ||||||
|  | #include <wx/stattext.h> | ||||||
|  | #include <wx/textctrl.h> | ||||||
|  | #include <wx/checkbox.h> | ||||||
|  | 
 | ||||||
|  | #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(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								src/slic3r/Utils/FlashAir.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/slic3r/Utils/FlashAir.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | #ifndef slic3r_FlashAir_hpp_ | ||||||
|  | #define slic3r_FlashAir_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <wx/string.h> | ||||||
|  | 
 | ||||||
|  | #include "PrintHost.hpp" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | class DynamicPrintConfig; | ||||||
|  | class Http; | ||||||
|  | 
 | ||||||
|  | class FlashAir : public PrintHost | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	FlashAir(DynamicPrintConfig *config); | ||||||
|  | 	~FlashAir() override = default; | ||||||
|  | 
 | ||||||
|  | 	const char* get_name() const override; | ||||||
|  | 
 | ||||||
|  | 	bool test(wxString &curl_msg) const override; | ||||||
|  | 	wxString get_test_ok_msg() const override; | ||||||
|  | 	wxString get_test_failed_msg(wxString &msg) const override; | ||||||
|  | 	bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; | ||||||
|  | 	bool has_auto_discovery() const override { return false; } | ||||||
|  | 	bool can_test() const override { return true; } | ||||||
|  |     PrintHostPostUploadActions get_post_upload_actions() const override { return {}; } | ||||||
|  | 	std::string get_host() const override { return host; } | ||||||
|  |      | ||||||
|  | private: | ||||||
|  | 	std::string host; | ||||||
|  | 
 | ||||||
|  | 	std::string timestamp_str() const; | ||||||
|  | 	std::string make_url(const std::string &path) const; | ||||||
|  | 	std::string make_url(const std::string &path, const std::string &arg, const std::string &val) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										150
									
								
								src/slic3r/Utils/MKS.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/slic3r/Utils/MKS.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | ||||||
|  | #include "MKS.hpp" | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <ctime> | ||||||
|  | #include <chrono> | ||||||
|  | #include <thread> | ||||||
|  | #include <boost/filesystem/path.hpp> | ||||||
|  | #include <boost/format.hpp> | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/property_tree/ptree.hpp> | ||||||
|  | #include <boost/property_tree/json_parser.hpp> | ||||||
|  | #include <boost/asio.hpp> | ||||||
|  | #include <boost/algorithm/string.hpp> | ||||||
|  | 
 | ||||||
|  | #include <wx/frame.h> | ||||||
|  | #include <wx/event.h> | ||||||
|  | #include <wx/progdlg.h> | ||||||
|  | #include <wx/sizer.h> | ||||||
|  | #include <wx/stattext.h> | ||||||
|  | #include <wx/textctrl.h> | ||||||
|  | #include <wx/checkbox.h> | ||||||
|  | 
 | ||||||
|  | #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 { | ||||||
|  | 
 | ||||||
|  | MKS::MKS(DynamicPrintConfig* config) : | ||||||
|  | 	m_host(config->opt_string("print_host")), m_console_port("8080") | ||||||
|  | {} | ||||||
|  | 
 | ||||||
|  | const char* MKS::get_name() const { return "MKS"; } | ||||||
|  | 
 | ||||||
|  | bool MKS::test(wxString& msg) const | ||||||
|  | { | ||||||
|  | 	Utils::TCPConsole console(m_host, m_console_port); | ||||||
|  | 
 | ||||||
|  | 	console.enqueue_cmd("M105"); | ||||||
|  | 	bool ret = console.run_queue(); | ||||||
|  | 
 | ||||||
|  | 	if (!ret) | ||||||
|  | 		msg = wxString::FromUTF8(console.error_message().c_str()); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString MKS::get_test_ok_msg() const | ||||||
|  | { | ||||||
|  | 	return _(L("Connection to MKS works correctly.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString MKS::get_test_failed_msg(wxString& msg) const | ||||||
|  | { | ||||||
|  | 	return GUI::from_u8((boost::format("%s: %s") | ||||||
|  | 		% _utf8(L("Could not connect to MKS")) | ||||||
|  | 		% std::string(msg.ToUTF8())).str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const | ||||||
|  | { | ||||||
|  | 	bool res = true; | ||||||
|  | 
 | ||||||
|  | 	auto upload_cmd = get_upload_url(upload_data.upload_path.string()); | ||||||
|  | 	BOOST_LOG_TRIVIAL(info) << boost::format("MKS: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") | ||||||
|  | 		% upload_data.source_path | ||||||
|  | 		% upload_data.upload_path | ||||||
|  | 		% (upload_data.post_action == PrintHostPostUploadAction::StartPrint) | ||||||
|  | 		% upload_cmd; | ||||||
|  | 
 | ||||||
|  | 	auto http = Http::post(std::move(upload_cmd)); | ||||||
|  | 	http.set_post_body(upload_data.source_path); | ||||||
|  | 
 | ||||||
|  | 	http.on_complete([&](std::string body, unsigned status) { | ||||||
|  | 		BOOST_LOG_TRIVIAL(debug) << boost::format("MKS: File uploaded: HTTP %1%: %2%") % status % body; | ||||||
|  | 
 | ||||||
|  | 		int err_code = get_err_code_from_body(body); | ||||||
|  | 		if (err_code != 0) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Request completed but error code was received: %1%") % err_code; | ||||||
|  | 			error_fn(format_error(body, L("Unknown error occured"), 0)); | ||||||
|  | 			res = false; | ||||||
|  | 		} | ||||||
|  | 		else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) { | ||||||
|  | 			wxString errormsg; | ||||||
|  | 			res = start_print(errormsg, upload_data.upload_path.string()); | ||||||
|  | 			if (!res) { | ||||||
|  | 				error_fn(std::move(errormsg)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		}) | ||||||
|  | 		.on_error([&](std::string body, std::string error, unsigned status) { | ||||||
|  | 			BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % 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) << "MKS: Upload canceled"; | ||||||
|  | 				res = false; | ||||||
|  | 			} | ||||||
|  | 		}).perform_sync(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string MKS::get_upload_url(const std::string& filename) const | ||||||
|  | { | ||||||
|  | 	return (boost::format("http://%1%/upload?X-Filename=%2%") | ||||||
|  | 		% m_host | ||||||
|  | 		% Http::url_encode(filename)).str(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool MKS::start_print(wxString& msg, const std::string& filename) const | ||||||
|  | { | ||||||
|  | 	// For some reason printer firmware does not want to respond on gcode commands immediately after file upload.
 | ||||||
|  | 	// So we just introduce artificial delay to workaround it.
 | ||||||
|  | 	// TODO: Inspect reasons
 | ||||||
|  | 	std::this_thread::sleep_for(std::chrono::milliseconds(1500)); | ||||||
|  | 
 | ||||||
|  | 	Utils::TCPConsole console(m_host, m_console_port); | ||||||
|  | 
 | ||||||
|  | 	console.enqueue_cmd(std::string("M23 ") + filename); | ||||||
|  | 	console.enqueue_cmd("M24"); | ||||||
|  | 
 | ||||||
|  | 	bool ret = console.run_queue(); | ||||||
|  | 
 | ||||||
|  | 	if (!ret) | ||||||
|  | 		msg = wxString::FromUTF8(console.error_message().c_str()); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int MKS::get_err_code_from_body(const std::string& body) const | ||||||
|  | { | ||||||
|  | 	pt::ptree root; | ||||||
|  | 	std::istringstream iss(body); // wrap returned json to istringstream
 | ||||||
|  | 	pt::read_json(iss, root); | ||||||
|  | 
 | ||||||
|  | 	return root.get<int>("err", 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // Slic3r
 | ||||||
							
								
								
									
										42
									
								
								src/slic3r/Utils/MKS.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/slic3r/Utils/MKS.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | #ifndef slic3r_MKS_hpp_ | ||||||
|  | #define slic3r_MKS_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <wx/string.h> | ||||||
|  | 
 | ||||||
|  | #include "PrintHost.hpp" | ||||||
|  | #include "TCPConsole.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | class DynamicPrintConfig; | ||||||
|  | class Http; | ||||||
|  | 
 | ||||||
|  | class MKS : public PrintHost | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	explicit MKS(DynamicPrintConfig* config); | ||||||
|  | 	~MKS() override = default; | ||||||
|  | 
 | ||||||
|  | 	const char* get_name() const override; | ||||||
|  | 
 | ||||||
|  | 	bool test(wxString& curl_msg) const override; | ||||||
|  | 	wxString get_test_ok_msg() const override; | ||||||
|  | 	wxString get_test_failed_msg(wxString& msg) const override; | ||||||
|  | 	bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; | ||||||
|  | 	bool has_auto_discovery() const override { return false; } | ||||||
|  | 	bool can_test() const override { return true; } | ||||||
|  |     PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; } | ||||||
|  | 	std::string get_host() const override { return m_host; } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	std::string m_host; | ||||||
|  | 	std::string m_console_port; | ||||||
|  | 
 | ||||||
|  | 	std::string get_upload_url(const std::string& filename) const; | ||||||
|  | 	bool start_print(wxString& msg, const std::string& filename) const; | ||||||
|  | 	int get_err_code_from_body(const std::string& body) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -14,11 +14,11 @@ | ||||||
| #include "libslic3r/PrintConfig.hpp" | #include "libslic3r/PrintConfig.hpp" | ||||||
| #include "libslic3r/Channel.hpp" | #include "libslic3r/Channel.hpp" | ||||||
| #include "OctoPrint.hpp" | #include "OctoPrint.hpp" | ||||||
| //#include "Duet.hpp"
 | #include "Duet.hpp" | ||||||
| //#include "FlashAir.hpp"
 | #include "FlashAir.hpp" | ||||||
| //#include "AstroBox.hpp"
 | #include "AstroBox.hpp" | ||||||
| //#include "Repetier.hpp"
 | #include "Repetier.hpp" | ||||||
| //#include "MKS.hpp"
 | #include "MKS.hpp" | ||||||
| #include "../GUI/PrintHostDialogs.hpp" | #include "../GUI/PrintHostDialogs.hpp" | ||||||
| 
 | 
 | ||||||
| namespace fs = boost::filesystem; | namespace fs = boost::filesystem; | ||||||
|  | @ -47,12 +47,12 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) | ||||||
| 
 | 
 | ||||||
|         switch (host_type) { |         switch (host_type) { | ||||||
|             case htOctoPrint: return new OctoPrint(config); |             case htOctoPrint: return new OctoPrint(config); | ||||||
|             //case htDuet:      return new Duet(config);
 |             case htDuet:      return new Duet(config); | ||||||
|             //case htFlashAir:  return new FlashAir(config);
 |             case htFlashAir:  return new FlashAir(config); | ||||||
|             //case htAstroBox:  return new AstroBox(config);
 |             case htAstroBox:  return new AstroBox(config); | ||||||
|             //case htRepetier:  return new Repetier(config);
 |             case htRepetier:  return new Repetier(config); | ||||||
|             case htPrusaLink: return new PrusaLink(config); |             case htPrusaLink: return new PrusaLink(config); | ||||||
|             //case htMKS:       return new MKS(config);
 |             case htMKS:       return new MKS(config); | ||||||
|             default:          return nullptr; |             default:          return nullptr; | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|  |  | ||||||
							
								
								
									
										274
									
								
								src/slic3r/Utils/Repetier.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								src/slic3r/Utils/Repetier.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,274 @@ | ||||||
|  | #include "Repetier.hpp" | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <sstream> | ||||||
|  | #include <exception> | ||||||
|  | #include <boost/foreach.hpp> | ||||||
|  | #include <boost/format.hpp> | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/property_tree/ptree.hpp> | ||||||
|  | #include <boost/property_tree/json_parser.hpp> | ||||||
|  | #include <boost/algorithm/string/predicate.hpp> | ||||||
|  | 
 | ||||||
|  | #include <wx/progdlg.h> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include "libslic3r/PrintConfig.hpp" | ||||||
|  | #include "slic3r/GUI/I18N.hpp" | ||||||
|  | #include "slic3r/GUI/GUI.hpp" | ||||||
|  | #include "slic3r/GUI/format.hpp" | ||||||
|  | #include "Http.hpp" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace fs = boost::filesystem; | ||||||
|  | namespace pt = boost::property_tree; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | Repetier::Repetier(DynamicPrintConfig *config) : | ||||||
|  |     host(config->opt_string("print_host")), | ||||||
|  |     apikey(config->opt_string("printhost_apikey")), | ||||||
|  |     cafile(config->opt_string("printhost_cafile")), | ||||||
|  |     port(config->opt_string("printhost_port")) | ||||||
|  | {} | ||||||
|  | 
 | ||||||
|  | const char* Repetier::get_name() const { return "Repetier"; } | ||||||
|  | 
 | ||||||
|  | bool Repetier::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 = true; | ||||||
|  |     auto url = make_url("printer/info"); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << boost::format("%1%: List version 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 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; | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 std::stringstream ss(body); | ||||||
|  |                 pt::ptree ptree; | ||||||
|  |                 pt::read_json(ss, ptree); | ||||||
|  |                  | ||||||
|  |                 const auto text = ptree.get_optional<std::string>("name"); | ||||||
|  |                 res = validate_version_text(text); | ||||||
|  |                 if (! res) { | ||||||
|  |                     msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "Repetier")).str()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             catch (const std::exception &) { | ||||||
|  |                 res = false; | ||||||
|  |                 msg = "Could not parse server response"; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString Repetier::get_test_ok_msg () const | ||||||
|  | { | ||||||
|  |     return _(L("Connection to Repetier works correctly.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | wxString Repetier::get_test_failed_msg (wxString &msg) const | ||||||
|  | { | ||||||
|  |         return GUI::from_u8((boost::format("%s: %s\n\n%s") | ||||||
|  |         % _utf8(L("Could not connect to Repetier")) | ||||||
|  |         % std::string(msg.ToUTF8()) | ||||||
|  |         % _utf8(L("Note: Repetier version at least 0.90.0 is required."))).str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Repetier::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 = true; | ||||||
|  | 
 | ||||||
|  |     auto url = upload_data.post_action == PrintHostPostUploadAction::StartPrint | ||||||
|  |         ? make_url((boost::format("printer/job/%1%") % port).str()) | ||||||
|  |         : make_url((boost::format("printer/model/%1%") % port).str()); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%, group: %7%") | ||||||
|  |         % name | ||||||
|  |         % upload_data.source_path | ||||||
|  |         % url | ||||||
|  |         % upload_filename.string() | ||||||
|  |         % upload_parent_path.string() | ||||||
|  |         % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") | ||||||
|  |         % upload_data.group; | ||||||
|  | 
 | ||||||
|  |     auto http = Http::post(std::move(url)); | ||||||
|  |     set_auth(http); | ||||||
|  | 
 | ||||||
|  |     if (! upload_data.group.empty() && upload_data.group != _utf8(L("Default"))) { | ||||||
|  |         http.form_add("group", upload_data.group); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(upload_data.post_action == PrintHostPostUploadAction::StartPrint) { | ||||||
|  |         http.form_add("name", upload_filename.string()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     http.form_add("a", "upload") | ||||||
|  |         .form_add_file("filename", 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: %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) << "Repetier: Upload canceled"; | ||||||
|  |                 res = false; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Repetier::validate_version_text(const boost::optional<std::string> &version_text) const | ||||||
|  | { | ||||||
|  |     return version_text ? (!version_text->empty()) : true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Repetier::set_auth(Http &http) const | ||||||
|  | { | ||||||
|  |     http.header("X-Api-Key", apikey); | ||||||
|  | 
 | ||||||
|  |     if (! cafile.empty()) { | ||||||
|  |         http.ca_file(cafile); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Repetier::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 { | ||||||
|  |         return (boost::format("http://%1%/%2%") % host % path).str(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Repetier::get_groups(wxArrayString& groups) const | ||||||
|  | { | ||||||
|  |     bool res = true; | ||||||
|  |      | ||||||
|  |     const char *name = get_name(); | ||||||
|  |     auto url = make_url((boost::format("printer/api/%1%") % port).str()); | ||||||
|  | 
 | ||||||
|  |     BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get groups at: %2%") % name % url; | ||||||
|  | 
 | ||||||
|  |     auto http = Http::get(std::move(url)); | ||||||
|  |     set_auth(http); | ||||||
|  |     http.form_add("a", "listModelGroups"); | ||||||
|  |     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; | ||||||
|  |         }) | ||||||
|  |         .on_complete([&](std::string body, unsigned) { | ||||||
|  |             BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got groups: %2%") % name % body; | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 std::stringstream ss(body); | ||||||
|  |                 pt::ptree ptree; | ||||||
|  |                 pt::read_json(ss, ptree); | ||||||
|  | 
 | ||||||
|  |                 BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptree.get_child("groupNames.")) { | ||||||
|  |                     if (v.second.data() == "#") { | ||||||
|  |                         groups.push_back(_utf8(L("Default"))); | ||||||
|  |                     } else { | ||||||
|  |                         // Is it safe to assume that the data are utf-8 encoded?
 | ||||||
|  |                         groups.push_back(GUI::from_u8(v.second.data())); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             catch (const std::exception &) { | ||||||
|  |                 //msg = "Could not parse server response";
 | ||||||
|  |                 res = false; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Repetier::get_printers(wxArrayString& printers) const | ||||||
|  | { | ||||||
|  |     const char *name = get_name(); | ||||||
|  | 
 | ||||||
|  |     bool res = true; | ||||||
|  |     auto url = make_url("printer/list"); | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |             res = false; | ||||||
|  |         }) | ||||||
|  |         .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<std::string>("error"); | ||||||
|  |             if (error) | ||||||
|  |                 throw HostNetworkError(*error); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptree.get_child("data.")) { | ||||||
|  |                     const auto port = v.second.get<std::string>("slug"); | ||||||
|  |                     printers.push_back(Slic3r::GUI::from_u8(port)); | ||||||
|  |                 } | ||||||
|  |             } catch (const std::exception &err) { | ||||||
|  |                 throw HostNetworkError(GUI::format(_L("Enumeration of host printers failed.\nMessage body: \"%1%\"\nError: \"%2%\""), body, err.what())); | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .perform_sync(); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								src/slic3r/Utils/Repetier.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/slic3r/Utils/Repetier.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | #ifndef slic3r_Repetier_hpp_ | ||||||
|  | #define slic3r_Repetier_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <wx/string.h> | ||||||
|  | #include <boost/optional.hpp> | ||||||
|  | 
 | ||||||
|  | #include "PrintHost.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | 
 | ||||||
|  | class DynamicPrintConfig; | ||||||
|  | class Http; | ||||||
|  | 
 | ||||||
|  | class Repetier : public PrintHost | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     Repetier(DynamicPrintConfig *config); | ||||||
|  |     ~Repetier() override = default; | ||||||
|  | 
 | ||||||
|  |     const char* get_name() const override; | ||||||
|  | 
 | ||||||
|  |     bool test(wxString &curl_msg) const override; | ||||||
|  |     wxString get_test_ok_msg () const override; | ||||||
|  |     wxString get_test_failed_msg (wxString &msg) const override; | ||||||
|  |     bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; | ||||||
|  |     bool has_auto_discovery() const override { return false; } | ||||||
|  |     bool can_test() const override { return true; } | ||||||
|  |     PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; } | ||||||
|  |     bool supports_multiple_printers() const override { return true; } | ||||||
|  |     std::string get_host() const override { return host; } | ||||||
|  |      | ||||||
|  |     bool get_groups(wxArrayString &groups) const override; | ||||||
|  |     bool get_printers(wxArrayString &printers) const override; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     virtual bool validate_version_text(const boost::optional<std::string> &version_text) const; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::string host; | ||||||
|  |     std::string apikey; | ||||||
|  |     std::string cafile; | ||||||
|  |     std::string port; | ||||||
|  | 
 | ||||||
|  |     void set_auth(Http &http) const; | ||||||
|  |     std::string make_url(const std::string &path) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Stone Li
						Stone Li