diff --git a/applications/gui/src/ctrl_window.cpp b/applications/gui/src/ctrl_window.cpp index 7b4308e584c88227f98f17064e5094c50a65a36a..38a496376cd95b5ec96b72a9cd3c8bb0694ed124 100644 --- a/applications/gui/src/ctrl_window.cpp +++ b/applications/gui/src/ctrl_window.cpp @@ -3,6 +3,8 @@ #include <nanogui/layout.h> #include <nanogui/label.h> #include <nanogui/combobox.h> +#include <nanogui/button.h> +#include <nanogui/entypo.h> #include <vector> #include <string> @@ -13,30 +15,64 @@ using std::vector; ControlWindow::ControlWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl) - : nanogui::Window(parent, "Control"), ctrl_(ctrl) { + : nanogui::Window(parent, "Node Control"), ctrl_(ctrl) { setLayout(new nanogui::GroupLayout()); using namespace nanogui; - new Label(this, "Select Node","sans-bold"); - vector<string> details = ctrl->getSlaves(); - LOG(INFO) << "Details count = " << details.size(); - - vector<string> available; - for (auto &d : details) { - auto detail = ftl::config::json_t::parse(d); - LOG(INFO) << "DETAIL RECEIVED " << detail; - available.push_back(detail["title"].get<string>()); - } + _updateDetails(); + + auto button = new Button(this, "Add Node", ENTYPO_ICON_PLUS); + button->setCallback([this] { + // Show new connection dialog + }); + button = new Button(this, "Restart All", ENTYPO_ICON_CYCLE); + button->setCallback([this] { + ctrl_->restart(); + }); + button = new Button(this, "Shutdown All", ENTYPO_ICON_POWER_PLUG); + button->setCallback([this] { + ctrl_->shutdown(); + }); - auto select = new ComboBox(this, available); - select->setCallback([this,available](int ix) { + new Label(this, "Select Node","sans-bold"); + auto select = new ComboBox(this, node_titles_); + select->setCallback([this](int ix) { LOG(INFO) << "Change node: " << ix; - + _changeActive(ix); + }); + + button = new Button(this, "Restart Node", ENTYPO_ICON_CYCLE); + button->setCallback([this] { + ctrl_->restart(_getActiveID()); + }); + + button = new Button(this, "Shutdown Node", ENTYPO_ICON_POWER_PLUG); + button->setCallback([this] { + ctrl_->shutdown(_getActiveID()); }); + + _changeActive(0); } ControlWindow::~ControlWindow() { } +void ControlWindow::_updateDetails() { + node_details_ = ctrl_->getSlaves(); + + node_titles_.clear(); + for (auto &d : node_details_) { + node_titles_.push_back(d["title"].get<string>()); + } +} + +void ControlWindow::_changeActive(int ix) { + active_ix_ = ix; +} + +ftl::UUID ControlWindow::_getActiveID() { + return ftl::UUID(node_details_[active_ix_]["id"].get<string>()); +} + diff --git a/applications/gui/src/ctrl_window.hpp b/applications/gui/src/ctrl_window.hpp index 973ffe1aadbf4e7281f006eb5c9bc445f7efe3fd..58df7b9be88e7ddba9b344464336369c53d36d96 100644 --- a/applications/gui/src/ctrl_window.hpp +++ b/applications/gui/src/ctrl_window.hpp @@ -3,6 +3,7 @@ #include <nanogui/window.h> #include <ftl/master.hpp> +#include <ftl/uuid.hpp> namespace ftl { namespace gui { @@ -17,6 +18,13 @@ class ControlWindow : public nanogui::Window { private: ftl::ctrl::Master *ctrl_; + std::vector<ftl::config::json_t> node_details_; + std::vector<std::string> node_titles_; + int active_ix_; + + void _updateDetails(); + void _changeActive(int); + ftl::UUID _getActiveID(); }; } diff --git a/applications/gui/src/main.cpp b/applications/gui/src/main.cpp index 5ada2cba5d4eece9bb89c2eb022bdead3a545a55..a12ff59055e2aca407f3b0032850bce52163cc07 100644 --- a/applications/gui/src/main.cpp +++ b/applications/gui/src/main.cpp @@ -194,6 +194,8 @@ class FTLApplication : public nanogui::Screen { } virtual void draw(NVGcontext *ctx) { + nvgText(ctx, 10, 10, "FT-Lab Remote Presence System", NULL); + /* Draw the user interface */ Screen::draw(ctx); } diff --git a/components/control/cpp/include/ftl/master.hpp b/components/control/cpp/include/ftl/master.hpp index 17ca49c2c2fc9f08ebf5f7183f7c7cbbe10baf32..2a961af8de19a97ace119a70dd2870e993733dc9 100644 --- a/components/control/cpp/include/ftl/master.hpp +++ b/components/control/cpp/include/ftl/master.hpp @@ -37,7 +37,7 @@ class Master { std::vector<std::string> getConfigurables(const ftl::UUID &peer); - std::vector<std::string> getSlaves(); + std::vector<ftl::config::json_t> getSlaves(); std::vector<ftl::config::json_t> get(const std::string &uri); diff --git a/components/control/cpp/include/ftl/slave.hpp b/components/control/cpp/include/ftl/slave.hpp index e61290d630c1f10bd38335b228d9657b17ab6de7..dc6010635ed922d7cae13d03898f391a31275851 100644 --- a/components/control/cpp/include/ftl/slave.hpp +++ b/components/control/cpp/include/ftl/slave.hpp @@ -3,6 +3,8 @@ #include <ftl/net/universe.hpp> #include <ftl/configurable.hpp> +#include <loguru.hpp> +#include <mutex> namespace ftl { namespace ctrl { @@ -11,6 +13,13 @@ class Slave { public: Slave(ftl::net::Universe *, ftl::Configurable *); ~Slave(); + + void sendLog(const loguru::Message& message); + + private: + std::vector<ftl::UUID> log_peers_; + ftl::net::Universe *net_; + std::mutex mutex_; }; } diff --git a/components/control/cpp/src/master.cpp b/components/control/cpp/src/master.cpp index 5072c41553524bfae22f86702383f3f364a3a433..7ccaa877a62764f4e7dc2e4e57fa05ad9cfb6595 100644 --- a/components/control/cpp/src/master.cpp +++ b/components/control/cpp/src/master.cpp @@ -11,12 +11,14 @@ using ftl::ctrl::LogEvent; Master::Master(Configurable *root, Universe *net) : root_(root), net_(net) { - net_->subscribe("log", [this](const std::string &pre, const std::string &msg) { + net->bind("log", [this](int v, const std::string &pre, const std::string &msg) { LOG(INFO) << "RECEIVE LOG"; for (auto f : log_handlers_) { f({pre,msg}); } }); + + net->broadcast("log_subscribe", net->id()); } Master::~Master() { @@ -47,8 +49,13 @@ void Master::set(const ftl::UUID &peer, const string &uri, json_t &value) { net_->send(peer, "update_cfg", uri, (string)value); } -vector<string> Master::getSlaves() { - return net_->findAll<string>("slave_details"); +vector<json_t> Master::getSlaves() { + auto response = net_->findAll<string>("slave_details"); + vector<json_t> result; + for (auto &r : response) { + result.push_back(json_t::parse(r)); + } + return result; } vector<string> Master::getConfigurables() { diff --git a/components/control/cpp/src/slave.cpp b/components/control/cpp/src/slave.cpp index fd348c18124e04117c70d85479180286f152d69b..8d5cefb9f33bdf910948d9a058730a2848f40b0f 100644 --- a/components/control/cpp/src/slave.cpp +++ b/components/control/cpp/src/slave.cpp @@ -1,18 +1,18 @@ #include <ftl/slave.hpp> -#include <loguru.hpp> using ftl::Configurable; using ftl::net::Universe; using ftl::ctrl::Slave; using std::string; +using std::mutex; +using std::unique_lock; static void netLog(void* user_data, const loguru::Message& message) { - Universe *net = (Universe*)user_data; - net->publish("log", message.preamble, message.message); + Slave *slave = static_cast<Slave*>(user_data); + slave->sendLog(message); } -Slave::Slave(Universe *net, ftl::Configurable *root) { - net->createResource("log"); +Slave::Slave(Universe *net, ftl::Configurable *root) : net_(net) { net->bind("restart", []() { LOG(WARNING) << "Remote restart..."; exit(1); @@ -39,9 +39,23 @@ Slave::Slave(Universe *net, ftl::Configurable *root) { return {json.dump()}; }); - loguru::add_callback("net_log", netLog, net, loguru::Verbosity_INFO); + net->bind("log_subscribe", [this](const ftl::UUID &peer) { + unique_lock<mutex> lk(mutex_); + log_peers_.push_back(peer); + }); + + loguru::add_callback("net_log", netLog, this, loguru::Verbosity_INFO); } Slave::~Slave() { } + +void Slave::sendLog(const loguru::Message& message) { + unique_lock<mutex> lk(mutex_); + for (auto &p : log_peers_) { + if (!net_->send(p, "log", message.verbosity, message.preamble, message.message)) { + // TODO(Nick) Remove peer from loggers list... + } + } +} diff --git a/components/net/cpp/include/ftl/net/universe.hpp b/components/net/cpp/include/ftl/net/universe.hpp index 5ce99f3a5f781991f44ed1d33c24e0f717371e53..407458c11cf1ecfa116a77b0568ee12cbe41276c 100644 --- a/components/net/cpp/include/ftl/net/universe.hpp +++ b/components/net/cpp/include/ftl/net/universe.hpp @@ -104,7 +104,7 @@ class Universe : public ftl::Configurable { R call(const UUID &pid, const std::string &name, ARGS... args); template <typename... ARGS> - void send(const UUID &pid, const std::string &name, ARGS... args); + bool send(const UUID &pid, const std::string &name, ARGS... args); template <typename R, typename... ARGS> std::optional<R> findOne(const std::string &name, ARGS... args); @@ -285,13 +285,13 @@ R Universe::call(const ftl::UUID &pid, const std::string &name, ARGS... args) { } template <typename... ARGS> -void Universe::send(const ftl::UUID &pid, const std::string &name, ARGS... args) { +bool Universe::send(const ftl::UUID &pid, const std::string &name, ARGS... args) { Peer *p = getPeer(pid); if (p == nullptr) { DLOG(WARNING) << "Attempting to call an unknown peer : " << pid.to_string(); throw -1; } - p->send(name, args...); + return p->send(name, args...) > 0; } template <typename... ARGS> diff --git a/components/net/cpp/include/ftl/uuid.hpp b/components/net/cpp/include/ftl/uuid.hpp index 5d494b8ddc26b262113b42db0bf1e461d61fc8c9..0b3cb6a1f68bdbd40e494db69bff000dd82b4998 100644 --- a/components/net/cpp/include/ftl/uuid.hpp +++ b/components/net/cpp/include/ftl/uuid.hpp @@ -25,8 +25,17 @@ namespace ftl { uuid_generate(uuid_); #endif } - explicit UUID(int u) { memset(&uuid_,u,16); } - UUID(const ftl::UUID &u) { memcpy(&uuid_,&u.uuid_,16); } + explicit UUID(int u) { memset(uuid_,u,16); } + UUID(const ftl::UUID &u) { memcpy(uuid_,u.uuid_,16); } + explicit UUID(const std::string &s) { +#ifdef WIN32 + // TODO(Nick) Windows UUID parse +#else + if (uuid_parse(s.c_str(), uuid_) < 0) { + memset(uuid_,0,16); + } +#endif + } UUID &operator=(const UUID &u) { memcpy(&uuid_,&u.uuid_,16); return *this;