aboutsummaryrefslogtreecommitdiffstats
path: root/daemon/src/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/src/config.cpp')
-rw-r--r--daemon/src/config.cpp179
1 files changed, 179 insertions, 0 deletions
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 <curl/curl.h>
+
+#include <iostream>
+
+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