This repository has been archived on 2026-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
Simon Stürz 37c2d0219d add debug categories to each plugin
fix loading vendorId
improoved man page
improoved help message
add extern ids to extern-plugininfo.h
2019-04-01 20:48:17 +02:00

220 lines
8.0 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is 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, version 2 of the License. *
* *
* Guh is 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 guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonrpcserver.h"
#include "extern-plugininfo.h"
JsonRpcServer::JsonRpcServer(QObject *parent) :
QObject(parent),
m_id(0)
{
m_manager = new TuneManager(31337, this);
connect(m_manager, &TuneManager::tuneConnectionStatusChanged, this, &JsonRpcServer::connectionStatusChanged);
connect(m_manager, &TuneManager::dataReady, this, &JsonRpcServer::processData);
}
void JsonRpcServer::start()
{
m_manager->start();
}
void JsonRpcServer::stop()
{
m_manager->stop();
}
bool JsonRpcServer::tuneAvailable()
{
return m_manager->tuneAvailable();
}
bool JsonRpcServer::sync(QList<Device *> deviceList)
{
if (!tuneAvailable()) {
return false;
}
QVariantMap message;
QVariantMap params;
QVariantList moods;
QVariantMap tune;
foreach (Device* device, deviceList) {
if (device->deviceClassId() == moodDeviceClassId) {
QVariantMap mood;
mood.insert("name", device->paramValue("name"));
mood.insert("deviceId", device->id());
mood.insert("position", device->paramValue("position"));
mood.insert("icon", device->paramValue("icon"));
QVariantMap states;
states.insert("value", device->stateValue(valueStateTypeId).toInt());
states.insert("active", device->stateValue(activeStateTypeId).toBool());
mood.insert("states", states);
moods.append(mood);
}
if (device->deviceClassId() == tuneDeviceClassId) {
tune.insert("name", device->paramValue("name"));
tune.insert("deviceId", device->id());
tune.insert("brightness", device->stateValue(brightnessStateTypeId).toInt());
tune.insert("power", device->stateValue(powerStateTypeId).toBool());
}
}
m_id++;
params.insert("moods", moods);
params.insert("tune", tune);
message.insert("method", "Items.Sync");
message.insert("id", m_id);
message.insert("params", params);
m_requests.insert(m_id, message);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
qCDebug(dcTune) << jsonDoc.toJson();
m_manager->sendData(jsonDoc.toJson(QJsonDocument::Compact));
return true;
}
void JsonRpcServer::executeAction(Device *device, const Action &action)
{
QVariantMap message;
QVariantMap params;
params.insert("deviceId", device->id());
params.insert("actionId", action.id());
if (device->deviceClassId() == moodDeviceClassId) {
message.insert("method", "Mood.ExecuteAction");
if (action.actionTypeId() == valueActionTypeId) {
params.insert("value", action.param("value").value().toInt());
params.insert("active", device->stateValue(activeStateTypeId).toBool());
} else if (action.actionTypeId() == activeActionTypeId) {
params.insert("value", device->stateValue(valueStateTypeId).toInt());
params.insert("active", action.param("active").value().toBool());
}
} else if(device->deviceClassId() == tuneDeviceClassId) {
message.insert("method", "Tune.ExecuteAction");
if (action.actionTypeId() == brightnessActionTypeId) {
params.insert("brightness", action.param("brightness").value().toInt());
params.insert("power", device->stateValue(powerStateTypeId).toBool());
} else if (action.actionTypeId() == powerActionTypeId) {
params.insert("brightness", device->stateValue(brightnessStateTypeId).toInt());
params.insert("power", action.param("power").value().toBool());
}
}
m_id++;
message.insert("id", m_id);
message.insert("params", params);
m_requests.insert(m_id, message);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
qCDebug(dcTune) << jsonDoc.toJson();
m_manager->sendData(jsonDoc.toJson(QJsonDocument::Compact));
}
QByteArray JsonRpcServer::formatResponse(int commandId, const QVariantMap &responseParams)
{
QVariantMap responseMap;
responseMap.insert("id", commandId);
responseMap.insert("success", true);
responseMap.insert("params", responseParams);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(responseMap);
return jsonDoc.toJson(QJsonDocument::Compact);
}
QByteArray JsonRpcServer::formatErrorResponse(int commandId, const QString &errorMessage)
{
QVariantMap responseMap;
responseMap.insert("id", commandId);
responseMap.insert("success", false);
responseMap.insert("error", errorMessage);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(responseMap);
return jsonDoc.toJson(QJsonDocument::Compact);
}
void JsonRpcServer::handleResponse(const QVariantMap &response)
{
int responseId = response.value("id").toInt();
if (!m_requests.contains(responseId)) {
qCWarning(dcTune) << "got a response without a corresponding request!!!!";
return;
}
// remove it request because we have a response now...
QVariantMap request = m_requests.take(responseId);
// Note: maby we have to do something if any request fails
if (!response.value("success").toBool()) {
qCWarning(dcTune) << "error for request:" << request << response.value("error").toString();
}
// check if this is a response to an action execution
if (response.contains("actionId")) {
emit gotActionResponse(response);
}
}
void JsonRpcServer::processData(const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcTune) << "failed to parse data" << data << ":" << error.errorString();
return;
}
QVariantMap message = jsonDoc.toVariant().toMap();
// check if the message has an id
if (!message.contains("id")) {
qCWarning(dcTune) << "message does not contain a valid id" << message;
return;
}
// if this is a response message to a request
if (message.contains("success") && !message.contains("method")) {
handleResponse(message);
return;
}
// otherwise we need a method
if (!message.contains("method")) {
qCWarning(dcTune) << "message does not contain a valid method" << message;
return;
}
int commandId = message.value("id").toInt();
if (message.value("method").toString() == "Mood.SyncStates") {
emit gotMoodSync(message.value("params").toMap());
m_manager->sendData(formatResponse(commandId));
}
if (message.value("method").toString() == "Tune.SyncStates") {
emit gotTuneSync(message.value("params").toMap());
m_manager->sendData(formatResponse(commandId));
}
}