From 34fc9ace914bc04ac97af59e064daa1a47969bf3 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Thu, 11 Apr 2019 08:38:10 +0300
Subject: [PATCH] Add json config to net

---
 .../cpp}/include/nlohmann/json.hpp            |  0
 net/cpp/include/ftl/net/universe.hpp          | 11 ++-
 net/cpp/src/main.cpp                          | 92 ++++++++++++++++---
 net/cpp/src/universe.cpp                      | 20 +++-
 net/cpp/test/net_integration.cpp              | 10 +-
 5 files changed, 106 insertions(+), 27 deletions(-)
 rename {cv-node => common/cpp}/include/nlohmann/json.hpp (100%)

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 d34b842fc..8f84287fe 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 76e72fd3a..7999e37b7 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 ffe195fc8..006131c4e 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 cc2d581d0..0d33af7c2 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");
-- 
GitLab