File indexing completed on 2025-07-02 08:55:20
0001
0002 #include "JWiringService.h"
0003 #include "toml.hpp"
0004 #include <exception>
0005 #include <memory>
0006 #include <set>
0007
0008 namespace jana::services {
0009
0010 JWiringService::JWiringService() {
0011 SetPrefix("jana");
0012 }
0013
0014 void JWiringService::Init() {
0015 LOG_INFO(GetLogger()) << "Initializing JWiringService" << LOG_END;
0016
0017
0018
0019
0020
0021 if (!m_wirings_input_file().empty()) {
0022 AddWiringFile(*m_wirings_input_file);
0023 }
0024 }
0025
0026 void JWiringService::AddWirings(std::vector<std::unique_ptr<Wiring>>& wirings_bundle, const std::string& bundle_source) {
0027
0028 std::set<std::string> prefixes_in_bundle;
0029 for (auto& wiring: wirings_bundle) {
0030
0031
0032 auto bundle_it = prefixes_in_bundle.find(wiring->prefix);
0033 if (bundle_it != prefixes_in_bundle.end()) {
0034 throw JException("Duplicated prefix '%s' in wiring bundle '%s'", wiring->prefix.c_str(), bundle_source.c_str());
0035 }
0036 prefixes_in_bundle.insert(wiring->prefix);
0037
0038
0039 auto it = m_wirings_from_prefix.find(wiring->prefix);
0040 if (it == m_wirings_from_prefix.end()) {
0041
0042 m_wirings_from_prefix[wiring->prefix] = wiring.get();
0043 m_wirings_from_type_and_plugin_names[{wiring->type_name, wiring->plugin_name}].push_back(wiring.get());
0044 m_wirings.push_back(std::move(wiring));
0045 }
0046 else {
0047
0048
0049 if (wiring->type_name != it->second->type_name) {
0050 throw JException("Wiring mismatch: type name '%s' vs '%s'", wiring->type_name.c_str(), it->second->type_name.c_str());
0051 }
0052 if (wiring->plugin_name != it->second->plugin_name) {
0053 throw JException("Wiring mismatch: plugin name '%s' vs '%s'", wiring->plugin_name.c_str(), it->second->plugin_name.c_str());
0054 }
0055 Overlay(*(it->second), *wiring);
0056
0057
0058 }
0059 }
0060
0061 wirings_bundle.clear();
0062 }
0063
0064 void JWiringService::AddWirings(const toml::table& table, const std::string& source) {
0065
0066 std::vector<std::unique_ptr<Wiring>> wirings;
0067 auto facs = table["factory"].as_array();
0068 if (facs == nullptr) {
0069 throw JException("No factories found!");
0070 }
0071 for (const auto& fac : *facs) {
0072 auto wiring = std::make_unique<Wiring>();
0073
0074 if (fac.as_table() == nullptr) {
0075 throw JException("Invalid format: 'factory' is not a table");
0076 }
0077 auto& f = *fac.as_table();
0078
0079 wiring->plugin_name = f["plugin_name"].value<std::string>().value_or("");
0080 wiring->type_name = f["type_name"].value<std::string>().value();
0081 wiring->prefix = f["prefix"].value<std::string>().value();
0082
0083 wiring->level = parseEventLevel(f["level"].value_or<std::string>("None"));
0084
0085 auto input_names = f["input_names"].as_array();
0086 if (input_names != nullptr) {
0087 for (const auto& input_name : *input_names) {
0088 wiring->input_names.push_back(input_name.value<std::string>().value());
0089 }
0090 }
0091
0092 auto variadic_input_names = f["variadic_input_names"].as_array();
0093 if (variadic_input_names != nullptr) {
0094 for (const auto& input_name_vec : *variadic_input_names) {
0095 std::vector<std::string> temp;
0096 for (const auto& input_name : *(input_name_vec.as_array())) {
0097 temp.push_back(input_name.as_string()->get());
0098 }
0099 wiring->variadic_input_names.push_back(temp);
0100 }
0101 }
0102
0103 auto input_levels = f["input_levels"].as_array();
0104 if (input_levels != nullptr) {
0105 for (const auto& input_level : *input_levels) {
0106 wiring->input_levels.push_back(parseEventLevel(input_level.value<std::string>().value()));
0107 }
0108 }
0109
0110 auto variadic_input_levels = f["variadic_input_levels"].as_array();
0111 if (variadic_input_levels != nullptr) {
0112 for (const auto& input_level : *variadic_input_levels) {
0113 wiring->variadic_input_levels.push_back(parseEventLevel(input_level.value<std::string>().value()));
0114 }
0115 }
0116
0117 auto output_names = f["output_names"].as_array();
0118 if (output_names != nullptr) {
0119 for (const auto& output_name : *f["output_names"].as_array()) {
0120 wiring->output_names.push_back(output_name.value<std::string>().value());
0121 }
0122 }
0123
0124 auto variadic_output_names = f["variadic_output_names"].as_array();
0125 if (variadic_output_names != nullptr) {
0126 for (const auto& output_name_vec : *variadic_output_names) {
0127 std::vector<std::string> temp;
0128 for (const auto& output_name : *(output_name_vec.as_array())) {
0129 temp.push_back(output_name.as_string()->get());
0130 }
0131 wiring->variadic_output_names.push_back(temp);
0132 }
0133 }
0134
0135
0136 auto configs = f["configs"].as_table();
0137 if (configs != nullptr) {
0138 for (const auto& config : *configs) {
0139 std::string config_name(config.first);
0140
0141
0142 wiring->configs[config_name] = config.second.value<std::string>().value();
0143 }
0144 }
0145
0146 wirings.push_back(std::move(wiring));
0147 }
0148 AddWirings(wirings, source);
0149 }
0150
0151 void JWiringService::AddWiringFile(const std::string& filename) {
0152 try {
0153 auto tbl = toml::parse_file(filename);
0154 AddSharedParameters(tbl, filename);
0155 AddWirings(tbl, filename);
0156 }
0157 catch (const toml::parse_error& err) {
0158 auto e = JException("Error parsing TOML file: '%s'", filename.c_str());
0159 e.nested_exception = std::current_exception();
0160 throw e;
0161 }
0162 }
0163
0164 const JWiringService::Wiring* JWiringService::GetWiring(const std::string& prefix) const {
0165 auto it = m_wirings_from_prefix.find(prefix);
0166 if (it == m_wirings_from_prefix.end()) {
0167 return nullptr;
0168 }
0169 return it->second;
0170 }
0171
0172 const std::vector<JWiringService::Wiring*>&
0173 JWiringService::GetWirings(const std::string& plugin_name, const std::string& type_name) const {
0174
0175 auto it = m_wirings_from_type_and_plugin_names.find({type_name, plugin_name});
0176 if (it == m_wirings_from_type_and_plugin_names.end()) {
0177 return m_no_wirings;
0178 }
0179 return it->second;
0180 }
0181
0182
0183 void JWiringService::Overlay(Wiring& above, const Wiring& below) {
0184
0185
0186 if (above.plugin_name != below.plugin_name) throw JException("Plugin name mismatch!");
0187 if (above.type_name != below.type_name) throw JException("Type name mismatch!");
0188
0189 if (above.input_names.empty() && !below.input_names.empty()) {
0190 above.input_names = std::move(below.input_names);
0191 }
0192 if (above.input_levels.empty() && !below.input_levels.empty()) {
0193 above.input_levels = std::move(below.input_levels);
0194 }
0195 if (above.output_names.empty() && !below.output_names.empty()) {
0196 above.output_names = std::move(below.output_names);
0197 }
0198 for (const auto& [key, val] : below.configs) {
0199 if (above.configs.find(key) == above.configs.end()) {
0200 above.configs[key] = val;
0201 }
0202 }
0203 }
0204
0205
0206 void JWiringService::AddSharedParameters(const toml::table& table, const std::string& ) {
0207 auto shared_params = table["configs"].as_table();
0208 if (shared_params == nullptr) {
0209 LOG_INFO(GetLogger()) << "No configs found!" << LOG_END;
0210 return;
0211 }
0212 for (const auto& param : *shared_params) {
0213 std::string key(param.first);
0214 std::string val = *param.second.value<std::string>();
0215 m_shared_parameters[key] = val;
0216 }
0217 }
0218
0219
0220
0221 const std::map<std::string, std::string>& JWiringService::GetSharedParameters() const {
0222 return m_shared_parameters;
0223 }
0224
0225
0226 }