From a5903dbf2e009bf1deea48d57d85b920e8eba8aa Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Sat, 25 Jul 2020 20:04:18 +0300
Subject: [PATCH] Add groups to UI

---
 applications/gui2/src/modules/addsource.cpp   | 14 +++--
 applications/gui2/src/views/addsource.cpp     |  2 +
 .../streams/include/ftl/streams/feed.hpp      |  3 +-
 components/streams/src/feed.cpp               | 57 ++++++++++++++++++-
 4 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/applications/gui2/src/modules/addsource.cpp b/applications/gui2/src/modules/addsource.cpp
index d90039c3e..166d76a91 100644
--- a/applications/gui2/src/modules/addsource.cpp
+++ b/applications/gui2/src/modules/addsource.cpp
@@ -22,10 +22,14 @@ void AddCtrl::show() {
 }
 
 ftl::Configurable *AddCtrl::add(const std::string &uri) {
-	if (io->feed()->sourceActive(uri)) {
-		io->feed()->remove(uri);
-	} else {
-		io->feed()->add(uri);
+	try {
+		if (io->feed()->sourceActive(uri)) {
+			io->feed()->remove(uri);
+		} else {
+			io->feed()->add(uri);
+		}
+	} catch (const ftl::exception &e) {
+		screen->showError("Exception", e.what());
 	}
 	return nullptr;
 }
@@ -35,7 +39,7 @@ std::vector<std::string> AddCtrl::getHosts() {
 }
 
 std::vector<std::string> AddCtrl::getGroups() {
-	return {};
+	return std::move(io->feed()->availableGroups());
 }
 
 std::set<ftl::stream::SourceInfo> AddCtrl::getRecent() {
diff --git a/applications/gui2/src/views/addsource.cpp b/applications/gui2/src/views/addsource.cpp
index 9ca1b0d1b..f92203601 100644
--- a/applications/gui2/src/views/addsource.cpp
+++ b/applications/gui2/src/views/addsource.cpp
@@ -59,6 +59,7 @@ nanogui::Button *AddSourceWindow::_addButton(const std::string &s, nanogui::Widg
 	case ftl::URI::SCHEME_FTL			: icon = ENTYPO_ICON_CLOUD; break;
 	case ftl::URI::SCHEME_WS			:
 	case ftl::URI::SCHEME_TCP			: icon = ENTYPO_ICON_CLASSIC_COMPUTER; break;
+	case ftl::URI::SCHEME_GROUP			: icon = ENTYPO_ICON_MERGE; break;
 	default: break;
 	}
 
@@ -101,6 +102,7 @@ void AddSourceWindow::rebuild() {
 	auto srcs = ctrl_->getRecent();
 
 	for (auto &s : srcs) {
+		LOG(INFO) << "ADD RECENT: " << s.uri;
 		_addButton(s.uri, recentscroll);
 	}
 
diff --git a/components/streams/include/ftl/streams/feed.hpp b/components/streams/include/ftl/streams/feed.hpp
index 17e6c3192..c8565fcf2 100644
--- a/components/streams/include/ftl/streams/feed.hpp
+++ b/components/streams/include/ftl/streams/feed.hpp
@@ -25,7 +25,7 @@ struct SourceInfo {
 	std::string uri;
 	int64_t last_used;
 
-	inline bool operator<(const SourceInfo &o) const { return last_used > o.last_used; }
+	inline bool operator<(const SourceInfo &o) const { return last_used >= o.last_used; }
 };
 
 class Feed : public ftl::Configurable {
@@ -107,6 +107,7 @@ public:
 	std::vector<std::string> availableNetworkSources();
 	std::vector<std::string> availableFileSources();
 	std::vector<std::string> availableDeviceSources();
+	std::vector<std::string> availableGroups();
 	bool sourceAvailable(const std::string &uri);
 	bool sourceActive(const std::string &uri);
 
diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp
index 9a5974093..aa43a3935 100644
--- a/components/streams/src/feed.cpp
+++ b/components/streams/src/feed.cpp
@@ -95,6 +95,7 @@ Feed::Feed(nlohmann::json &config, ftl::net::Universe*net) :
 		"recent_files",
 		"recent_sources",
 		"known_hosts",
+		"known_groups",
 		"auto_host_connect",
 		"auto_host_sources",
 		"uri",
@@ -540,6 +541,17 @@ std::vector<std::string> Feed::availableNetworkSources() {
 	return netcams_;
 }
 
+std::vector<std::string> Feed::availableGroups() {
+	std::vector<std::string> groups;
+	auto &known = getConfig()["known_groups"];
+
+	for (auto &f : known.items()) {
+		groups.push_back(f.key());
+	}
+
+	return groups;
+}
+
 std::vector<std::string> Feed::availableFileSources() {
 	std::vector<std::string> files;
 	auto &recent_files = getConfig()["recent_files"];
@@ -611,6 +623,17 @@ bool Feed::sourceActive(const std::string &suri) {
 
 	if (uri.getScheme() == ftl::URI::SCHEME_TCP || uri.getScheme() == ftl::URI::SCHEME_WS) {
 		return net_->isConnected(uri);
+	} else if (uri.getScheme() == ftl::URI::SCHEME_GROUP) {
+		// Check that every constituent source is active
+		auto &known = getConfig()["known_groups"];
+		if (known.contains(uri.getBaseURI())) {
+			auto &sources = known[uri.getBaseURI()]["sources"];
+
+			for (auto i=sources.begin(); i!=sources.end(); ++i) {
+				if (!sourceActive(i.key())) return false;
+			}
+		}
+		return true;
 	} else {
 		SHARED_LOCK(mtx_, lk);
 		return fsid_lookup_.count(uri.getBaseURI()) > 0;
@@ -655,6 +678,13 @@ std::string Feed::getName(const std::string &puri) {
 		return getConfig()["recent_files"][uri.getBaseURI()].value("name", "FTLFile");
 	} else if (uri.getScheme() == ftl::URI::SCHEME_TCP || uri.getScheme() == ftl::URI::SCHEME_WS) {
 		return uri.getBaseURI();
+	} else if (uri.getScheme() == ftl::URI::SCHEME_GROUP) {
+		auto &groups = getConfig()["known_groups"];
+		if (groups.contains(uri.getBaseURI())) {
+			return uri.getPathSegment(0) + std::string(" (") + std::to_string(groups[uri.getBaseURI()]["sources"].size()) + std::string(")");
+		} else {
+			return uri.getPathSegment(0);
+		}
 	}
 
 	return uri.getPathSegment(-1);
@@ -674,6 +704,14 @@ nlohmann::json &Feed::_add_recent_source(const ftl::URI &uri) {
 	details["uri"] = uri.to_string();
 	details["name"] = name;
 	details["last_open"] = ftl::timer::get_time();
+
+	if (uri.hasAttribute("group")) {
+		std::string grpname = uri.getAttribute<std::string>("group");
+		auto &groups = getConfig()["known_groups"];
+		auto &grpdetail = groups[std::string("group:")+grpname];
+		grpdetail["sources"][uri.getBaseURI()] = true;
+	}
+
 	return details;
 }
 
@@ -816,7 +854,11 @@ uint32_t Feed::add(const std::string &path) {
 		auto &known = getConfig()["recent_sources"];
 		auto &details = known[uri.getBaseURI()];
 		if (details.contains("host")) {
-			net_->connect(details["host"].get<std::string>())->waitConnection();
+			auto *p = net_->connect(details["host"].get<std::string>());
+			p->noReconnect();
+			if (!p->waitConnection()) {
+				throw FTL_Error("Could not connect to host " << details["host"].get<std::string>() << " for stream " << path);
+			}
 		} else {
 			// See if it can otherwise be found?
 		}
@@ -836,6 +878,19 @@ uint32_t Feed::add(const std::string &path) {
 
 		add_src_cb_.trigger(fsid);
 		return fsid;
+	} else if (scheme == ftl::URI::SCHEME_GROUP) {
+		auto &known = getConfig()["known_groups"];
+		if (known.contains(uri.getBaseURI())) {
+			auto &sources = known[uri.getBaseURI()]["sources"];
+
+			lk.unlock();
+			for (auto i=sources.begin(); i!=sources.end(); ++i) {
+				add(i.key());
+			}
+
+			lk.lock();
+			_add_recent_source(uri);
+		}
 	}
 	else{
 		throw ftl::exception("bad uri");
-- 
GitLab