Files
OrcaSlicer/src/slic3r/Utils/NetworkAgentFactory.cpp
T
grant0013 d1a33d2efd Add CrealityPrintAgent for CFS filament sync
Subclass of MoonrakerPrinterAgent for K-series Creality printers
(K2, K2 Plus, K2 Pro) with CFS support. Registers in
NetworkAgentFactory under host_type=crealityprint. Overrides
fetch_filament_info() to defer to base when the host is not a
CFS-capable K-series board, otherwise query the boxsInfo WebSocket
on port 9999, parse the box hierarchy into CFSSlot[], and publish
each loaded slot as an AmsTrayData entry via build_ams_payload()
so they surface in Orca filament UI.

boxsInfo schema reference (verified against K2 Combo F021 firmware
v1.1.260206):
  materialBoxs[].materials[] fields: id, state, vendor, type, name,
  color, pressure, rfid, percent. state=1 means loaded; box.type=0
  is a CFS unit, type=1 is the external spool holder (handled by
  the upload dialog).

Accepted CFS boxes are renumbered sequentially since the K2 raw
box.id has gaps for the external spool holder. Model detection is
delegated to CrealityPrint::supports_multi_color_print() added in
PR #13291.
2026-05-19 16:01:13 +00:00

193 lines
6.9 KiB
C++

#include "NetworkAgentFactory.hpp"
#include "IPrinterAgent.hpp"
#include "ICloudServiceAgent.hpp"
#include "BBLPrinterAgent.hpp"
#include "OrcaPrinterAgent.hpp"
#include "QidiPrinterAgent.hpp"
#include "SnapmakerPrinterAgent.hpp"
#include "MoonrakerPrinterAgent.hpp"
#include "CrealityPrintAgent.hpp"
#include <boost/log/trivial.hpp>
#include <map>
#include <mutex>
namespace Slic3r {
namespace {
static std::mutex s_registry_mutex;
std::map<std::string, PrinterAgentInfo>& get_printer_agents()
{
static std::map<std::string, PrinterAgentInfo> agents;
return agents;
}
std::map<std::string, std::shared_ptr<IPrinterAgent>>& get_printer_agent_cache()
{
static std::map<std::string, std::shared_ptr<IPrinterAgent>> cache;
return cache;
}
// Helper to register a printer agent type with the standard factory pattern.
// AgentTypes that take a log_dir constructor arg use the default; BBLPrinterAgent
// (no log_dir) is registered separately.
template<typename T>
void register_agent()
{
auto info = T::get_agent_info_static();
NetworkAgentFactory::register_printer_agent(
info.id, info.name,
[](std::shared_ptr<ICloudServiceAgent> cloud_agent,
const std::string& log_dir) -> std::shared_ptr<IPrinterAgent> {
auto agent = std::make_shared<T>(log_dir);
if (cloud_agent)
agent->set_cloud_agent(cloud_agent);
return agent;
});
}
} // anonymous namespace
bool NetworkAgentFactory::register_printer_agent(const std::string& id, const std::string& display_name, PrinterAgentFactory factory)
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
auto& agents = get_printer_agents();
return agents.emplace(id, PrinterAgentInfo(id, display_name, std::move(factory))).second;
}
bool NetworkAgentFactory::is_printer_agent_registered(const std::string& id)
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
auto& agents = get_printer_agents();
return agents.find(id) != agents.end();
}
const PrinterAgentInfo* NetworkAgentFactory::get_printer_agent_info(const std::string& id)
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
auto& agents = get_printer_agents();
auto it = agents.find(id);
return (it != agents.end()) ? &it->second : nullptr;
}
std::vector<PrinterAgentInfo> NetworkAgentFactory::get_registered_printer_agents()
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
auto& agents = get_printer_agents();
std::vector<PrinterAgentInfo> result;
result.reserve(agents.size());
for (const auto& pair : agents) {
result.push_back(pair.second);
}
return result;
}
std::shared_ptr<IPrinterAgent> NetworkAgentFactory::create_printer_agent_by_id(const std::string& id,
std::shared_ptr<ICloudServiceAgent> cloud_agent,
const std::string& log_dir)
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
// Check cache first
auto& cache = get_printer_agent_cache();
auto cache_it = cache.find(id);
if (cache_it != cache.end()) {
BOOST_LOG_TRIVIAL(info) << "Reusing cached printer agent: " << id;
if (cloud_agent)
cache_it->second->set_cloud_agent(cloud_agent);
return cache_it->second;
}
// Not cached — create via factory
auto& agents = get_printer_agents();
auto it = agents.find(id);
if (it == agents.end()) {
BOOST_LOG_TRIVIAL(warning) << "Unknown printer agent ID: " << id;
return nullptr;
}
auto agent = it->second.factory(cloud_agent, log_dir);
if (agent) {
BOOST_LOG_TRIVIAL(info) << "Created and cached printer agent: " << id;
cache[id] = agent;
}
return agent;
}
void NetworkAgentFactory::clear_printer_agent_cache()
{
std::lock_guard<std::mutex> lock(s_registry_mutex);
auto& cache = get_printer_agent_cache();
for (auto& pair : cache) {
if (pair.second)
pair.second->disconnect_printer();
}
cache.clear();
BOOST_LOG_TRIVIAL(info) << "Printer agent cache cleared";
}
void NetworkAgentFactory::register_all_agents()
{
register_agent<OrcaPrinterAgent>();
register_agent<QidiPrinterAgent>();
register_agent<SnapmakerPrinterAgent>();
register_agent<CrealityPrintAgent>(); // Must come BEFORE MoonrakerPrinterAgent —
// CrealityPrintAgent extends Moonraker behaviour
// for K-series boards with CFS support.
register_agent<MoonrakerPrinterAgent>();
// BBLPrinterAgent takes no constructor args, so register manually
{
auto info = BBLPrinterAgent::get_agent_info_static();
register_printer_agent(info.id, info.name,
[](std::shared_ptr<ICloudServiceAgent> cloud_agent,
const std::string& /*log_dir*/) -> std::shared_ptr<IPrinterAgent> {
auto agent = std::make_shared<BBLPrinterAgent>();
if (cloud_agent)
agent->set_cloud_agent(cloud_agent);
return agent;
});
}
}
std::unique_ptr<NetworkAgent> create_agent_from_config(const std::string& log_dir, AppConfig* app_config)
{
if (!app_config)
return std::make_unique<NetworkAgent>(nullptr, nullptr);
// Always create Orca cloud agent as the primary provider
auto cloud_agent = NetworkAgentFactory::create_cloud_agent(ORCA_CLOUD_PROVIDER, log_dir);
if (!cloud_agent) {
BOOST_LOG_TRIVIAL(error) << "Failed to create cloud agent";
}
auto agent = std::make_unique<NetworkAgent>(std::move(cloud_agent), nullptr);
if (agent) {
// create orca cloud agent first
auto* orca_cloud = dynamic_cast<OrcaCloudServiceAgent*>(agent->get_cloud_agent().get());
if (orca_cloud) {
orca_cloud->configure_urls(app_config);
}
// Initialize third-party cloud agents from config
auto providers = app_config->get_cloud_providers();
for (const auto& provider : providers) {
if (provider == ORCA_CLOUD_PROVIDER)
continue; // Primary agent already created above
auto third_party_agent = NetworkAgentFactory::create_cloud_agent(provider, log_dir);
if (third_party_agent) {
agent->add_cloud_agent(provider, std::move(third_party_agent));
BOOST_LOG_TRIVIAL(info) << "Initialized third-party cloud agent: " << provider;
}
}
}
return agent;
}
} // namespace Slic3r