#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