fixed: get full json objects from the tcp stream, and parse them

This commit is contained in:
Bob 2021-09-26 23:01:15 +02:00
parent fd151cf7df
commit 0f32809b74
2 changed files with 68 additions and 9 deletions

View file

@ -21,6 +21,7 @@
#include <cstdio>
#include <unistd.h>
#include <cstdint>
#include <iostream>
#include <boost/asio.hpp>
@ -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<const char*>(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();
}
}
}

View file

@ -20,6 +20,7 @@
#define KODICLIENT_H
#include <thread>
#include <string>
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;