180 lines
5.9 KiB
C++
180 lines
5.9 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright (C) 2013 - 2024, nymea GmbH
|
|
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
|
*
|
|
* This file is part of nymea-energy-plugin-nymea.
|
|
*
|
|
* nymea-energy-plugin-nymea.s 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nymea-energy-plugin-nymea.s 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 nymea-energy-plugin-nymea. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "mockcontroller.h"
|
|
|
|
#include <integrations/thing.h>
|
|
|
|
#include <QTcpSocket>
|
|
#include <QJsonDocument>
|
|
#include <QRegularExpression>
|
|
|
|
#include "extern-plugininfo.h"
|
|
|
|
EnergyMockController::EnergyMockController(Thing *thing, QObject *parent):
|
|
QTcpServer(parent),
|
|
m_thing(thing)
|
|
{
|
|
|
|
}
|
|
|
|
EnergyMockController::~EnergyMockController()
|
|
{
|
|
close();
|
|
}
|
|
|
|
void EnergyMockController::incomingConnection(qintptr socket)
|
|
{
|
|
QTcpSocket* s = new QTcpSocket(this);
|
|
connect(s, &QTcpSocket::readyRead, this, &EnergyMockController::onReadyRead);
|
|
connect(s, &QTcpSocket::disconnected, s, [s](){
|
|
s->deleteLater();
|
|
});
|
|
s->setSocketDescriptor(socket);
|
|
}
|
|
|
|
void EnergyMockController::logActionExecuted(const ActionType &actionType, const Action &action)
|
|
{
|
|
QVariantMap actionMap;
|
|
actionMap.insert("timestamp", static_cast<uint>(QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000));
|
|
actionMap.insert("actionTypeId", action.actionTypeId());
|
|
actionMap.insert("name", actionType.name());
|
|
actionMap.insert("displayName", actionType.displayName());
|
|
QVariantList params;
|
|
foreach (const Param ¶m, action.params()) {
|
|
QVariantMap paramsMap;
|
|
paramsMap.insert("paramTypeId", param.paramTypeId());
|
|
paramsMap.insert("value", param.value());
|
|
paramsMap.insert("name", actionType.paramTypes().findById(param.paramTypeId()).name());
|
|
params.append(paramsMap);
|
|
}
|
|
actionMap.insert("params", params);
|
|
m_executedActions.append(actionMap);
|
|
//qCDebug(dcEnergyMocks()) << "Action logged" << actionMap;
|
|
}
|
|
|
|
void EnergyMockController::onReadyRead()
|
|
{
|
|
QTcpSocket *client = static_cast<QTcpSocket*>(sender());
|
|
QByteArray data = client->readAll();
|
|
|
|
// split the data into header and payload
|
|
int headerEndIndex = data.indexOf("\r\n\r\n");
|
|
if (headerEndIndex < 0) {
|
|
qCWarning(dcEnergyMocks()) << "Could not parse payload" << data;
|
|
return;
|
|
}
|
|
|
|
QByteArray rawHeader = data.left(headerEndIndex);
|
|
QByteArray payload = data.right(data.length() - headerEndIndex).simplified();
|
|
|
|
// parse status line
|
|
QStringList headerLines = QString(rawHeader).split(QRegularExpression("\r\n"));
|
|
QString statusLine = headerLines.takeFirst();
|
|
QStringList statusLineTokens = statusLine.split(QRegularExpression("[ \r\n][ \r\n]*"));
|
|
|
|
// verify http version
|
|
QString httpVersion = statusLineTokens.at(2).toUtf8().simplified();
|
|
if (!httpVersion.contains("HTTP")) {
|
|
qCWarning(dcEnergyMocks()) << "Unknown HTTP version:" << httpVersion;
|
|
return;
|
|
}
|
|
|
|
QString methodString = statusLineTokens.at(0).simplified();
|
|
QUrl url = QUrl("http://example.com" + statusLineTokens.at(1).simplified());
|
|
QUrlQuery query(url);
|
|
|
|
if (url.path() == "/setstates") {
|
|
qCDebug(dcEnergyMocks()) << "Set states called" << methodString << url.path() << query.toString();
|
|
|
|
emit updateStateRequestReceived(query);
|
|
|
|
QTextStream os(client);
|
|
os.setAutoDetectUnicode(true);
|
|
os << generateHeader();
|
|
client->close();
|
|
return;
|
|
} else if (url.path() == "/actionhistory") {
|
|
QTextStream os(client);
|
|
os.setAutoDetectUnicode(true);
|
|
os << generateJsonResponse(QJsonDocument::fromVariant(m_executedActions));
|
|
client->close();
|
|
return;
|
|
} else if (url.path() == "/clearactionhistory") {
|
|
m_executedActions.clear();
|
|
QTextStream os(client);
|
|
os.setAutoDetectUnicode(true);
|
|
os << generateHeader();
|
|
client->close();
|
|
return;
|
|
}
|
|
|
|
|
|
// Default website
|
|
QTextStream os(client);
|
|
os.setAutoDetectUnicode(true);
|
|
os << generateWebPage();
|
|
client->close();
|
|
|
|
}
|
|
|
|
QByteArray EnergyMockController::generateHeader()
|
|
{
|
|
QByteArray contentHeader(
|
|
"HTTP/1.0 200 Ok\r\n"
|
|
"Content-Type: text/html; charset=\"utf-8\"\r\n"
|
|
"\r\n"
|
|
);
|
|
return contentHeader;
|
|
}
|
|
|
|
QByteArray EnergyMockController::generateJsonResponse(const QJsonDocument &document)
|
|
{
|
|
QByteArray body = document.toJson(QJsonDocument::Compact);
|
|
QByteArray contentHeader("HTTP/1.0 200 Ok\r\n");
|
|
contentHeader.append("Content-Type: application/json\r\n");
|
|
contentHeader.append(QString("Content-Length: %1").arg(body.length()).toUtf8() + "\r\n");
|
|
contentHeader.append("\r\n");
|
|
QByteArray response = contentHeader + body;
|
|
//qCDebug(dcEnergyMocks()) << "Action histroy response:" << response;
|
|
return response;
|
|
}
|
|
|
|
QByteArray EnergyMockController::generateWebPage()
|
|
{
|
|
QString body = QString(
|
|
"<html>"
|
|
"<body>"
|
|
"<h1>Mock device Controller</h1>\n"
|
|
"<hr>"
|
|
"<h2>Device Information</h2>"
|
|
"Name: %1<br>"
|
|
"ID: %2<br>"
|
|
"DeviceClass ID: %3<br>").arg(m_thing->name()).arg(m_thing->id().toString()).arg(m_thing->thingClassId().toString());
|
|
body.append("</body>");
|
|
body.append("</html>\n");
|
|
|
|
return generateHeader() + body.toUtf8();
|
|
}
|