Refactor tcpserver into multiple files
This commit is contained in:
parent
e3b6d5c3a6
commit
59b55d1868
10 changed files with 486 additions and 446 deletions
|
|
@ -42,11 +42,16 @@ target_sources(SHinterface
|
||||||
src/sun.cpp
|
src/sun.cpp
|
||||||
src/programmode.h
|
src/programmode.h
|
||||||
src/programmode.cpp
|
src/programmode.cpp
|
||||||
src/tcpserver.h
|
|
||||||
src/tcpserver.cpp
|
|
||||||
src/pipewire.h
|
src/pipewire.h
|
||||||
src/pipewire.cpp
|
src/pipewire.cpp
|
||||||
|
|
||||||
|
src/service/service.h
|
||||||
|
src/service/service.cpp
|
||||||
|
src/service/tcpclient.h
|
||||||
|
src/service/tcpclient.cpp
|
||||||
|
src/service/tcpserver.h
|
||||||
|
src/service/tcpserver.cpp
|
||||||
|
|
||||||
src/actors/actor.h
|
src/actors/actor.h
|
||||||
src/actors/actor.cpp
|
src/actors/actor.cpp
|
||||||
src/actors/factoractor.h
|
src/actors/factoractor.h
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@
|
||||||
#include "sensors/mqttsensorsource.h"
|
#include "sensors/mqttsensorsource.h"
|
||||||
#include "items/fixeditemsource.h"
|
#include "items/fixeditemsource.h"
|
||||||
#include "items/itemloadersource.h"
|
#include "items/itemloadersource.h"
|
||||||
#include "tcpserver.h"
|
#include "service/tcpclient.h"
|
||||||
|
#include "service/tcpserver.h"
|
||||||
|
|
||||||
class MainObject : public QObject
|
class MainObject : public QObject
|
||||||
{
|
{
|
||||||
|
|
|
||||||
104
src/service/service.cpp
Normal file
104
src/service/service.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "items/item.h"
|
||||||
|
#include "items/itemstore.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
|
||||||
|
Service::Service(QObject* parent):
|
||||||
|
ItemSource(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QJsonObject Service::createMessage(const QString& type, const QJsonArray& data)
|
||||||
|
{
|
||||||
|
QJsonObject json;
|
||||||
|
json["MessageType"] = type;
|
||||||
|
json["Data"] = data;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::sensorEvent(Sensor sensor)
|
||||||
|
{
|
||||||
|
QJsonArray sensors;
|
||||||
|
QJsonObject sensorjson;
|
||||||
|
sensor.store(sensorjson);
|
||||||
|
sensors.append(sensorjson);
|
||||||
|
QJsonObject json = createMessage("SensorUpdate", sensors);
|
||||||
|
sendJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::itemUpdated(std::weak_ptr<Item> item)
|
||||||
|
{
|
||||||
|
qDebug()<<__func__;
|
||||||
|
QJsonArray items;
|
||||||
|
QJsonObject itemjson;
|
||||||
|
item.lock()->store(itemjson);
|
||||||
|
items.append(itemjson);
|
||||||
|
QJsonObject json = createMessage("ItemUpdate", items);
|
||||||
|
json["FullList"] = false;
|
||||||
|
sendJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::refresh()
|
||||||
|
{
|
||||||
|
sendJson(createMessage("GetSensors", QJsonArray()));
|
||||||
|
sendJson(createMessage("GetItems", QJsonArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::sendSensors()
|
||||||
|
{
|
||||||
|
QJsonArray sensors;
|
||||||
|
for(auto& sensor: *globalSensors.getSensors())
|
||||||
|
{
|
||||||
|
QJsonObject sensorjson;
|
||||||
|
sensor.store(sensorjson);
|
||||||
|
sensors.append(sensorjson);
|
||||||
|
}
|
||||||
|
sendJson(createMessage("SensorUpdate", sensors));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::sendItems()
|
||||||
|
{
|
||||||
|
QJsonArray items;
|
||||||
|
for(auto& item: *globalItems.getItems())
|
||||||
|
{
|
||||||
|
QJsonObject itemjson;
|
||||||
|
item->store(itemjson);
|
||||||
|
items.append(itemjson);
|
||||||
|
}
|
||||||
|
QJsonObject json = createMessage("ItemUpdate", items);
|
||||||
|
json["FullList"] = true;
|
||||||
|
sendJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Service::processIncomeingJson(const QByteArray& jsonbytes)
|
||||||
|
{
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
||||||
|
qDebug()<<"Got Json:"<<QString::fromLatin1(doc.toJson(QJsonDocument::JsonFormat::Indented));
|
||||||
|
QJsonObject json = doc.object();
|
||||||
|
QString type = json["MessageType"].toString();
|
||||||
|
if(type == "GetSensors")
|
||||||
|
{
|
||||||
|
qDebug()<<"Sending sensors";
|
||||||
|
sendSensors();
|
||||||
|
}
|
||||||
|
else if(type == "GetItems")
|
||||||
|
{
|
||||||
|
qDebug()<<"Sending Items";
|
||||||
|
sendItems();
|
||||||
|
}
|
||||||
|
else if(type == "SensorUpdate")
|
||||||
|
{
|
||||||
|
QJsonArray data = json["Data"].toArray();
|
||||||
|
for(QJsonValueRef sensorjson : data)
|
||||||
|
{
|
||||||
|
QJsonObject jsonobject = sensorjson.toObject();
|
||||||
|
Sensor sensor(jsonobject);
|
||||||
|
gotSensor(sensor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/service/service.h
Normal file
42
src/service/service.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef TCPSERVER_BASE_H
|
||||||
|
#define TCPSERVER_BASE_H
|
||||||
|
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "sensors/sensor.h"
|
||||||
|
#include "items/item.h"
|
||||||
|
#include "items/itemsource.h"
|
||||||
|
|
||||||
|
class Service : public ItemSource
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_IDLE,
|
||||||
|
STATE_RECV_JSON,
|
||||||
|
} client_state_t;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void gotSensor(Sensor sensor);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void sensorEvent(Sensor sensor);
|
||||||
|
void itemUpdated(std::weak_ptr<Item> item);
|
||||||
|
virtual void refresh() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Service(QObject* parent = nullptr);
|
||||||
|
void sendSensors();
|
||||||
|
void sendItems();
|
||||||
|
virtual void sendJson(const QJsonObject& json) = 0;
|
||||||
|
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static QJsonObject createMessage(const QString& type, const QJsonArray& data);
|
||||||
|
virtual void processIncomeingJson(const QByteArray& jsonbytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TCPSERVER_BASE_H
|
||||||
100
src/service/tcpclient.cpp
Normal file
100
src/service/tcpclient.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "items/item.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "tcpclient.h"
|
||||||
|
|
||||||
|
TcpClient::TcpClient(QObject* parent):
|
||||||
|
Service(parent),
|
||||||
|
socket(new QTcpSocket(this))
|
||||||
|
{
|
||||||
|
connect(socket, &QTcpSocket::readyRead, this, &TcpClient::socketReadyRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::sendJson(const QJsonObject& json)
|
||||||
|
{
|
||||||
|
QByteArray jsonData = QJsonDocument(json).toJson();
|
||||||
|
socket->write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpClient::launch(const QHostAddress &address, quint16 port)
|
||||||
|
{
|
||||||
|
socket->connectToHost(address, port);
|
||||||
|
return socket->waitForConnected(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::processIncomeingJson(const QByteArray& jsonbytes)
|
||||||
|
{
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
||||||
|
QJsonObject json = doc.object();
|
||||||
|
QString type = json["MessageType"].toString();
|
||||||
|
if(type == "ItemUpdate")
|
||||||
|
{
|
||||||
|
std::cout<<"Got item json:\n"<<QString::fromLatin1(jsonbytes).toStdString();
|
||||||
|
QJsonArray data = json["Data"].toArray();
|
||||||
|
std::vector<std::shared_ptr<Item>> items;
|
||||||
|
for(QJsonValueRef itemjson : data)
|
||||||
|
{
|
||||||
|
QJsonObject jsonobject = itemjson.toObject();
|
||||||
|
std::shared_ptr<Item> item = Item::loadItem(jsonobject);
|
||||||
|
if(item)
|
||||||
|
{
|
||||||
|
item->setLoaded(false);
|
||||||
|
items.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!items.empty())
|
||||||
|
gotItems(items, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Service::processIncomeingJson(jsonbytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::processComand(const QByteArray& command)
|
||||||
|
{
|
||||||
|
if(command.startsWith("MSG JSON LEN "))
|
||||||
|
{
|
||||||
|
state = STATE_RECV_JSON;
|
||||||
|
recievebytes = command.mid(13).toLongLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::socketReadyRead()
|
||||||
|
{
|
||||||
|
buffer += socket->readAll();
|
||||||
|
bool remianing = true;
|
||||||
|
while(remianing)
|
||||||
|
{
|
||||||
|
remianing = false;
|
||||||
|
while(state == STATE_IDLE && buffer.contains('\n'))
|
||||||
|
{
|
||||||
|
size_t newlineIndex = buffer.indexOf('\n');
|
||||||
|
QByteArray command = buffer.left(newlineIndex);
|
||||||
|
buffer.remove(0, newlineIndex+1);
|
||||||
|
processComand(command);
|
||||||
|
remianing = true;
|
||||||
|
}
|
||||||
|
if(state == STATE_RECV_JSON)
|
||||||
|
{
|
||||||
|
if(recievebytes <= buffer.size())
|
||||||
|
{
|
||||||
|
QByteArray json = buffer.left(recievebytes);
|
||||||
|
buffer.remove(0, recievebytes);
|
||||||
|
recievebytes = 0;
|
||||||
|
state = STATE_IDLE;
|
||||||
|
processIncomeingJson(json);
|
||||||
|
remianing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpClient::~TcpClient()
|
||||||
|
{
|
||||||
|
delete socket;
|
||||||
|
}
|
||||||
33
src/service/tcpclient.h
Normal file
33
src/service/tcpclient.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef TCPSERVER_CLIENT_H
|
||||||
|
#define TCPSERVER_CLIENT_H
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
class TcpClient : public Service
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QTcpSocket* socket;
|
||||||
|
client_state_t state = STATE_IDLE;
|
||||||
|
long long recievebytes = 0;
|
||||||
|
QByteArray buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TcpClient(QObject* parent = nullptr);
|
||||||
|
~TcpClient();
|
||||||
|
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override;
|
||||||
|
virtual void sendJson(const QJsonObject& json) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void processIncomeingJson(const QByteArray& jsonbytes) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void socketReadyRead();
|
||||||
|
void processComand(const QByteArray& command);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TCPSERVER_CLIENT_H
|
||||||
153
src/service/tcpserver.cpp
Normal file
153
src/service/tcpserver.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <vector>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
#include "items/item.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "tcpserver.h"
|
||||||
|
|
||||||
|
TcpServer::TcpServer(QObject* parent):
|
||||||
|
Service(parent),
|
||||||
|
server(this)
|
||||||
|
{
|
||||||
|
connect(&server, &QTcpServer::newConnection, this, &TcpServer::incomingConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::sendJson(const QJsonObject& json)
|
||||||
|
{
|
||||||
|
for(auto client: clients)
|
||||||
|
{
|
||||||
|
QByteArray jsonData = QJsonDocument(json).toJson();
|
||||||
|
client.socket->write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::processIncomeingJson(const QByteArray& jsonbytes)
|
||||||
|
{
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
||||||
|
QJsonObject json = doc.object();
|
||||||
|
QString type = json["MessageType"].toString();
|
||||||
|
if(type == "ItemUpdate")
|
||||||
|
{
|
||||||
|
qDebug()<<"Got Items";
|
||||||
|
QJsonArray data = json["Data"].toArray();
|
||||||
|
bool FullList = json["FullList"].toBool(false);
|
||||||
|
std::vector<std::shared_ptr<Item>> items;
|
||||||
|
for(QJsonValueRef itemjson : data)
|
||||||
|
{
|
||||||
|
QJsonObject jsonobject = itemjson.toObject();
|
||||||
|
std::shared_ptr<Item> item = Item::loadItem(jsonobject);
|
||||||
|
item->setLoaded(FullList);
|
||||||
|
if(item)
|
||||||
|
items.push_back(item);
|
||||||
|
}
|
||||||
|
if(FullList && !items.empty())
|
||||||
|
{
|
||||||
|
requestReplaceItems(items);
|
||||||
|
sigRequestSave();
|
||||||
|
}
|
||||||
|
else if(!items.empty())
|
||||||
|
{
|
||||||
|
gotItems(items, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Service::processIncomeingJson(jsonbytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpServer::launch(const QHostAddress &address, quint16 port)
|
||||||
|
{
|
||||||
|
return server.listen(address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::incomingConnection()
|
||||||
|
{
|
||||||
|
while(server.hasPendingConnections())
|
||||||
|
{
|
||||||
|
QTcpSocket* client = server.nextPendingConnection();
|
||||||
|
qDebug()<<"Got new client from"<<client->peerAddress().toString();
|
||||||
|
if(client)
|
||||||
|
{
|
||||||
|
clients.push_back({client});
|
||||||
|
connect(client, &QTcpSocket::errorOccurred, this, &TcpServer::socketError);
|
||||||
|
connect(client, &QTcpSocket::disconnected, this, &TcpServer::socketDisconnect);
|
||||||
|
connect(client, &QTcpSocket::readyRead, this, &TcpServer::socketReadyRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::socketError(QAbstractSocket::SocketError socketError)
|
||||||
|
{
|
||||||
|
(void)socketError;
|
||||||
|
for(size_t i = 0; i < clients.size(); i++)
|
||||||
|
{
|
||||||
|
if(clients[i].socket == TcpServer::sender())
|
||||||
|
{
|
||||||
|
clients.erase(clients.begin()+i);
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TcpServer::socketDisconnect()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < clients.size(); i++)
|
||||||
|
{
|
||||||
|
if(clients[i].socket == TcpServer::sender())
|
||||||
|
{
|
||||||
|
clients.erase(clients.begin()+i);
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::processComand(const QByteArray& command, Client& client)
|
||||||
|
{
|
||||||
|
if(command.startsWith("MSG JSON LEN "))
|
||||||
|
{
|
||||||
|
client.state = STATE_RECV_JSON;
|
||||||
|
client.recievebytes = command.mid(13).toLongLong();
|
||||||
|
qDebug()<<"Got command:"<<QString::fromLatin1(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::socketReadyRead()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < clients.size(); i++)
|
||||||
|
{
|
||||||
|
if(clients[i].socket == sender())
|
||||||
|
{
|
||||||
|
QByteArray newChars = clients[i].socket->readAll();
|
||||||
|
clients[i].buffer += newChars;
|
||||||
|
|
||||||
|
bool remianing = true;
|
||||||
|
while(remianing)
|
||||||
|
{
|
||||||
|
qDebug()<<clients[i].buffer;
|
||||||
|
remianing = false;
|
||||||
|
while(clients[i].state == STATE_IDLE && clients[i].buffer.contains('\n'))
|
||||||
|
{
|
||||||
|
size_t newlineIndex = clients[i].buffer.indexOf('\n');
|
||||||
|
QByteArray command = clients[i].buffer.left(newlineIndex);
|
||||||
|
clients[i].buffer.remove(0, newlineIndex+1);
|
||||||
|
processComand(command, clients[i]);
|
||||||
|
remianing = true;
|
||||||
|
}
|
||||||
|
if(clients[i].state == STATE_RECV_JSON)
|
||||||
|
{
|
||||||
|
if(clients[i].recievebytes <= clients[i].buffer.size())
|
||||||
|
{
|
||||||
|
QByteArray json = clients[i].buffer.left(clients[i].recievebytes);
|
||||||
|
clients[i].buffer.remove(0, clients[i].recievebytes);
|
||||||
|
clients[i].recievebytes = 0;
|
||||||
|
clients[i].state = STATE_IDLE;
|
||||||
|
processIncomeingJson(json);
|
||||||
|
remianing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/service/tcpserver.h
Normal file
45
src/service/tcpserver.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef TCPSERVER_SERVER_H
|
||||||
|
#define TCPSERVER_SERVER_H
|
||||||
|
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
class TcpServer : public Service
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
struct Client
|
||||||
|
{
|
||||||
|
QTcpSocket* socket;
|
||||||
|
QByteArray buffer;
|
||||||
|
client_state_t state = STATE_IDLE;
|
||||||
|
long long recievebytes = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Client> clients;
|
||||||
|
QTcpServer server;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TcpServer(QObject* parent = nullptr);
|
||||||
|
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override;
|
||||||
|
virtual void sendJson(const QJsonObject& json) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sigRequestSave();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void incomingConnection();
|
||||||
|
void socketError(QAbstractSocket::SocketError socketError);
|
||||||
|
void socketDisconnect();
|
||||||
|
void socketReadyRead();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void processIncomeingJson(const QByteArray& jsonbytes) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void processComand(const QByteArray& command, Client& client);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TCPSERVER_SERVER_H
|
||||||
|
|
@ -1,342 +0,0 @@
|
||||||
#include <QTcpSocket>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "items/item.h"
|
|
||||||
#include "items/itemstore.h"
|
|
||||||
#include "tcpserver.h"
|
|
||||||
|
|
||||||
|
|
||||||
TcpService::TcpService(QObject* parent):
|
|
||||||
ItemSource(parent)
|
|
||||||
{}
|
|
||||||
|
|
||||||
QJsonObject TcpService::createMessage(const QString& type, const QJsonArray& data)
|
|
||||||
{
|
|
||||||
QJsonObject json;
|
|
||||||
json["MessageType"] = type;
|
|
||||||
json["Data"] = data;
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpService::sensorEvent(Sensor sensor)
|
|
||||||
{
|
|
||||||
QJsonArray sensors;
|
|
||||||
QJsonObject sensorjson;
|
|
||||||
sensor.store(sensorjson);
|
|
||||||
sensors.append(sensorjson);
|
|
||||||
QJsonObject json = createMessage("SensorUpdate", sensors);
|
|
||||||
sendJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpService::itemUpdated(std::weak_ptr<Item> item)
|
|
||||||
{
|
|
||||||
qDebug()<<__func__;
|
|
||||||
QJsonArray items;
|
|
||||||
QJsonObject itemjson;
|
|
||||||
item.lock()->store(itemjson);
|
|
||||||
items.append(itemjson);
|
|
||||||
QJsonObject json = createMessage("ItemUpdate", items);
|
|
||||||
json["FullList"] = false;
|
|
||||||
sendJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpService::refresh()
|
|
||||||
{
|
|
||||||
sendJson(createMessage("GetSensors", QJsonArray()));
|
|
||||||
sendJson(createMessage("GetItems", QJsonArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpService::sendSensors()
|
|
||||||
{
|
|
||||||
QJsonArray sensors;
|
|
||||||
for(auto& sensor: *globalSensors.getSensors())
|
|
||||||
{
|
|
||||||
QJsonObject sensorjson;
|
|
||||||
sensor.store(sensorjson);
|
|
||||||
sensors.append(sensorjson);
|
|
||||||
}
|
|
||||||
sendJson(createMessage("SensorUpdate", sensors));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpService::sendItems()
|
|
||||||
{
|
|
||||||
QJsonArray items;
|
|
||||||
for(auto& item: *globalItems.getItems())
|
|
||||||
{
|
|
||||||
QJsonObject itemjson;
|
|
||||||
item->store(itemjson);
|
|
||||||
items.append(itemjson);
|
|
||||||
}
|
|
||||||
QJsonObject json = createMessage("ItemUpdate", items);
|
|
||||||
json["FullList"] = true;
|
|
||||||
sendJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TcpService::processIncomeingJson(const QByteArray& jsonbytes)
|
|
||||||
{
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
|
||||||
qDebug()<<"Got Json:"<<QString::fromLatin1(doc.toJson(QJsonDocument::JsonFormat::Indented));
|
|
||||||
QJsonObject json = doc.object();
|
|
||||||
QString type = json["MessageType"].toString();
|
|
||||||
if(type == "GetSensors")
|
|
||||||
{
|
|
||||||
qDebug()<<"Sending sensors";
|
|
||||||
sendSensors();
|
|
||||||
}
|
|
||||||
else if(type == "GetItems")
|
|
||||||
{
|
|
||||||
qDebug()<<"Sending Items";
|
|
||||||
sendItems();
|
|
||||||
}
|
|
||||||
else if(type == "SensorUpdate")
|
|
||||||
{
|
|
||||||
QJsonArray data = json["Data"].toArray();
|
|
||||||
for(QJsonValueRef sensorjson : data)
|
|
||||||
{
|
|
||||||
QJsonObject jsonobject = sensorjson.toObject();
|
|
||||||
Sensor sensor(jsonobject);
|
|
||||||
gotSensor(sensor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpClient::TcpClient(QObject* parent):
|
|
||||||
TcpService(parent),
|
|
||||||
socket(new QTcpSocket(this))
|
|
||||||
{
|
|
||||||
connect(socket, &QTcpSocket::readyRead, this, &TcpClient::socketReadyRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpClient::sendJson(const QJsonObject& json)
|
|
||||||
{
|
|
||||||
QByteArray jsonData = QJsonDocument(json).toJson();
|
|
||||||
socket->write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TcpClient::launch(const QHostAddress &address, quint16 port)
|
|
||||||
{
|
|
||||||
socket->connectToHost(address, port);
|
|
||||||
return socket->waitForConnected(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpClient::processIncomeingJson(const QByteArray& jsonbytes)
|
|
||||||
{
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
|
||||||
QJsonObject json = doc.object();
|
|
||||||
QString type = json["MessageType"].toString();
|
|
||||||
if(type == "ItemUpdate")
|
|
||||||
{
|
|
||||||
std::cout<<"Got item json:\n"<<QString::fromLatin1(jsonbytes).toStdString();
|
|
||||||
QJsonArray data = json["Data"].toArray();
|
|
||||||
std::vector<std::shared_ptr<Item>> items;
|
|
||||||
for(QJsonValueRef itemjson : data)
|
|
||||||
{
|
|
||||||
QJsonObject jsonobject = itemjson.toObject();
|
|
||||||
std::shared_ptr<Item> item = Item::loadItem(jsonobject);
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
item->setLoaded(false);
|
|
||||||
items.push_back(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!items.empty())
|
|
||||||
gotItems(items, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TcpService::processIncomeingJson(jsonbytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpClient::processComand(const QByteArray& command)
|
|
||||||
{
|
|
||||||
if(command.startsWith("MSG JSON LEN "))
|
|
||||||
{
|
|
||||||
state = STATE_RECV_JSON;
|
|
||||||
recievebytes = command.mid(13).toLongLong();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpClient::socketReadyRead()
|
|
||||||
{
|
|
||||||
buffer += socket->readAll();
|
|
||||||
bool remianing = true;
|
|
||||||
while(remianing)
|
|
||||||
{
|
|
||||||
remianing = false;
|
|
||||||
while(state == STATE_IDLE && buffer.contains('\n'))
|
|
||||||
{
|
|
||||||
size_t newlineIndex = buffer.indexOf('\n');
|
|
||||||
QByteArray command = buffer.left(newlineIndex);
|
|
||||||
buffer.remove(0, newlineIndex+1);
|
|
||||||
processComand(command);
|
|
||||||
remianing = true;
|
|
||||||
}
|
|
||||||
if(state == STATE_RECV_JSON)
|
|
||||||
{
|
|
||||||
if(recievebytes <= buffer.size())
|
|
||||||
{
|
|
||||||
QByteArray json = buffer.left(recievebytes);
|
|
||||||
buffer.remove(0, recievebytes);
|
|
||||||
recievebytes = 0;
|
|
||||||
state = STATE_IDLE;
|
|
||||||
processIncomeingJson(json);
|
|
||||||
remianing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpClient::~TcpClient()
|
|
||||||
{
|
|
||||||
delete socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpServer::TcpServer(QObject* parent):
|
|
||||||
TcpService(parent),
|
|
||||||
server(this)
|
|
||||||
{
|
|
||||||
connect(&server, &QTcpServer::newConnection, this, &TcpServer::incomingConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::sendJson(const QJsonObject& json)
|
|
||||||
{
|
|
||||||
for(auto client: clients)
|
|
||||||
{
|
|
||||||
QByteArray jsonData = QJsonDocument(json).toJson();
|
|
||||||
client.socket->write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::processIncomeingJson(const QByteArray& jsonbytes)
|
|
||||||
{
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(jsonbytes);
|
|
||||||
QJsonObject json = doc.object();
|
|
||||||
QString type = json["MessageType"].toString();
|
|
||||||
if(type == "ItemUpdate")
|
|
||||||
{
|
|
||||||
qDebug()<<"Got Items";
|
|
||||||
QJsonArray data = json["Data"].toArray();
|
|
||||||
bool FullList = json["FullList"].toBool(false);
|
|
||||||
std::vector<std::shared_ptr<Item>> items;
|
|
||||||
for(QJsonValueRef itemjson : data)
|
|
||||||
{
|
|
||||||
QJsonObject jsonobject = itemjson.toObject();
|
|
||||||
std::shared_ptr<Item> item = Item::loadItem(jsonobject);
|
|
||||||
item->setLoaded(FullList);
|
|
||||||
if(item)
|
|
||||||
items.push_back(item);
|
|
||||||
}
|
|
||||||
if(FullList && !items.empty())
|
|
||||||
{
|
|
||||||
requestReplaceItems(items);
|
|
||||||
sigRequestSave();
|
|
||||||
}
|
|
||||||
else if(!items.empty())
|
|
||||||
{
|
|
||||||
gotItems(items, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TcpService::processIncomeingJson(jsonbytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TcpServer::launch(const QHostAddress &address, quint16 port)
|
|
||||||
{
|
|
||||||
return server.listen(address, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::incomingConnection()
|
|
||||||
{
|
|
||||||
while(server.hasPendingConnections())
|
|
||||||
{
|
|
||||||
QTcpSocket* client = server.nextPendingConnection();
|
|
||||||
qDebug()<<"Got new client from"<<client->peerAddress().toString();
|
|
||||||
if(client)
|
|
||||||
{
|
|
||||||
clients.push_back({client});
|
|
||||||
connect(client, &QTcpSocket::errorOccurred, this, &TcpServer::socketError);
|
|
||||||
connect(client, &QTcpSocket::disconnected, this, &TcpServer::socketDisconnect);
|
|
||||||
connect(client, &QTcpSocket::readyRead, this, &TcpServer::socketReadyRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::socketError(QAbstractSocket::SocketError socketError)
|
|
||||||
{
|
|
||||||
(void)socketError;
|
|
||||||
for(size_t i = 0; i < clients.size(); i++)
|
|
||||||
{
|
|
||||||
if(clients[i].socket == TcpServer::sender())
|
|
||||||
{
|
|
||||||
clients.erase(clients.begin()+i);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void TcpServer::socketDisconnect()
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < clients.size(); i++)
|
|
||||||
{
|
|
||||||
if(clients[i].socket == TcpServer::sender())
|
|
||||||
{
|
|
||||||
clients.erase(clients.begin()+i);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::processComand(const QByteArray& command, Client& client)
|
|
||||||
{
|
|
||||||
if(command.startsWith("MSG JSON LEN "))
|
|
||||||
{
|
|
||||||
client.state = STATE_RECV_JSON;
|
|
||||||
client.recievebytes = command.mid(13).toLongLong();
|
|
||||||
qDebug()<<"Got command:"<<QString::fromLatin1(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcpServer::socketReadyRead()
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < clients.size(); i++)
|
|
||||||
{
|
|
||||||
if(clients[i].socket == sender())
|
|
||||||
{
|
|
||||||
QByteArray newChars = clients[i].socket->readAll();
|
|
||||||
clients[i].buffer += newChars;
|
|
||||||
|
|
||||||
bool remianing = true;
|
|
||||||
while(remianing)
|
|
||||||
{
|
|
||||||
qDebug()<<clients[i].buffer;
|
|
||||||
remianing = false;
|
|
||||||
while(clients[i].state == STATE_IDLE && clients[i].buffer.contains('\n'))
|
|
||||||
{
|
|
||||||
size_t newlineIndex = clients[i].buffer.indexOf('\n');
|
|
||||||
QByteArray command = clients[i].buffer.left(newlineIndex);
|
|
||||||
clients[i].buffer.remove(0, newlineIndex+1);
|
|
||||||
processComand(command, clients[i]);
|
|
||||||
remianing = true;
|
|
||||||
}
|
|
||||||
if(clients[i].state == STATE_RECV_JSON)
|
|
||||||
{
|
|
||||||
if(clients[i].recievebytes <= clients[i].buffer.size())
|
|
||||||
{
|
|
||||||
QByteArray json = clients[i].buffer.left(clients[i].recievebytes);
|
|
||||||
clients[i].buffer.remove(0, clients[i].recievebytes);
|
|
||||||
clients[i].recievebytes = 0;
|
|
||||||
clients[i].state = STATE_IDLE;
|
|
||||||
processIncomeingJson(json);
|
|
||||||
remianing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
101
src/tcpserver.h
101
src/tcpserver.h
|
|
@ -1,101 +0,0 @@
|
||||||
#ifndef TCPSERVER_H
|
|
||||||
#define TCPSERVER_H
|
|
||||||
|
|
||||||
#include <QTcpServer>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "sensors/sensor.h"
|
|
||||||
#include "items/item.h"
|
|
||||||
#include "items/itemsource.h"
|
|
||||||
|
|
||||||
class TcpService : public ItemSource
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
protected:
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
STATE_IDLE,
|
|
||||||
STATE_RECV_JSON,
|
|
||||||
} client_state_t;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void gotSensor(Sensor sensor);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void sensorEvent(Sensor sensor);
|
|
||||||
void itemUpdated(std::weak_ptr<Item> item);
|
|
||||||
virtual void refresh() override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TcpService(QObject* parent = nullptr);
|
|
||||||
void sendSensors();
|
|
||||||
void sendItems();
|
|
||||||
virtual void sendJson(const QJsonObject& json) = 0;
|
|
||||||
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static QJsonObject createMessage(const QString& type, const QJsonArray& data);
|
|
||||||
virtual void processIncomeingJson(const QByteArray& jsonbytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
class TcpClient : public TcpService
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
QTcpSocket* socket;
|
|
||||||
client_state_t state = STATE_IDLE;
|
|
||||||
long long recievebytes = 0;
|
|
||||||
QByteArray buffer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TcpClient(QObject* parent = nullptr);
|
|
||||||
~TcpClient();
|
|
||||||
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override;
|
|
||||||
virtual void sendJson(const QJsonObject& json) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void processIncomeingJson(const QByteArray& jsonbytes) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void socketReadyRead();
|
|
||||||
void processComand(const QByteArray& command);
|
|
||||||
};
|
|
||||||
|
|
||||||
class TcpServer : public TcpService
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
struct Client
|
|
||||||
{
|
|
||||||
QTcpSocket* socket;
|
|
||||||
QByteArray buffer;
|
|
||||||
client_state_t state = STATE_IDLE;
|
|
||||||
long long recievebytes = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Client> clients;
|
|
||||||
QTcpServer server;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TcpServer(QObject* parent = nullptr);
|
|
||||||
virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override;
|
|
||||||
virtual void sendJson(const QJsonObject& json) override;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void sigRequestSave();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void incomingConnection();
|
|
||||||
void socketError(QAbstractSocket::SocketError socketError);
|
|
||||||
void socketDisconnect();
|
|
||||||
void socketReadyRead();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void processIncomeingJson(const QByteArray& jsonbytes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void processComand(const QByteArray& command, Client& client);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TCPSERVER_H
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue