summaryrefslogtreecommitdiff
path: root/libs/surfaces/websockets/message.cc
diff options
context:
space:
mode:
authorLuciano Iam <lucianito@gmail.com>2020-02-20 13:12:36 +0100
committerRobin Gareus <robin@gareus.org>2020-02-22 23:10:24 +0100
commit8db9755d1e075f22275286e94b37af311c6d489f (patch)
treed72749d8cdc77914303c34c6aa6f5a28e620ddb8 /libs/surfaces/websockets/message.cc
parent44165309299960e35d4efa2194b2c2db63c2c1b2 (diff)
Add websockets surface module
Diffstat (limited to 'libs/surfaces/websockets/message.cc')
-rw-r--r--libs/surfaces/websockets/message.cc193
1 files changed, 193 insertions, 0 deletions
diff --git a/libs/surfaces/websockets/message.cc b/libs/surfaces/websockets/message.cc
new file mode 100644
index 0000000000..941e01f539
--- /dev/null
+++ b/libs/surfaces/websockets/message.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 Luciano Iam <lucianito@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#include <sstream>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+#include "message.h"
+
+// JSON does not support Infinity or NaN
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#define JSON_INF 1.0e+128
+#define JSON_INF_STR XSTR(JSON_INF)
+
+namespace pt = boost::property_tree;
+
+NodeStateMessage::NodeStateMessage (const NodeState& state)
+ : _valid (true)
+ , _state (state)
+{
+ _write = state.n_val () > 0;
+}
+
+NodeStateMessage::NodeStateMessage (void *buf, size_t len)
+ : _valid (false)
+ , _write (false)
+{
+ try {
+ std::string s { static_cast<char *>(buf), len };
+
+ std::istringstream is { s };
+ pt::ptree root;
+ pt::read_json (is, root);
+
+ _state = NodeState { root.get<std::string> ("node") };
+
+ pt::ptree addr = root.get_child ("addr", pt::ptree ());
+
+ for (pt::ptree::iterator it = addr.begin (); it != addr.end (); ++it) {
+ // throws if datatype not uint32_t
+ _state.add_addr (boost::lexical_cast<uint32_t>(it->second.data ()));
+ }
+
+ pt::ptree val = root.get_child ("val", pt::ptree ());
+
+ for (pt::ptree::iterator it = val.begin (); it != val.end (); ++it) {
+
+ std::string val = it->second.data ();
+
+ try {
+ _state.add_val (boost::lexical_cast<int>(val));
+ } catch (const boost::bad_lexical_cast&) {
+ try {
+ double d = boost::lexical_cast<double>(val);
+ if (d >= JSON_INF) {
+ d = std::numeric_limits<double>::infinity ();
+ } else if (d <= -JSON_INF) {
+ d = -std::numeric_limits<double>::infinity ();
+ }
+ _state.add_val (d);
+ } catch (const boost::bad_lexical_cast&) {
+ if (val == "false") {
+ _state.add_val (false);
+ } else if (val == "true") {
+ _state.add_val (true);
+ } else {
+ _state.add_val (val);
+ }
+ }
+ }
+ }
+
+ if (_state.n_val () > 0) {
+ _write = true;
+ }
+
+ _valid = true;
+
+ } catch (const std::exception& exc) {
+#ifdef DEBUG
+ std::cerr << "cannot parse message - " << exc.what () << std::endl;
+#endif
+ }
+}
+
+size_t
+NodeStateMessage::serialize (void *buf, size_t len) const
+{
+ // boost json writes all values as strings, we do not want that
+
+ if (len == 0) {
+ return -1;
+ }
+
+ std::stringstream ss;
+
+ ss << "{\"node\":\"" << _state.node () << "\"";
+
+ int n_addr = _state.n_addr ();
+
+ if (n_addr > 0) {
+ ss << ",\"addr\":[";
+
+ for (int i = 0; i < n_addr; i++) {
+ if (i > 0) {
+ ss << ',';
+ }
+
+ ss << _state.nth_addr (i);
+ }
+
+ ss << "]";
+ }
+
+ int n_val = _state.n_val ();
+
+ if (n_val > 0) {
+ ss << ",\"val\":[";
+
+ for (int i = 0; i < n_val; i++) {
+ if (i > 0) {
+ ss << ',';
+ }
+
+ TypedValue val = _state.nth_val (i);
+
+ switch (val.type ()) {
+ case TypedValue::Empty:
+ ss << "null";
+ break;
+ case TypedValue::Bool:
+ ss << (static_cast<bool>(val) ? "true" : "false");
+ break;
+ case TypedValue::Int:
+ ss << static_cast<int>(val);
+ break;
+ case TypedValue::Double: {
+ double d = static_cast<double>(val);
+ if (d == std::numeric_limits<double>::infinity ()) {
+ ss << JSON_INF_STR;
+ } else if (d == -std::numeric_limits<double>::infinity ()) {
+ ss << "-" JSON_INF_STR;
+ } else {
+ ss << d;
+ }
+ break;
+ }
+ case TypedValue::String:
+ ss << '"' << static_cast<std::string>(val) << '"';
+ break;
+ default:
+ break;
+ }
+ }
+
+ ss << "]";
+ }
+
+ ss << '}';
+
+ std::string s = ss.str ();
+ const char *cs = s.c_str ();
+ size_t cs_sz = strlen (cs);
+
+ if (len < cs_sz) {
+ return -1;
+ }
+
+ memcpy (buf, cs, cs_sz);
+
+ return cs_sz;
+}