337 lines
12 KiB
C++
337 lines
12 KiB
C++
#include "ApismClient.h"
|
||
|
||
#include <QDebug>
|
||
#include <QByteArray>
|
||
#include <QHostAddress>
|
||
#include <QString>
|
||
#include <QList>
|
||
#include <QListIterator>
|
||
#include <QScopedPointer>
|
||
#include <QProcess>
|
||
#include <QRegularExpression>
|
||
|
||
|
||
ApismClient::ApismClient(QObject *parent)
|
||
: QObject(parent)
|
||
, lastError(0)
|
||
, lastErrorDescription("")
|
||
, currentRequest(ISMAS::REQUEST::NO_REQUEST)
|
||
, retryCounter(0)
|
||
, flagValidParameter(false)
|
||
{
|
||
this->apismTcpSendClient.reset(new ApismTcpClient("127.0.0.1", "7777", ApismTcpClient::ExpectedResponse::STATE, this));
|
||
this->apismTcpRequestResponseClient.reset(new ApismTcpClient("127.0.0.1", "7778", ApismTcpClient::ExpectedResponse::JSON, this));
|
||
|
||
this->apismTcpRequestResponseClient->setResponseTimeout(30000);
|
||
|
||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::receivedData,
|
||
this, &ApismClient::onReceivedResponse);
|
||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::responseTimeout,
|
||
this, &ApismClient::onRequestResponseClientResponseTimeout);
|
||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectTimeout,
|
||
this, &ApismClient::onRequestResponseClientConnectTimeout);
|
||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionClosedByRemoteHost,
|
||
this, &ApismClient::onRequestResponseClientConnectionClosedByRemoteHost);
|
||
connect(apismTcpRequestResponseClient.get(), &ApismTcpClient::connectionRefusedError,
|
||
this, &ApismClient::restartApism);
|
||
|
||
connect(apismTcpSendClient.get(), &ApismTcpClient::responseTimeout,
|
||
this, &ApismClient::onSendClientResponseTimeout);
|
||
connect(apismTcpSendClient.get(), &ApismTcpClient::connectionRefusedError,
|
||
this, &ApismClient::restartApism);
|
||
|
||
|
||
// not needed as APISM closes the socket after we send data, so readyRead()
|
||
// might not even fire
|
||
// connect(&m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
|
||
|
||
// defined for Qt >= 5.15, we have 5.12
|
||
// qRegisterMetaType<QAbstractSocket::SocketError>();
|
||
// connect(&m_socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
|
||
// this, SLOT(onSocketError(&QAbstractSocket::SocketError)));
|
||
|
||
// switch of DEBUG:
|
||
this->apismTcpSendClient->setDebug(true);
|
||
this->apismTcpRequestResponseClient->setDebug(true);
|
||
}
|
||
|
||
ApismClient::~ApismClient() {
|
||
}
|
||
|
||
void ApismClient::restartApism() {
|
||
QProcess::startDetached("/bin/systemctl", {"restart", "apism"});
|
||
}
|
||
|
||
|
||
void ApismClient::sendSelfTest() {
|
||
this->currentRequest = ISMAS::REQUEST::SELF;
|
||
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_SELF#J={}");
|
||
}
|
||
|
||
void ApismClient::sendRequestParameter() {
|
||
this->currentRequest = ISMAS::REQUEST::PARAMETER;
|
||
this->apismTcpRequestResponseClient->sendData("#M=APISM#C=REQ_ISMASPARAMETER#J={}");
|
||
}
|
||
|
||
void ApismClient::handleISMASResponseError()
|
||
{
|
||
switch (this->currentRequest) {
|
||
case ISMAS::REQUEST::NO_REQUEST:
|
||
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: " << currentRequest;
|
||
break;
|
||
case ISMAS::REQUEST::PING:
|
||
//emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||
break;
|
||
case ISMAS::REQUEST::SELF:
|
||
//emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||
break;
|
||
case ISMAS::REQUEST::PARAMETER:
|
||
//emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||
break;
|
||
}
|
||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||
}
|
||
|
||
|
||
void ApismClient::handleISMASOfflineResponseError()
|
||
{
|
||
nsApismInterface::RESULT_STATE resultState;
|
||
|
||
if (this->retryCounter < 50) {
|
||
resultState = nsApismInterface::RESULT_STATE::ERROR_RETRY;
|
||
this->retryCounter++;
|
||
}
|
||
else {
|
||
resultState = nsApismInterface::RESULT_STATE::ERROR_BACKEND;
|
||
this->retryCounter = 0;
|
||
}
|
||
|
||
qCritical() << "ApismClient::handleISMASOfflineResponseError(): currentRequest is " << this->currentRequest;
|
||
|
||
|
||
switch (this->currentRequest) {
|
||
case ISMAS::REQUEST::NO_REQUEST:
|
||
break;
|
||
case ISMAS::REQUEST::PING:
|
||
//emit this->sendMininformPingResponse(resultState, QJsonObject());
|
||
//break;
|
||
case ISMAS::REQUEST::SELF:
|
||
emit this->sendReqSelfResponse(resultState, QJsonObject());
|
||
break;
|
||
case ISMAS::REQUEST::PARAMETER:
|
||
emit this->sendReqParameterResponse(resultState, QJsonObject());
|
||
break;
|
||
}
|
||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||
|
||
// note: this does not work here, because a new request within this error handling method
|
||
// must use a new socket connection!
|
||
// This does not work with an allready open socket connection.
|
||
/* Communication to APISM must be in the following way:
|
||
* 1) establish socket connection
|
||
* 2) send your request to this socket
|
||
* 3) wait for a possible answer
|
||
* 4) receive the answer
|
||
* 5) close socket connection
|
||
*
|
||
* => a request can only be sent to apsim if the socket is closed!
|
||
* => apism (socket) is blocked systemwide until socket is closed!
|
||
* =>
|
||
*/
|
||
|
||
//this->sendSelfTest();
|
||
}
|
||
|
||
|
||
|
||
void ApismClient::private_handleErrorResponse(QString errorString)
|
||
{
|
||
qCritical() << "------------------------------------------------------";
|
||
qCritical() << "ApismClient::private_handleErrorResponse(" << errorString << ")";
|
||
qCritical() << " this->retryCounter = " << this->retryCounter;
|
||
qCritical() << "------------------------------------------------------";
|
||
|
||
this->handleISMASOfflineResponseError();
|
||
}
|
||
|
||
|
||
/*
|
||
{\r\n \"REQ_START#53365_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||
\r\n \"Response\": {\r\n \"Result\": \"ERR:Ung<6E>ltiger Datums-String: \"\r\n }\r\n}
|
||
*/
|
||
|
||
/*
|
||
: ISMAS received: "{\r\n \"REQ_PING#30844_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||
"PING": { "IsAviable": "TRUE" }
|
||
}"
|
||
*/
|
||
|
||
//void ApismClient::onSendClientResponseTimeout()
|
||
//{
|
||
//
|
||
//}
|
||
|
||
void ApismClient::private_handleReqSelfResponse(QJsonObject response)
|
||
{
|
||
bool ismasConnected = response["ISMAS"].toBool();
|
||
QString brokerConnectedString = response["Broker"].toString();
|
||
|
||
qCritical() << "ApismClient::handleReqSelfResponse() " << endl
|
||
<< " ismasConnected = " << ismasConnected << endl
|
||
<< " brokerConnectedString = " << brokerConnectedString;
|
||
|
||
/* possible values: "Restart connection"
|
||
* "Connected"
|
||
* "NOT CONNECTED"
|
||
*/
|
||
if (brokerConnectedString == "NOT CONNECTED") {
|
||
qCritical() << "ApismClient: \"NOT CONNECTED\": restart APISM";
|
||
this->restartApism();
|
||
}
|
||
|
||
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||
}
|
||
|
||
/**
|
||
* sample parameter response:
|
||
{
|
||
"REQ_ISMASPARAMETER#4210959_Response": {
|
||
"Aknoledge": "OK"
|
||
},
|
||
"Dev_ID": {
|
||
"Device_Type": "2020",
|
||
"Custom_ID": 332,
|
||
"Device_ID": 99
|
||
},
|
||
"Fileupload": {
|
||
"TRG": ""
|
||
},
|
||
"Parameter": {
|
||
"Location": "An Der Bahn 11",
|
||
"Group": "Group1",
|
||
"Zone": "Zone1",
|
||
"Name": "PSA",
|
||
"SecNumber": "0",
|
||
"LastAcc": "0",
|
||
"GPSLat": "49.6062",
|
||
"GPSLon": "12.1244",
|
||
"TarifID": "none",
|
||
"UserTextID": "1"
|
||
"TERMINALID": "",
|
||
"TERMINALKEY": ""
|
||
},
|
||
"Lock": {
|
||
"Locked": "0"
|
||
}
|
||
}
|
||
*/
|
||
void ApismClient::private_handleParameterResponse(QJsonObject response)
|
||
{
|
||
// extract location info and store location info in persistent data:
|
||
QJsonValue jsonSubVal_Location;
|
||
jsonSubVal_Location = response["Location"];
|
||
|
||
QString locationString = jsonSubVal_Location.toString("no location");
|
||
|
||
//this->persistentData->setParameter("Location", locationString);
|
||
|
||
// feature UserText
|
||
QJsonValue jsonSubVal_UserText;
|
||
jsonSubVal_UserText = response["UserTextID"];
|
||
QString userTextIdString = jsonSubVal_UserText.toString("0");
|
||
//this->persistentData->setParameter("UserTextID", userTextIdString);
|
||
|
||
// TERMINALID
|
||
//QJsonValue jsonSubVal_TERMINALID;
|
||
//jsonSubVal_TERMINALID = response["TERMINALID"];
|
||
//QString terminalIdString = jsonSubVal_TERMINALID.toString("");
|
||
//QString terminalIdFile = this->m_config->getSystemDataPath() + "TERMINALID";
|
||
//QString terminalIdStringOrigin = ATBSystem::readPSAConfigString(terminalIdFile);
|
||
//if ( (terminalIdString.size() > 1) &&
|
||
// (terminalIdString != terminalIdStringOrigin))
|
||
//{
|
||
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALID: " << terminalIdString;
|
||
// ATBSystem::setPSAConfigString(terminalIdFile, terminalIdString);
|
||
//}
|
||
|
||
// TERMINALKEY
|
||
//QJsonValue jsonSubVal_TERMINALKEY;
|
||
//jsonSubVal_TERMINALKEY = response["TERMINALKEY"];
|
||
//QString terminalKeyString = jsonSubVal_TERMINALKEY.toString("");
|
||
//QString terminalJeyFile = this->m_config->getSystemDataPath() + "TERMINALKEY";
|
||
//QString terminalKeyStringOrigin = ATBSystem::readPSAConfigString(terminalJeyFile);
|
||
//if ( (terminalKeyString.size() > 1) &&
|
||
// (terminalKeyString != terminalKeyStringOrigin))
|
||
//{
|
||
// qCritical() << "ApismClient::handleParameterResponse(): new TERMINALKEY: " << terminalKeyString;
|
||
//
|
||
|
||
// ATBSystem::setPSAConfigString(terminalJeyFile, terminalKeyString);
|
||
//}
|
||
|
||
|
||
//qCritical() << "ApismClient::handleParameterResponse() " << endl
|
||
// << " Location = " << locationString << endl
|
||
// << " UserTextID = " << userTextIdString << endl
|
||
// << " TERMINALID = " << terminalIdString << endl
|
||
// << " TERMINALKEY = " << terminalKeyString;
|
||
|
||
|
||
if (locationString != "no location") {
|
||
this->flagValidParameter = true;
|
||
emit this->sendReqParameterResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||
}
|
||
}
|
||
|
||
void ApismClient::private_handleFileUploadResponse(QJsonObject response) {
|
||
QJsonValue jsonSubVal_TRG{response["TRG"]};
|
||
if (jsonSubVal_TRG.isUndefined()) {
|
||
return;
|
||
}
|
||
|
||
bool updateRequested = (jsonSubVal_TRG.toString("") == "WAIT");
|
||
|
||
}
|
||
|
||
/************************************************************************************************
|
||
* operators
|
||
*/
|
||
QDebug operator<< (QDebug debug, ISMAS::REQUEST request)
|
||
{
|
||
switch(request) {
|
||
case ISMAS::REQUEST::NO_REQUEST:
|
||
debug << QString("ISMAS::REQUEST::NO_REQUEST");
|
||
break;
|
||
case ISMAS::REQUEST::PING:
|
||
debug << QString("ISMAS::REQUEST::PING");
|
||
break;
|
||
case ISMAS::REQUEST::SELF:
|
||
debug << QString("ISMAS::REQUEST::SELF");
|
||
break;
|
||
case ISMAS::REQUEST::PARAMETER:
|
||
debug << QString("ISMAS::REQUEST::PARAMETER");
|
||
break;
|
||
}
|
||
return debug;
|
||
}
|
||
|
||
QString& operator<< (QString& str, ISMAS::REQUEST request)
|
||
{
|
||
switch(request) {
|
||
case ISMAS::REQUEST::NO_REQUEST:
|
||
str = QString("ISMAS::REQUEST::NO_REQUEST");
|
||
break;
|
||
case ISMAS::REQUEST::PING:
|
||
str = QString("ISMAS::REQUEST::PING");
|
||
break;
|
||
case ISMAS::REQUEST::SELF:
|
||
str = QString("ISMAS::REQUEST::SELF");
|
||
break;
|
||
case ISMAS::REQUEST::PARAMETER:
|
||
str = QString("ISMAS::REQUEST::PARAMETER");
|
||
break;
|
||
}
|
||
return str;
|
||
}
|
||
|