feat(automation): GUI_App owns automation server lifecycle (opt-in)

This commit is contained in:
SoftFever
2026-06-03 03:58:01 +08:00
parent b54cc75362
commit 622272e674
2 changed files with 54 additions and 0 deletions

View File

@@ -6,6 +6,9 @@
#include "GUI_ObjectList.hpp"
#include "slic3r/GUI/UserManager.hpp"
#include "slic3r/GUI/TaskManager.hpp"
#include "slic3r/GUI/Automation/AutomationServer.hpp"
#include "slic3r/GUI/Automation/WxUiBackend.hpp"
#include "slic3r/GUI/Automation/JsonRpcDispatcher.hpp"
#include "format.hpp"
#include "libslic3r_version.h"
#include "Downloader.hpp"
@@ -730,6 +733,12 @@ void GUI_App::post_init()
if (! this->initialized())
throw Slic3r::RuntimeError("Calling post_init() while not yet initialized");
// UI automation: start the localhost server only when --automation-server set a port.
if (this->init_params != nullptr && this->init_params->automation_port > 0) {
m_automation_port = this->init_params->automation_port;
start_automation_server();
}
m_open_method = "double_click";
bool switch_to_3d = false;
@@ -2464,6 +2473,7 @@ bool GUI_App::OnInit()
int GUI_App::OnExit()
{
stop_http_server();
stop_automation_server();
stop_sync_user_preset();
if (m_device_manager) {
@@ -7082,6 +7092,33 @@ void GUI_App::stop_http_server()
m_http_server.stop();
}
void GUI_App::start_automation_server()
{
if (m_automation_port <= 0) return; // disabled
if (m_automation_server) return; // already running
using namespace Slic3r::GUI::Automation;
m_automation_backend.reset(new WxUiBackend());
m_automation_dispatcher.reset(new JsonRpcDispatcher(*m_automation_backend));
m_automation_server.reset(new AutomationServer((unsigned short)m_automation_port));
JsonRpcDispatcher* disp = m_automation_dispatcher.get();
m_automation_server->set_handler(
[disp](const std::string& body) { return disp->handle_request(body); });
m_automation_server->set_health_text(
std::string("OrcaSlicer automation server v") + kAutomationVersion);
m_automation_server->start();
BOOST_LOG_TRIVIAL(warning)
<< "UI automation server ENABLED on 127.0.0.1:" << m_automation_port
<< " (input injection is active)";
}
void GUI_App::stop_automation_server()
{
if (m_automation_server) m_automation_server->stop();
m_automation_server.reset();
m_automation_dispatcher.reset();
m_automation_backend.reset();
}
void GUI_App::switch_staff_pick(bool on)
{
mainframe->m_webview->SendDesignStaffpick(on);

View File

@@ -86,6 +86,14 @@ class ModelMallDialog;
class PingCodeBindDialog;
class NetworkErrorDialog;
// UI automation (opt-in). Forward declarations so GUI_App can own the stack
// by unique_ptr without pulling the Automation headers into this header.
namespace Automation {
class AutomationServer;
class WxUiBackend;
class JsonRpcDispatcher;
}
enum FileType
{
@@ -335,6 +343,11 @@ private:
HttpServer m_http_server;
bool m_show_gcode_window{true};
boost::thread m_check_network_thread;
// --- UI automation (opt-in; off unless --automation-server) ---
std::unique_ptr<Slic3r::GUI::Automation::AutomationServer> m_automation_server;
std::unique_ptr<Slic3r::GUI::Automation::WxUiBackend> m_automation_backend;
std::unique_ptr<Slic3r::GUI::Automation::JsonRpcDispatcher> m_automation_dispatcher;
public:
//try again when subscription fails
void on_start_subscribe_again(std::string dev_id);
@@ -371,6 +384,10 @@ public:
// NOTE: Task 17 extends the automation lifecycle (server/backend) around this
// accessor; here we only add the minimal flag/accessor the hooks depend on.
bool is_automation_enabled() const { return m_automation_port > 0; }
// UI automation lifecycle: wires WxUiBackend -> JsonRpcDispatcher -> AutomationServer
// and starts/stops the localhost server. Both no-op when automation is off.
void start_automation_server();
void stop_automation_server();
bool is_recreating_gui() const { return m_is_recreating_gui; }
std::string logo_name() const { return is_editor() ? "OrcaSlicer" : "OrcaSlicer-gcodeviewer"; }