mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-19 15:03:05 +00:00
Translate filament ids at the printer boundary
Orca content-addresses every system filament, Bambu's included, but a printer, its AMS and its vendor's cloud know only that vendor's own catalog ids. The printer agent now translates between the two: outbound MQTT and FTP traffic, the AMS mapping sent with a print job, and the ids written into a 3mf bound for the printer all leave in the printer's own ids, while status messages, loaded projects and SD-card prints arrive in Orca's. An id with no mapping passes through unchanged, and an agent whose printers already speak Orca's ids translates nothing at all. Bambu's map is generated from BambuStudio's own shipped bundle; a missing or unreadable file leaves every lookup an identity rather than taking the app down. The profile check validates the map's shape, and profile CI now runs on the paths that can change it. docs/HLSD/filament_id.md records the places the map deliberately does not reach.
This commit is contained in:
@@ -1,11 +1,121 @@
|
||||
#include "BBLPrinterAgent.hpp"
|
||||
#include "BBLNetworkPlugin.hpp"
|
||||
#include "NetworkAgentFactory.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
// Bambu's own catalog ids for every filament this app ships, Bambu's own included, since Orca
|
||||
// content-addresses those too. Keyed both ways so each of the four translation entry points
|
||||
// below is a single lookup. Loaded once per process, on first use. A missing or malformed file
|
||||
// logs once and leaves both maps empty, so every translation degrades to identity. Same shape
|
||||
// as DevFilaBlacklist::load_filaments_blacklist_config.
|
||||
struct BambuFilamentIdMap { std::unordered_map<std::string, std::string> to_bambu, to_orca; };
|
||||
|
||||
const BambuFilamentIdMap& bambu_filament_id_map()
|
||||
{
|
||||
static const BambuFilamentIdMap map = [] {
|
||||
BambuFilamentIdMap m;
|
||||
const std::string path = resources_dir() + "/printers/bambu_filament_ids.json";
|
||||
try {
|
||||
boost::nowide::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bambu filament id map not found, ids pass through untranslated: " << path;
|
||||
return m;
|
||||
}
|
||||
json doc;
|
||||
file >> doc;
|
||||
for (const auto& [orca_filament_id, row] : doc.at("filaments").items()) {
|
||||
const std::string bambu_id = row.at("bambu_id").get<std::string>();
|
||||
m.to_bambu.emplace(orca_filament_id, bambu_id);
|
||||
m.to_orca.emplace(bambu_id, orca_filament_id);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Bambu filament id map unreadable, ids pass through untranslated: " << e.what();
|
||||
m = {};
|
||||
}
|
||||
return m;
|
||||
}();
|
||||
return map;
|
||||
}
|
||||
|
||||
// Rewrites every string under "tray_info_idx", "filament_id" or "filamentId", at any depth, in place.
|
||||
void rewrite_filament_ids(json& j, const std::unordered_map<std::string, std::string>& map)
|
||||
{
|
||||
if (j.is_object()) {
|
||||
for (auto& [key, value] : j.items()) {
|
||||
if (value.is_string() && (key == "tray_info_idx" || key == "filament_id" || key == "filamentId")) {
|
||||
auto it = map.find(value.get_ref<const std::string&>());
|
||||
if (it != map.end())
|
||||
value = it->second;
|
||||
} else
|
||||
rewrite_filament_ids(value, map);
|
||||
}
|
||||
} else if (j.is_array())
|
||||
for (auto& element : j)
|
||||
rewrite_filament_ids(element, map);
|
||||
}
|
||||
|
||||
// Text that does not parse as JSON, or that mentions none of the id keys, comes back byte-identical.
|
||||
std::string rewrite_filament_ids(std::string text, const std::unordered_map<std::string, std::string>& map)
|
||||
{
|
||||
if (map.empty() || (text.find("tray_info_idx") == std::string::npos && text.find("filament_id") == std::string::npos &&
|
||||
text.find("filamentId") == std::string::npos))
|
||||
return text; // nothing to map, skip the parse (moved, not copied)
|
||||
try {
|
||||
json j = json::parse(text);
|
||||
rewrite_filament_ids(j, map);
|
||||
return j.dump();
|
||||
} catch (const std::exception&) {
|
||||
return text; // not JSON: forward as received
|
||||
}
|
||||
}
|
||||
|
||||
// Wraps an inbound message callback so every Bambu id it delivers arrives already translated.
|
||||
// A null fn is a deregistration (see GUI_App.cpp's shutdown phase 1 and NetworkAgent::apply_printer_callbacks
|
||||
// clearing callbacks with {}), and must stay null rather than become a live wrapper around an empty target.
|
||||
OnMessageFn to_orca_messages(OnMessageFn fn)
|
||||
{
|
||||
if (!fn)
|
||||
return fn;
|
||||
return [fn = std::move(fn)](std::string dev_id, std::string msg) { fn(std::move(dev_id), BBLPrinterAgent::to_orca_payload(std::move(msg))); };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string BBLPrinterAgent::to_orca_filament_id(const std::string& printer_filament_id) const
|
||||
{
|
||||
const auto& map = bambu_filament_id_map().to_orca;
|
||||
auto it = map.find(printer_filament_id);
|
||||
return it != map.end() ? it->second : printer_filament_id;
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::from_orca_filament_id(const std::string& orca_filament_id) const
|
||||
{
|
||||
const auto& map = bambu_filament_id_map().to_bambu;
|
||||
auto it = map.find(orca_filament_id);
|
||||
return it != map.end() ? it->second : orca_filament_id;
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::to_orca_payload(std::string json_text)
|
||||
{
|
||||
return rewrite_filament_ids(std::move(json_text), bambu_filament_id_map().to_orca);
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::from_orca_payload(std::string json_text)
|
||||
{
|
||||
return rewrite_filament_ids(std::move(json_text), bambu_filament_id_map().to_bambu);
|
||||
}
|
||||
|
||||
BBLPrinterAgent::BBLPrinterAgent() = default;
|
||||
|
||||
BBLPrinterAgent::~BBLPrinterAgent() = default;
|
||||
@@ -22,6 +132,7 @@ void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
|
||||
|
||||
int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag)
|
||||
{
|
||||
json_str = from_orca_payload(std::move(json_str));
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message();
|
||||
@@ -67,6 +178,7 @@ int BBLPrinterAgent::disconnect_printer()
|
||||
|
||||
int BBLPrinterAgent::send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag)
|
||||
{
|
||||
json_str = from_orca_payload(std::move(json_str));
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message_to_printer();
|
||||
@@ -321,6 +433,7 @@ int dispatch_start(CurrentFn func, PrintParams& params, const CallbackFns&... ca
|
||||
auto agent = plugin.get_agent();
|
||||
if (!func || !agent)
|
||||
return -1;
|
||||
params.ams_mapping_info = BBLPrinterAgent::from_orca_payload(std::move(params.ams_mapping_info));
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy:
|
||||
return reinterpret_cast<LegacyFn>(func)(agent, BBLNetworkPlugin::as_legacy(params), callbacks...);
|
||||
@@ -408,7 +521,7 @@ int BBLPrinterAgent::set_on_message_fn(OnMessageFn fn)
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_set_on_message_fn();
|
||||
if (func && agent) {
|
||||
return func(agent, fn);
|
||||
return func(agent, to_orca_messages(std::move(fn)));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -441,7 +554,7 @@ int BBLPrinterAgent::set_on_local_message_fn(OnMessageFn fn)
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_set_on_local_message_fn();
|
||||
if (func && agent) {
|
||||
return func(agent, fn);
|
||||
return func(agent, to_orca_messages(std::move(fn)));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user