mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'add-duet-software-framework-support' of https://github.com/Duet3D/PrusaSlicer into Duet3D-add-duet-software-framework-support
This commit is contained in:
		
						commit
						daeb618812
					
				
					 4 changed files with 144 additions and 51 deletions
				
			
		|  | @ -36,12 +36,10 @@ const char* Duet::get_name() const { return "Duet"; } | |||
| 
 | ||||
| bool Duet::test(wxString &msg) const | ||||
| { | ||||
| 	bool connected = connect(msg); | ||||
| 	if (connected) { | ||||
| 		disconnect(); | ||||
| 	} | ||||
| 	auto connectionType = connect(msg); | ||||
| 	disconnect(connectionType); | ||||
| 
 | ||||
| 	return connected; | ||||
| 	return connectionType != ConnectionType::error; | ||||
| } | ||||
| 
 | ||||
| wxString Duet::get_test_ok_msg () const | ||||
|  | @ -59,33 +57,39 @@ wxString Duet::get_test_failed_msg (wxString &msg) const | |||
| bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const | ||||
| { | ||||
| 	wxString connect_msg; | ||||
| 	if (!connect(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()); | ||||
| 	auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType); | ||||
| 	BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") | ||||
| 		% upload_data.source_path | ||||
| 		% upload_data.upload_path | ||||
| 		% upload_data.start_print | ||||
| 		% upload_cmd; | ||||
| 
 | ||||
| 	auto http = Http::post(std::move(upload_cmd)); | ||||
| 	http.set_post_body(upload_data.source_path) | ||||
| 		.on_complete([&](std::string body, unsigned status) { | ||||
| 	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 = get_err_code_from_body(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.start_print) { | ||||
| 				wxString errormsg; | ||||
| 				res = start_print(errormsg, upload_data.upload_path.string()); | ||||
| 				res = start_print(errormsg, upload_data.upload_path.string(), connectionType); | ||||
| 				if (! res) { | ||||
| 					error_fn(std::move(errormsg)); | ||||
| 				} | ||||
|  | @ -106,20 +110,28 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e | |||
| 		}) | ||||
| 		.perform_sync(); | ||||
| 
 | ||||
| 	disconnect(); | ||||
| 	disconnect(connectionType); | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| bool Duet::connect(wxString &msg) const | ||||
| Duet::ConnectionType Duet::connect(wxString &msg) const | ||||
| { | ||||
| 	bool res = false; | ||||
| 	auto url = get_connect_url(); | ||||
| 	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) { | ||||
| 			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body; | ||||
| 			msg = format_error(body, error, 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; | ||||
|  | @ -127,7 +139,7 @@ bool Duet::connect(wxString &msg) const | |||
| 			int err_code = get_err_code_from_body(body); | ||||
| 			switch (err_code) { | ||||
| 				case 0: | ||||
| 					res = true; | ||||
| 					res = ConnectionType::rrf; | ||||
| 					break; | ||||
| 				case 1: | ||||
| 					msg = format_error(body, L("Wrong password"), 0); | ||||
|  | @ -146,8 +158,12 @@ bool Duet::connect(wxString &msg) const | |||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| void Duet::disconnect() const | ||||
| 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(); | ||||
| 
 | ||||
|  | @ -159,20 +175,31 @@ void Duet::disconnect() const | |||
| 	.perform_sync(); | ||||
| } | ||||
| 
 | ||||
| std::string Duet::get_upload_url(const std::string &filename) const | ||||
| std::string Duet::get_upload_url(const std::string &filename, ConnectionType connectionType) const | ||||
| { | ||||
| 	return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%") | ||||
| 			% get_base_url() | ||||
| 			% Http::url_encode(filename)  | ||||
| 			% timestamp_str()).str(); | ||||
| 	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 | ||||
| std::string Duet::get_connect_url(const bool dsfUrl) const | ||||
| { | ||||
| 	return (boost::format("%1%rr_connect?password=%2%&%3%") | ||||
| 			% get_base_url() | ||||
| 			% (password.empty() ? "reprap" : password) | ||||
| 			% timestamp_str()).str(); | ||||
| 	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 | ||||
|  | @ -201,15 +228,25 @@ std::string Duet::timestamp_str() const | |||
| 	return std::string(buffer); | ||||
| } | ||||
| 
 | ||||
| bool Duet::start_print(wxString &msg, const std::string &filename) const  | ||||
| bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const | ||||
| { | ||||
| 	bool res = false; | ||||
| 	bool dsf = (connectionType == ConnectionType::dsf); | ||||
| 
 | ||||
| 	auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"") | ||||
| 	auto url = dsf | ||||
| 		? (boost::format("%1%machine/code") | ||||
| 			% get_base_url()).str() | ||||
| 		: (boost::format("%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"") | ||||
| 			% get_base_url() | ||||
| 			% Http::url_encode(filename)).str(); | ||||
| 
 | ||||
| 	auto http = Http::get(std::move(url)); | ||||
| 	auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url))); | ||||
| 	if (dsf) { | ||||
| 		http.set_post_body( | ||||
| 				(boost::format("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); | ||||
|  |  | |||
|  | @ -29,16 +29,17 @@ public: | |||
| 	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) const; | ||||
| 	std::string get_connect_url() const; | ||||
| 	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; | ||||
| 	bool connect(wxString &msg) const; | ||||
| 	void disconnect() const; | ||||
| 	bool start_print(wxString &msg, const std::string &filename) const; | ||||
| 	ConnectionType connect(wxString &msg) const; | ||||
| 	void disconnect(ConnectionType connectionType) const; | ||||
| 	bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const; | ||||
| 	int get_err_code_from_body(const std::string &body) const; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,11 +35,11 @@ struct CurlGlobalInit | |||
| { | ||||
|     static std::unique_ptr<CurlGlobalInit> instance; | ||||
|     std::string message; | ||||
|      | ||||
| 
 | ||||
| 	CurlGlobalInit() | ||||
|     { | ||||
| #ifdef OPENSSL_CERT_OVERRIDE // defined if SLIC3R_STATIC=ON
 | ||||
|          | ||||
| 
 | ||||
|         // Look for a set of distro specific directories. Don't change the
 | ||||
|         // order: https://bugzilla.redhat.com/show_bug.cgi?id=1053882
 | ||||
|         static const char * CA_BUNDLES[] = { | ||||
|  | @ -48,17 +48,17 @@ struct CurlGlobalInit | |||
|             "/usr/share/ssl/certs/ca-bundle.crt", | ||||
|             "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
 | ||||
|             "/etc/ssl/cert.pem", | ||||
|             "/etc/ssl/ca-bundle.pem"              // OpenSUSE Tumbleweed              
 | ||||
|             "/etc/ssl/ca-bundle.pem"              // OpenSUSE Tumbleweed
 | ||||
|         }; | ||||
|          | ||||
| 
 | ||||
|         namespace fs = boost::filesystem; | ||||
|         // Env var name for the OpenSSL CA bundle (SSL_CERT_FILE nomally)
 | ||||
|         const char *const SSL_CA_FILE = X509_get_default_cert_file_env(); | ||||
|         const char * ssl_cafile = ::getenv(SSL_CA_FILE); | ||||
|          | ||||
| 
 | ||||
|         if (!ssl_cafile) | ||||
|             ssl_cafile = X509_get_default_cert_file(); | ||||
|          | ||||
| 
 | ||||
|         int replace = true; | ||||
|         if (!ssl_cafile || !fs::exists(fs::path(ssl_cafile))) { | ||||
|             const char * bundle = nullptr; | ||||
|  | @ -86,15 +86,15 @@ struct CurlGlobalInit | |||
|         } | ||||
| 
 | ||||
| #endif // OPENSSL_CERT_OVERRIDE
 | ||||
|          | ||||
| 
 | ||||
|         if (CURLcode ec = ::curl_global_init(CURL_GLOBAL_DEFAULT)) { | ||||
|             message += _u8L("CURL init has failed. PrusaSlicer will be unable to establish " | ||||
|                             "network connections. See logs for additional details."); | ||||
|              | ||||
| 
 | ||||
|             BOOST_LOG_TRIVIAL(error) << ::curl_easy_strerror(ec); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
| 	~CurlGlobalInit() { ::curl_global_cleanup(); } | ||||
| }; | ||||
| 
 | ||||
|  | @ -120,6 +120,7 @@ struct Http::priv | |||
| 	std::string error_buffer;    // Used for CURLOPT_ERRORBUFFER
 | ||||
| 	size_t limit; | ||||
| 	bool cancel; | ||||
| 	fs::ifstream* putFile; | ||||
| 
 | ||||
| 	std::thread io_thread; | ||||
| 	Http::CompleteFn completefn; | ||||
|  | @ -138,6 +139,8 @@ struct Http::priv | |||
| 	void set_timeout_connect(long timeout); | ||||
| 	void form_add_file(const char *name, const fs::path &path, const char* filename); | ||||
| 	void set_post_body(const fs::path &path); | ||||
| 	void set_post_body(const std::string body); | ||||
| 	void set_put_body(const fs::path &path); | ||||
| 
 | ||||
| 	std::string curl_error(CURLcode curlcode); | ||||
| 	std::string body_size_error(); | ||||
|  | @ -152,9 +155,10 @@ Http::priv::priv(const std::string &url) | |||
| 	, error_buffer(CURL_ERROR_SIZE + 1, '\0') | ||||
| 	, limit(0) | ||||
| 	, cancel(false) | ||||
| 	, putFile(nullptr) | ||||
| { | ||||
|     Http::tls_global_init(); | ||||
|      | ||||
| 
 | ||||
| 	if (curl == nullptr) { | ||||
| 		throw Slic3r::RuntimeError(std::string("Could not construct Curl object")); | ||||
| 	} | ||||
|  | @ -284,6 +288,22 @@ void Http::priv::set_post_body(const fs::path &path) | |||
| 	postfields = file_content; | ||||
| } | ||||
| 
 | ||||
| void Http::priv::set_post_body(const std::string body) | ||||
| { | ||||
| 	postfields = body; | ||||
| } | ||||
| 
 | ||||
| void Http::priv::set_put_body(const fs::path &path) | ||||
| { | ||||
| 	boost::system::error_code ec; | ||||
| 	boost::uintmax_t filesize = file_size(path, ec); | ||||
| 	if (!ec) { | ||||
| 		putFile = new fs::ifstream(path); | ||||
| 		::curl_easy_setopt(curl, CURLOPT_READDATA, (void *) (putFile)); | ||||
| 		::curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::string Http::priv::curl_error(CURLcode curlcode) | ||||
| { | ||||
| 	return (boost::format("%1%:\n%2%\n[Error %3%]") | ||||
|  | @ -335,6 +355,11 @@ void Http::priv::http_perform() | |||
| 
 | ||||
| 	CURLcode res = ::curl_easy_perform(curl); | ||||
| 
 | ||||
| 	if (putFile != nullptr) { | ||||
| 		delete putFile; | ||||
| 		putFile = nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	if (res != CURLE_OK) { | ||||
| 		if (res == CURLE_ABORTED_BY_CALLBACK) { | ||||
| 			if (cancel) { | ||||
|  | @ -465,6 +490,18 @@ Http& Http::set_post_body(const fs::path &path) | |||
| 	return *this; | ||||
| } | ||||
| 
 | ||||
| Http& Http::set_post_body(const std::string body) | ||||
| { | ||||
| 	if (p) { p->set_post_body(body); } | ||||
| 	return *this; | ||||
| } | ||||
| 
 | ||||
| Http& Http::set_put_body(const fs::path &path) | ||||
| { | ||||
| 	if (p) { p->set_put_body(path);} | ||||
| 	return *this; | ||||
| } | ||||
| 
 | ||||
| Http& Http::on_complete(CompleteFn fn) | ||||
| { | ||||
| 	if (p) { p->completefn = std::move(fn); } | ||||
|  | @ -519,6 +556,13 @@ Http Http::post(std::string url) | |||
| 	return http; | ||||
| } | ||||
| 
 | ||||
| Http Http::put(std::string url) | ||||
| { | ||||
| 	Http http{std::move(url)}; | ||||
| 	curl_easy_setopt(http.p->curl, CURLOPT_UPLOAD, 1L); | ||||
| 	return http; | ||||
| } | ||||
| 
 | ||||
| bool Http::ca_file_supported() | ||||
| { | ||||
| 	::CURL *curl = ::curl_easy_init(); | ||||
|  | @ -531,7 +575,7 @@ std::string Http::tls_global_init() | |||
| { | ||||
|     if (!CurlGlobalInit::instance) | ||||
|         CurlGlobalInit::instance = std::make_unique<CurlGlobalInit>(); | ||||
|      | ||||
| 
 | ||||
|     return CurlGlobalInit::instance->message; | ||||
| } | ||||
| 
 | ||||
|  | @ -542,7 +586,7 @@ std::string Http::tls_system_cert_store() | |||
| #ifdef OPENSSL_CERT_OVERRIDE | ||||
|     ret = ::getenv(X509_get_default_cert_file_env()); | ||||
| #endif | ||||
|      | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,6 +49,7 @@ public: | |||
| 	// for a GET and a POST request respectively.
 | ||||
| 	static Http get(std::string url); | ||||
| 	static Http post(std::string url); | ||||
| 	static Http put(std::string url); | ||||
| 	~Http(); | ||||
| 
 | ||||
| 	Http(const Http &) = delete; | ||||
|  | @ -82,6 +83,16 @@ public: | |||
| 	// This can be used for hosts which do not support multipart requests.
 | ||||
| 	Http& set_post_body(const boost::filesystem::path &path); | ||||
| 
 | ||||
| 	// Set the POST request body.
 | ||||
| 	// The data is used verbatim, it is not additionally encoded in any way.
 | ||||
| 	// This can be used for hosts which do not support multipart requests.
 | ||||
| 	Http& set_post_body(const std::string body); | ||||
| 
 | ||||
| 	// Set the file contents as a PUT request body.
 | ||||
| 	// The data is used verbatim, it is not additionally encoded in any way.
 | ||||
| 	// This can be used for hosts which do not support multipart requests.
 | ||||
| 	Http& set_put_body(const boost::filesystem::path &path); | ||||
| 
 | ||||
| 	// Callback called on HTTP request complete
 | ||||
| 	Http& on_complete(CompleteFn fn); | ||||
| 	// Callback called on an error occuring at any stage of the requests: Url parsing, DNS lookup,
 | ||||
|  | @ -102,7 +113,7 @@ public: | |||
| 
 | ||||
| 	// Tells whether current backend supports seting up a CA file using ca_file()
 | ||||
| 	static bool ca_file_supported(); | ||||
|      | ||||
| 
 | ||||
|     // Return empty string on success or error message on fail.
 | ||||
|     static std::string tls_global_init(); | ||||
|     static std::string tls_system_cert_store(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Matena
						Lukas Matena