Files
OrcaSlicer/src/slic3r/Utils/Flashforge.hpp
T
HanifKoh e40030cf81 Stop Malformed Network Responses from Crashing the App (#15947)
* Stop Malformed Network Responses from Crashing the App

Duet, MKS and UltiMaker parsed print host replies with boost read_json
inside the HTTP completion callback with no try, so an HTML or truncated
reply threw out of the Physical Printer Test button and terminated the app,
or killed the upload queue thread. The five identical copies of the parser
(ESP3D's and Flashforge's were unused) are replaced by one shared
PrintHost::get_err_code_from_body that reports a non-JSON reply as an error.
The upload queue now catches a failing job per job, so one bad upload no
longer leaves later jobs queued forever.

Flashforge read material station slots with nlohmann value(), which throws
on off-type fields or non-object entries. The parsing moves into
Flashforge::parse_material_slots, which reads fields leniently with the
existing try_parse_json_int and skips bad entries.

UserManager::parse_json parsed the payload before its try block; the parse
now happens inside it.

* Keep UploadFinished Paired with UploadStarted When an Upload Throws

The exception from a throwing upload was caught around perform_job, so
the UploadFinished lifecycle event was skipped and plugins saw an
upload start that never finished.

The catch now sits around the upload call. The error is reported
through the job's error callback and UploadFinished is fired with an
error code, as for any other failed upload. The worker keeps running
for the next job. The started, upload and finished sequence moved to
PrintHostJobQueue::upload_job so it can be tested without the dialog.
2026-09-30 00:39:01 +08:00

80 lines
3.6 KiB
C++

#ifndef slic3r_FlashForge_hpp_
#define slic3r_FlashForge_hpp_
#include <vector>
#include <string>
#include <wx/string.h>
#include "PrintHost.hpp"
#include "SerialMessage.hpp"
#include "SerialMessageType.hpp"
#include "../../libslic3r/PrintConfig.hpp"
namespace Slic3r {
class DynamicPrintConfig;
class Http;
struct FlashforgeMaterialSlot
{
int slot_id {0}; // API is 1-based.
bool has_filament {false};
std::string material_name;
std::string material_color;
};
struct FlashforgeDiscoveredPrinter
{
std::string name;
std::string serial_number;
std::string ip_address;
};
class Flashforge : public PrintHost
{
public:
explicit Flashforge(DynamicPrintConfig *config);
~Flashforge() 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, InfoFn info_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 m_host; }
bool fetch_material_slots(std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station, wxString& msg) const;
// Parses a local API "detail" reply. Returns false when the body is not valid JSON.
static bool parse_material_slots(const std::string& body, std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station);
static bool discover_printers(std::vector<FlashforgeDiscoveredPrinter>& printers, wxString& msg, int timeout_ms = 10000, int idle_timeout_ms = 1500, int max_retries = 3);
private:
std::string m_host;
std::string m_serial_number;
std::string m_check_code;
std::string m_console_port;
const int m_bufferSize;
GCodeFlavor m_gcFlavor;
Slic3r::Utils::SerialMessage controlCommand = {"~M601 S1\r\n",Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage connectKlipperCommand = {"~M640\r\n",Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage connectLegacyCommand = {"~M650\r\n",Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage nozzlePosCommand = {"~M114\r\n", Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage deviceInfoCommand = {"~M115\r\n", Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage statusCommand = {"~M119\r\n",Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage tempStatusCommand = {"~M105\r\n", Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage printStatusCommand = {"~M27\r\n", Slic3r::Utils::Command};
Slic3r::Utils::SerialMessage saveFileCommand = {"~M29\r\n",Slic3r::Utils::Command};
bool upload_local_api(PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn) const;
bool test_local_api(wxString& msg) const;
bool request_local_api_json(const std::string& path, const std::string& body, std::string& response_body, wxString& error_msg) const;
std::string make_http_url(const std::string& path) const;
std::string extract_host_name() const;
bool connect(wxString& msg) const;
bool start_print(wxString& msg, const std::string& filename) const;
};
} // namespace Slic3r
#endif