diff --git a/cv-node/include/nlohmann/json.hpp b/common/cpp/include/nlohmann/json.hpp similarity index 100% rename from cv-node/include/nlohmann/json.hpp rename to common/cpp/include/nlohmann/json.hpp diff --git a/net/cpp/include/ftl/net/universe.hpp b/net/cpp/include/ftl/net/universe.hpp index d34b842fc4499231ac1e74ccc30a92e9b4b0c140..8f84287fefb979d7fd2482051b3339fb99c92884 100644 --- a/net/cpp/include/ftl/net/universe.hpp +++ b/net/cpp/include/ftl/net/universe.hpp @@ -5,6 +5,7 @@ #include <ftl/net/listener.hpp> #include <ftl/net/dispatcher.hpp> #include <ftl/uuid.hpp> +#include <nlohmann/json.hpp> #include <vector> #include <string> #include <thread> @@ -23,12 +24,12 @@ namespace net { */ class Universe { public: + Universe(); /** - * Constructor with a URI base. The base uri is used as a base to validate - * resource identifiers. (it may be removed). This creates a new thread - * to monitor network sockets. + * Constructor with json config object. The config allows listening and + * peer connection to be set up automatically. */ - explicit Universe(const std::string &base); + explicit Universe(nlohmann::json &config); /** * The destructor will terminate the network thread before completing. @@ -93,7 +94,7 @@ class Universe { private: bool active_; - std::string base_; + nlohmann::json config_; std::thread thread_; fd_set sfderror_; fd_set sfdread_; diff --git a/net/cpp/src/main.cpp b/net/cpp/src/main.cpp index 76e72fd3a7fa08154122322853632d017f231ba7..7999e37b771c21fb380441fab72c55ccdcf10e9b 100644 --- a/net/cpp/src/main.cpp +++ b/net/cpp/src/main.cpp @@ -1,5 +1,8 @@ #include <string> #include <iostream> +#include <map> +//#include <vector> +#include <fstream> #include <ftl/net.hpp> #ifndef WIN32 @@ -13,27 +16,82 @@ using std::string; using ftl::net::Universe; +using json = nlohmann::json; +using std::ifstream; +using std::map; static Universe *universe; static volatile bool stop = false; -void handle_options(const char ***argv, int *argc) { +// Store loaded configuration +static json config; + +/** + * Find and load a JSON configuration file + */ +static bool findConfiguration(const string &file) { + ifstream i; + + if (file != "") i.open(file); + if (!i.is_open()) i.open("./config.json"); + if (!i.is_open()) i.open(FTL_LOCAL_CONFIG_ROOT "/config.json"); + if (!i.is_open()) i.open(FTL_GLOBAL_CONFIG_ROOT "/config.json"); + if (!i.is_open()) return false; + i >> config; + return true; +} + +/** + * Generate a map from command line option to value + */ +map<string, string> read_options(char ***argv, int *argc) { + map<string, string> opts; + while (*argc > 0) { string cmd((*argv)[0]); if (cmd[0] != '-') break; - - if (cmd.find("--peer=") == 0) { - cmd = cmd.substr(cmd.find("=")+1); - //std::cout << "Peer added " << cmd.substr(cmd.find("=")+1) << std::endl; - universe->connect(cmd); - } else if (cmd.find("--listen=") == 0) { - cmd = cmd.substr(cmd.find("=")+1); - universe->listen(cmd); + + size_t p; + if ((p = cmd.find("=")) == string::npos) { + opts[cmd.substr(2)] = "true"; + } else { + opts[cmd.substr(2, p-2)] = cmd.substr(p+1); } - + (*argc)--; (*argv)++; } + + return opts; +} + +/** + * Put command line options into json config. If config element does not exist + * or is of a different type then report an error. + */ +static void process_options(const map<string, string> &opts) { + for (auto opt : opts) { + if (opt.first == "config") continue; + + if (opt.first == "version") { + std::cout << "FTL Vision Node - v" << FTL_VERSION << std::endl; + std::cout << FTL_VERSION_LONG << std::endl; + exit(0); + } + + try { + auto ptr = json::json_pointer("/"+opt.first); + // TODO(nick) Allow strings without quotes + auto v = json::parse(opt.second); + if (v.type() != config.at(ptr).type()) { + LOG(ERROR) << "Incorrect type for argument " << opt.first; + continue; + } + config.at(ptr) = v; + } catch(...) { + LOG(ERROR) << "Unrecognised option: " << opt.first; + } + } } void handle_command(const char *l) { @@ -53,14 +111,18 @@ void handle_command(const char *l) { } } -int main(int argc, const char **argv) { +int main(int argc, char **argv) { argc--; argv++; - - universe = new Universe("ftl://cli"); - + // Process Arguments - handle_options(&argv, &argc); + auto options = read_options(&argv, &argc); + if (!findConfiguration(options["config"])) { + LOG(FATAL) << "Could not find any configuration!"; + } + process_options(options); + + universe = new Universe(config); while (!stop) { #ifndef WIN32 diff --git a/net/cpp/src/universe.cpp b/net/cpp/src/universe.cpp index ffe195fc8ed9e7b0edd77b6972fc6f1ba1b9f311..006131c4eb1d7120447d9b358051bbb0516424c2 100644 --- a/net/cpp/src/universe.cpp +++ b/net/cpp/src/universe.cpp @@ -11,9 +11,25 @@ using std::thread; using ftl::net::Peer; using ftl::net::Listener; using ftl::net::Universe; +using nlohmann::json; -Universe::Universe(const string &base) : - active_(true), base_(base), thread_(Universe::__start, this) { +Universe::Universe() : active_(true), thread_(Universe::__start, this) {} + +Universe::Universe(nlohmann::json &config) : + active_(true), config_(config), thread_(Universe::__start, this) { + if (config["listen"].is_array()) { + for (auto &l : config["listen"]) { + listen(l); + } + } else if (config["listen"].is_string()) { + listen(config["listen"]); + } + + if (config["peers"].is_array()) { + for (auto &p : config["peers"]) { + connect(p); + } + } } Universe::~Universe() { diff --git a/net/cpp/test/net_integration.cpp b/net/cpp/test/net_integration.cpp index cc2d581d01baba343f170df30562ad8f4027c66a..0d33af7c22140c66d480bec0e9af442ca6114e5e 100644 --- a/net/cpp/test/net_integration.cpp +++ b/net/cpp/test/net_integration.cpp @@ -13,8 +13,8 @@ using std::chrono::milliseconds; // --- Tests ------------------------------------------------------------------- TEST_CASE("Universe::connect()", "[net]") { - Universe a("ftl://utu.fi"); - Universe b("ftl://utu.fi"); + Universe a; + Universe b; a.listen("tcp://localhost:7077"); @@ -73,8 +73,8 @@ TEST_CASE("Universe::connect()", "[net]") { } TEST_CASE("Universe::broadcast()", "[net]") { - Universe a("ftl://utu.fi"); - Universe b("ftl://utu.fi"); + Universe a; + Universe b; a.listen("tcp://localhost:7077"); @@ -122,7 +122,7 @@ TEST_CASE("Universe::broadcast()", "[net]") { } SECTION("one argument to two peers") { - Universe c("ftl://utu.fi"); + Universe c; b.connect("tcp://localhost:7077"); c.connect("tcp://localhost:7077");