File indexing completed on 2025-01-18 10:17:35
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 void JWiringService::Init() {
0011 LOG_INFO(GetLogger()) << "Initializing JWiringService" << LOG_END;
0012
0013
0014
0015
0016
0017 if (!m_wirings_input_file().empty()) {
0018 AddWirings(*m_wirings_input_file);
0019 }
0020 }
0021
0022 void JWiringService::AddWirings(std::vector<std::unique_ptr<Wiring>>& wirings_bundle, const std::string& bundle_source) {
0023
0024 std::set<std::string> prefixes_in_bundle;
0025 for (auto& wiring: wirings_bundle) {
0026
0027
0028 auto bundle_it = prefixes_in_bundle.find(wiring->prefix);
0029 if (bundle_it != prefixes_in_bundle.end()) {
0030 throw JException("Duplicated prefix '%s' in wiring bundle '%s'", wiring->prefix.c_str(), bundle_source.c_str());
0031 }
0032 prefixes_in_bundle.insert(wiring->prefix);
0033
0034
0035 auto it = m_wirings_from_prefix.find(wiring->prefix);
0036 if (it == m_wirings_from_prefix.end()) {
0037
0038 m_wirings_from_prefix[wiring->prefix] = wiring.get();
0039 m_wirings_from_type_and_plugin_names[{wiring->type_name, wiring->plugin_name}].push_back(wiring.get());
0040 m_wirings.push_back(std::move(wiring));
0041 }
0042 else {
0043
0044
0045 if (wiring->type_name != it->second->type_name) {
0046 throw JException("Wiring mismatch: type name '%s' vs '%s'", wiring->type_name.c_str(), it->second->type_name.c_str());
0047 }
0048 if (wiring->plugin_name != it->second->plugin_name) {
0049 throw JException("Wiring mismatch: plugin name '%s' vs '%s'", wiring->plugin_name.c_str(), it->second->plugin_name.c_str());
0050 }
0051 Overlay(*(it->second), *wiring);
0052
0053
0054 }
0055 }
0056
0057 wirings_bundle.clear();
0058 }
0059
0060 void JWiringService::AddWirings(const toml::table& table, const std::string& source) {
0061
0062 std::vector<std::unique_ptr<Wiring>> wirings;
0063 auto facs = table["factory"].as_array();
0064 if (facs == nullptr) {
0065 throw JException("No factories found!");
0066 }
0067 for (const auto& fac : *facs) {
0068 auto wiring = std::make_unique<Wiring>();
0069
0070 if (fac.as_table() == nullptr) {
0071 throw JException("Invalid format: 'factory' is not a table");
0072 }
0073 auto& f = *fac.as_table();
0074
0075 wiring->plugin_name = f["plugin_name"].value<std::string>().value_or("");
0076 wiring->type_name = f["type_name"].value<std::string>().value();
0077 wiring->prefix = f["prefix"].value<std::string>().value();
0078
0079 wiring->level = parseEventLevel(f["level"].value_or<std::string>("None"));
0080
0081 auto input_names = f["input_names"].as_array();
0082 if (input_names != nullptr) {
0083 for (const auto& input_name : *f["input_names"].as_array()) {
0084 wiring->input_names.push_back(input_name.value<std::string>().value());
0085 }
0086 }
0087
0088 auto output_names = f["output_names"].as_array();
0089 if (output_names != nullptr) {
0090 for (const auto& output_name : *f["output_names"].as_array()) {
0091 wiring->output_names.push_back(output_name.value<std::string>().value());
0092 }
0093 }
0094
0095 auto input_levels = f["input_levels"].as_array();
0096 if (input_levels != nullptr) {
0097 for (const auto& input_level : *input_levels) {
0098 wiring->input_levels.push_back(parseEventLevel(input_level.value<std::string>().value()));
0099 }
0100 }
0101
0102 auto configs = f["configs"].as_table();
0103 if (configs != nullptr) {
0104 for (const auto& config : *configs) {
0105 std::string config_name(config.first);
0106
0107
0108 wiring->configs[config_name] = config.second.value<std::string>().value();
0109 }
0110 }
0111
0112 wirings.push_back(std::move(wiring));
0113 }
0114 AddWirings(wirings, source);
0115 }
0116
0117 void JWiringService::AddWirings(const std::string& filename) {
0118 try {
0119 auto tbl = toml::parse_file(filename);
0120 AddWirings(tbl, filename);
0121 }
0122 catch (const toml::parse_error& err) {
0123 auto e = JException("Error parsing TOML file: '%s'", filename.c_str());
0124 e.nested_exception = std::current_exception();
0125 throw e;
0126 }
0127 }
0128
0129 const JWiringService::Wiring* JWiringService::GetWiring(const std::string& prefix) const {
0130 auto it = m_wirings_from_prefix.find(prefix);
0131 if (it == m_wirings_from_prefix.end()) {
0132 return nullptr;
0133 }
0134 return it->second;
0135 }
0136
0137 const std::vector<JWiringService::Wiring*>&
0138 JWiringService::GetWirings(const std::string& plugin_name, const std::string& type_name) const {
0139
0140 auto it = m_wirings_from_type_and_plugin_names.find({type_name, plugin_name});
0141 if (it == m_wirings_from_type_and_plugin_names.end()) {
0142 return m_no_wirings;
0143 }
0144 return it->second;
0145 }
0146
0147
0148 void JWiringService::Overlay(Wiring& above, const Wiring& below) {
0149
0150
0151 if (above.plugin_name != below.plugin_name) throw JException("Plugin name mismatch!");
0152 if (above.type_name != below.type_name) throw JException("Type name mismatch!");
0153
0154 if (above.input_names.empty() && !below.input_names.empty()) {
0155 above.input_names = std::move(below.input_names);
0156 }
0157 if (above.input_levels.empty() && !below.input_levels.empty()) {
0158 above.input_levels = std::move(below.input_levels);
0159 }
0160 if (above.output_names.empty() && !below.output_names.empty()) {
0161 above.output_names = std::move(below.output_names);
0162 }
0163 for (const auto& [key, val] : below.configs) {
0164 if (above.configs.find(key) == above.configs.end()) {
0165 above.configs[key] = val;
0166 }
0167 }
0168 }
0169
0170
0171
0172 }