diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2023-03-31 14:31:32 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2023-03-31 14:31:32 +0200 |
commit | ae70341365e27d766c8530924209fc4826036aea (patch) | |
tree | b18247e0b96b45b6f74b66d0ab5b5d69bb63f143 /lib | |
parent | fe19871f8ee362f65d194b864eb989618b994e58 (diff) | |
download | dabmod-ae70341365e27d766c8530924209fc4826036aea.tar.gz dabmod-ae70341365e27d766c8530924209fc4826036aea.tar.bz2 dabmod-ae70341365e27d766c8530924209fc4826036aea.zip |
Add JSON output to RC
Diffstat (limited to 'lib')
-rw-r--r-- | lib/RemoteControl.cpp | 94 | ||||
-rw-r--r-- | lib/RemoteControl.h | 14 |
2 files changed, 99 insertions, 9 deletions
diff --git a/lib/RemoteControl.cpp b/lib/RemoteControl.cpp index 30dcb60..6e9af20 100644 --- a/lib/RemoteControl.cpp +++ b/lib/RemoteControl.cpp @@ -25,6 +25,8 @@ #include <list> #include <string> #include <iostream> +#include <sstream> +#include <iomanip> #include <string> #include <algorithm> @@ -102,6 +104,74 @@ std::list< std::vector<std::string> > RemoteControllers::get_param_list_values(c return allparams; } + +static std::string escape_json(const std::string &s) { + std::ostringstream o; + for (auto c = s.cbegin(); c != s.cend(); c++) { + switch (*c) { + case '"': o << "\\\""; break; + case '\\': o << "\\\\"; break; + case '\b': o << "\\b"; break; + case '\f': o << "\\f"; break; + case '\n': o << "\\n"; break; + case '\r': o << "\\r"; break; + case '\t': o << "\\t"; break; + default: + if ('\x00' <= *c && *c <= '\x1f') { + o << "\\u" + << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(*c); + } else { + o << *c; + } + } + } + return o.str(); +} + +std::string RemoteControllers::get_params_json(const std::string& name) { + RemoteControllable* controllable = get_controllable_(name); + const auto& values = controllable->get_all_values(); + + std::ostringstream ss; + ss << "{ "; + size_t ix = 0; + for (const auto& element : values) { + if (ix > 0) { + ss << ","; + } + + ss << "\"" << escape_json(element.first) << "\": "; + + const auto& value = element.second; + if (std::holds_alternative<string>(value)) { + ss << "\"" << escape_json(std::get<string>(value)) << "\""; + } + else if (std::holds_alternative<double>(value)) { + ss << std::defaultfloat << std::get<double>(value); + } + else if (std::holds_alternative<ssize_t>(value)) { + ss << std::get<ssize_t>(value); + } + else if (std::holds_alternative<size_t>(value)) { + ss << std::get<size_t>(value); + } + else if (std::holds_alternative<bool>(value)) { + ss << (std::get<bool>(value) ? "true" : "false"); + } + else if (std::holds_alternative<std::nullopt_t>(value)) { + ss << "null"; + } + else { + throw std::logic_error("variant alternative not handled"); + } + + ix++; + } + ss << " }"; + + return ss.str(); +} + std::string RemoteControllers::get_param(const std::string& name, const std::string& param) { RemoteControllable* controllable = get_controllable_(name); return controllable->get_parameter(param); @@ -427,10 +497,15 @@ void RemoteControllerZmq::recv_all(zmq::socket_t& pSocket, std::vector<std::stri bool more = true; do { zmq::message_t msg; - pSocket.recv(msg); - std::string incoming((char*)msg.data(), msg.size()); - message.push_back(incoming); - more = msg.more(); + const auto zresult = pSocket.recv(msg); + if (zresult) { + std::string incoming((char*)msg.data(), msg.size()); + message.push_back(incoming); + more = msg.more(); + } + else { + more = false; + } } while (more); } @@ -532,6 +607,15 @@ void RemoteControllerZmq::process() send_fail_reply(repSocket, err.what()); } } + else if (msg.size() == 2 && command == "showjson") { + std::string module((char*) msg[1].data(), msg[1].size()); + std::string json = rcs.get_params_json(module); + + zmq::message_t zmsg(json.size()); + memcpy(zmsg.data(), json.data(), json.size()); + + repSocket.send(zmsg, zmq::send_flags::none); + } else if (msg.size() == 3 && command == "get") { std::string module((char*) msg[1].data(), msg[1].size()); std::string parameter((char*) msg[2].data(), msg[2].size()); @@ -561,7 +645,7 @@ void RemoteControllerZmq::process() } else { send_fail_reply(repSocket, - "Unsupported command. commands: list, show, get, set"); + "Unsupported command. commands: list, show, get, set, showjson"); } } } diff --git a/lib/RemoteControl.h b/lib/RemoteControl.h index 2358b3a..4bc3b68 100644 --- a/lib/RemoteControl.h +++ b/lib/RemoteControl.h @@ -3,7 +3,7 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2019 + Copyright (C) 2023 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -36,6 +36,8 @@ #endif #include <list> +#include <unordered_map> +#include <variant> #include <map> #include <memory> #include <string> @@ -113,13 +115,16 @@ class RemoteControllable { } /* Base function to set parameters. */ - virtual void set_parameter( - const std::string& parameter, - const std::string& value) = 0; + virtual void set_parameter(const std::string& parameter, const std::string& value) = 0; /* Getting a parameter always returns a string. */ virtual const std::string get_parameter(const std::string& parameter) const = 0; + using value_t = std::variant<std::string, double, size_t, ssize_t, bool, std::nullopt_t>; + using map_t = std::unordered_map<std::string, value_t>; + + virtual const map_t get_all_values() const = 0; + protected: std::string m_rc_name; std::list< std::vector<std::string> > m_parameters; @@ -135,6 +140,7 @@ class RemoteControllers { void check_faults(); std::list< std::vector<std::string> > get_param_list_values(const std::string& name); std::string get_param(const std::string& name, const std::string& param); + std::string get_params_json(const std::string& name); void set_param( const std::string& name, |