178 lines
6.4 KiB
C++
178 lines
6.4 KiB
C++
#include "./connection.h"
|
|
|
|
#include "../alpm/manager.h"
|
|
#include "../alpm/upgradelookup.h"
|
|
#include "../alpm/suggestionslookup.h"
|
|
#include "../alpm/packageinfolookup.h"
|
|
#include "../alpm/config.h"
|
|
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonArray>
|
|
#include <QWebSocket>
|
|
#include <QCoreApplication>
|
|
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
namespace RepoIndex {
|
|
|
|
Connection::Connection(Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
|
QObject(parent),
|
|
m_socket(socket),
|
|
m_manager(alpmManager),
|
|
m_repoInfoUpdatesRequested(false),
|
|
m_groupInfoUpdatesRequested(false)
|
|
{
|
|
socket->setParent(this);
|
|
connect(socket, &QWebSocket::textMessageReceived, this, &Connection::processTextMessage);
|
|
connect(socket, &QWebSocket::binaryMessageReceived, this, &Connection::processBinaryMessage);
|
|
connect(socket, &QWebSocket::disconnected, this, &Connection::socketDisconnected);
|
|
}
|
|
|
|
void Connection::sendJson(const QJsonObject &obj)
|
|
{
|
|
m_socket->sendTextMessage(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
|
}
|
|
|
|
void Connection::sendError(const QString &msg, const QJsonValue &id)
|
|
{
|
|
QJsonObject response;
|
|
response.insert(QStringLiteral("class"), QStringLiteral("error"));
|
|
response.insert(QStringLiteral("msg"), msg);
|
|
if(!id.isNull() && !id.isUndefined()) {
|
|
response.insert(QStringLiteral("id"), id);
|
|
}
|
|
sendJson(response);
|
|
}
|
|
|
|
void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value)
|
|
{
|
|
QJsonObject response;
|
|
response.insert(QStringLiteral("class"), QStringLiteral("results"));
|
|
response.insert(QStringLiteral("what"), what);
|
|
response.insert(QStringLiteral("value"), value);
|
|
if(!id.isNull() && !id.isUndefined()) {
|
|
response.insert("id", id);
|
|
}
|
|
sendJson(response);
|
|
}
|
|
|
|
void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const QJsonArray &values)
|
|
{
|
|
QJsonObject response;
|
|
response.insert(QStringLiteral("class"), QStringLiteral("results"));
|
|
response.insert(QStringLiteral("what"), what);
|
|
response.insert(QStringLiteral("values"), values);
|
|
if(!id.isNull() && !id.isUndefined()) {
|
|
response.insert("id", id);
|
|
}
|
|
sendJson(response);
|
|
}
|
|
|
|
template<class Lookup, typename... Args>
|
|
void Connection::performLookup(const QJsonObject &request, Args &&...args)
|
|
{
|
|
auto *lookup = new Lookup(forward<Args>(args)...);
|
|
if(lookup->finished()) {
|
|
// the lookup has already finished when constructing the lookup object
|
|
// -> send the results immidiately
|
|
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), lookup->results());
|
|
} else if(!lookup->errors().isEmpty()) {
|
|
// error occured during the construction of the lookup object
|
|
// -> send the errors immidiately
|
|
QJsonObject results;
|
|
results.insert(QStringLiteral("errors"), lookup->errors());
|
|
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results);
|
|
} else {
|
|
// the lookup object has been created without errors but the lookup is not done yet
|
|
// -> send results when available
|
|
connect(lookup, &Lookup::resultsAvailable, this, &Connection::sendResult);
|
|
}
|
|
// in any case: the lookup object destroys itself
|
|
}
|
|
|
|
void Connection::handleQuery(const QJsonObject &obj)
|
|
{
|
|
const auto what = obj.value(QStringLiteral("what")).toString();
|
|
const auto id = obj.value(QStringLiteral("id"));
|
|
if(what == QLatin1String("basicrepoinfo")) {
|
|
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
|
|
sendResult(what, id, m_manager.basicRepoInfo());
|
|
} else if(what == QLatin1String("basicpkginfo") || what == QLatin1String("pkgdetails") || what == QLatin1String("fullpkginfo")) {
|
|
performLookup<PackageInfoLookup>(obj, m_manager, obj);
|
|
} else if(what == QLatin1String("groupinfo")) {
|
|
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
|
|
sendResults(what, id, m_manager.groupInfo());
|
|
} else if(what == QLatin1String("suggestions")) {
|
|
performLookup<SuggestionsLookup>(obj, m_manager, obj);
|
|
} else if(what == QLatin1String("upgradelookup")) {
|
|
performLookup<UpgradeLookupJson>(obj, m_manager, obj);
|
|
} else if(what == QLatin1String("ping")) {
|
|
sendResult(what, id, QStringLiteral("pong"));
|
|
} else {
|
|
sendError(QStringLiteral("unknown query"), id);
|
|
}
|
|
}
|
|
|
|
void Connection::handleCmd(const QJsonObject &obj)
|
|
{
|
|
const auto what = obj.value(QStringLiteral("what")).toString();
|
|
const auto id = obj.value(QStringLiteral("id"));
|
|
if(what == QLatin1String("stop")) {
|
|
if(m_socket->peerAddress().isLoopback()) {
|
|
cerr << shchar << "Info: Server stopped via web interface." << endl;
|
|
QCoreApplication::quit();
|
|
} else {
|
|
sendError(QStringLiteral("rejected"), id);
|
|
}
|
|
} else if(what == QLatin1String("reinitalpm")) {
|
|
if(m_socket->peerAddress().isLoopback()) {
|
|
cerr << shchar << "Info: Reinit of ALPM databases triggered via web interface." << endl;
|
|
m_manager.removeAllDatabases();
|
|
m_manager.addLocalDatabase();
|
|
m_manager.addDataBasesFromPacmanConfig();
|
|
m_manager.addDatabasesFromRepoIndexConfig();
|
|
m_manager.initAlpmDataBases(true);
|
|
} else {
|
|
sendError(QStringLiteral("rejected"), id);
|
|
}
|
|
} else {
|
|
sendError(QStringLiteral("unknown command"), id);
|
|
}
|
|
}
|
|
|
|
void Connection::processTextMessage(const QString &message)
|
|
{
|
|
QJsonParseError error;
|
|
QByteArray jsonData;
|
|
jsonData.append(message);
|
|
const QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
|
|
if(error.error == QJsonParseError::NoError) {
|
|
const QJsonObject obj = doc.object();
|
|
const QString msgClass = obj.value(QStringLiteral("class")).toString();
|
|
if(msgClass == QLatin1String("query")) {
|
|
handleQuery(obj);
|
|
} else if(msgClass == QLatin1String("cmd")) {
|
|
handleCmd(obj);
|
|
} else {
|
|
sendError(QStringLiteral("no message class specified"));
|
|
}
|
|
} else {
|
|
sendError(QStringLiteral("unable to parse JSON: ") + error.errorString());
|
|
}
|
|
}
|
|
|
|
void Connection::processBinaryMessage(const QByteArray &)
|
|
{
|
|
sendError(QStringLiteral("unable to parse binary messages"));
|
|
}
|
|
|
|
void Connection::socketDisconnected()
|
|
{
|
|
deleteLater();
|
|
}
|
|
|
|
}
|