From c5c195ff5318f00d544c0fbceb133abcc4ba7a5a Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Wed, 23 Jul 2025 22:33:05 +0200 Subject: MVP --- daemon/src/config.cpp | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 daemon/src/config.cpp (limited to 'daemon/src/config.cpp') diff --git a/daemon/src/config.cpp b/daemon/src/config.cpp new file mode 100644 index 0000000..b88fd0f --- /dev/null +++ b/daemon/src/config.cpp @@ -0,0 +1,179 @@ +#include "config.h" + +#include "tomlplusplus/toml.hpp" + +#include + +#include + +namespace midi_router +{ + +static size_t write_function(void *ptr, size_t size, size_t nmemb, std::string* data) { + data->append((char*) ptr, size * nmemb); + return size * nmemb; +} + +static long curl(std::string url, std::string & response) +{ + auto curl = curl_easy_init(); + if (!curl) { + return -1; + } + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + curl_easy_perform(curl); + + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + + curl_easy_cleanup(curl); + + return response_code; +} + +Config_Loader::Config_Loader(std::string url) +{ + auto code = curl(url, m_file_contents); + if (code != 200) + { + std::cerr << "Failed to fetch config file with code " << code << "\n"; + return; + } + + auto toml_config = toml::parse(m_file_contents); + + auto* devices = toml_config["devices"].as_table(); + if (!devices) + { + std::cerr << "Expected \"devices\" to be a table.\n"; + return; + } + + for (auto&& [id, name] : *devices) + { + m_device_map[name.as_string()->get()] = id.str(); + } +} + +Device_Map const & +Config_Loader::get_device_map() const +{ + return m_device_map; +} + +static void +add_to_routes(Device_Id const & from_device, Route_Table & rt, toml::table & routes, Connection_Manager const & cm) +{ + for (auto&& [key, types_node] : routes) + { + std::string to_device {key.str()}; + auto types = types_node.as_array(); + if (!types) + { + std::cerr << "Unable to parse note types for route from " << from_device << " to " << to_device << "\n"; + continue; + } + for (auto & type : *types) + { + std::string type_name = type.as_string()->get(); + if (type_name == "all") + { + for (auto&& [name, mt] : string2type) + { + rt[from_device][mt].push_back(cm.get_sender(to_device)); + } + } + else + { + Message_Type mt = string2type.at(type.as_string()->get()); + rt[from_device][mt].push_back(cm.get_sender(to_device)); + } + } + } +} + +static void +add_type_routes(Device_Map const & device_map, Device_Id const & from_device, Route_Table & rt, toml::table & routes, Connection_Manager const & cm) +{ + for (auto&& [key, devices_node] : routes) + { + std::string type {key.str()}; + auto devices = devices_node.as_array(); + if (!devices) + { + std::cerr << "Unable to parse devices for route from " << from_device << " with type " << type << "\n"; + continue; + } + for (auto & device : *devices) + { + Message_Type mt = string2type.at(type); + std::string to_device = device.as_string()->get(); + if (to_device == "all") + { + for (auto&& [name, id] : device_map) + { + if (id == from_device) continue; + rt[from_device][mt].push_back(cm.get_sender(id)); + } + } + else + { + rt[from_device][mt].push_back(cm.get_sender(to_device)); + } + } + } +} + +Route_Table const & +Config_Loader::compile_route_table(Connection_Manager const & cm) +{ + m_route_table.clear(); + + auto toml_config = toml::parse(m_file_contents); + + for (auto && [name, id] : m_device_map) + { + auto * to_routes = toml_config["route"]["from"][id]["to"].as_table(); + if (to_routes) + { + add_to_routes(id, m_route_table, *to_routes, cm); + } + + auto * type_routes = toml_config["route"]["from"][id]["type"].as_table(); + if (type_routes) + { + add_type_routes(m_device_map, id, m_route_table, *type_routes, cm); + } + } + + return m_route_table; +} + +void +Config_Loader::print_route_table() const +{ + std::cout << "Routes ===========================================================\n"; + for (auto && [source_id, message_types] : m_route_table) + { + std::cout << "From " << source_id << ":\n"; + for (auto && [type, targets] : message_types) + { + std::cout << "\t" << type2string.at(type) << ": "; + for (auto const & target : targets) + { + std::cout << target.get().get_id() << " "; + } + std::cout << "\n"; + } + } + std::cout << "==================================================================\n"; +} + +} // namespace midi_router -- cgit v1.2.3