From 0f32809b745ce6d2f41878c5eaa2b710cdad5df4 Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 26 Sep 2021 23:01:15 +0200 Subject: [PATCH] fixed: get full json objects from the tcp stream, and parse them --- src/kodiclient.cpp | 75 ++++++++++++++++++++++++++++++++++++++++------ src/kodiclient.h | 2 ++ 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/kodiclient.cpp b/src/kodiclient.cpp index 936e0f2..db0f8d7 100644 --- a/src/kodiclient.cpp +++ b/src/kodiclient.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -61,22 +62,63 @@ void CKodiClient::Process() printf("Connected to Kodi\n"); //Keep reading data from Kodi, when the tcp socket is closed an exception is thrown. + uint32_t bracketlevel = 0; + bool instring = false; + bool escaped = false; + std::string jsonstr; for(;;) { boost::asio::streambuf receive_buffer; - size_t readbytes = boost::asio::read(socket, receive_buffer, boost::asio::transfer_at_least(1)); + size_t bytesread = boost::asio::read(socket, receive_buffer, boost::asio::transfer_at_least(1)); + const char* data = boost::asio::buffer_cast(receive_buffer.data()); - //TODO: because of TCP, one read does not exactly equal one JSON object. - json jsondata = json::parse(data); - - //If Kodi signals a Player.OnPlay notification, the amplifier should be turned on. - if (jsondata.contains("method")) + //Parse the JSON data into separate JSON objects by finding the text from + //the starting { to ending }, while ignoring curly brackets in strings. + for (uint32_t i = 0; i < (uint32_t)bytesread; i++) { - if (jsondata["method"] == "Player.OnPlay") + jsonstr.push_back(data[i]); + + if (!instring) { - printf("Player started\n"); - m_ampswitch->SignalPlayStart(); + if (data[i] == '"') + { + instring = true; + } + else if (data[i] == '{') + { + bracketlevel++; + } + else if (data[i] == '}') + { + if (bracketlevel > 0) + { + bracketlevel--; + if (bracketlevel == 0) + { + Parse(jsonstr); + jsonstr.clear(); + } + } + else + { + jsonstr.clear(); //Shouldn't happen. + } + } + } + else + { + if (!escaped) + { + if (data[i] == '\\') + escaped = true; + else if (data[i] == '"') + instring = false; + } + else + { + escaped = false; + } } } } @@ -89,3 +131,18 @@ void CKodiClient::Process() } } } + +void CKodiClient::Parse(const std::string& jsonstr) +{ + json jsondata = json::parse(jsonstr); + + //If Kodi signals a Player.OnPlay notification, the amplifier should be turned on. + if (jsondata.contains("method")) + { + if (jsondata["method"] == "Player.OnPlay") + { + printf("Player started\n"); + m_ampswitch->SignalPlayStart(); + } + } +} diff --git a/src/kodiclient.h b/src/kodiclient.h index c2a830c..f8a8690 100644 --- a/src/kodiclient.h +++ b/src/kodiclient.h @@ -20,6 +20,7 @@ #define KODICLIENT_H #include +#include class CAmpSwitch; @@ -31,6 +32,7 @@ class CKodiClient private: static void SProcess(CKodiClient* kodiclient); void Process(); + void Parse(const std::string& jsonstr); std::thread m_thread; CAmpSwitch* m_ampswitch;