UI: Prepare RPC.

This commit is contained in:
Nodir Temirkhodjaev 2021-04-28 15:28:38 +03:00
parent ed750dc6ee
commit 5bda1022e8
10 changed files with 210 additions and 127 deletions

View File

@ -116,6 +116,7 @@ SOURCES += \
util/json/jsonutil.cpp \
util/json/mapwrapper.cpp \
util/logger.cpp \
util/metaclassutil.cpp \
util/model/stringlistmodel.cpp \
util/model/tableitemmodel.cpp \
util/model/tablesqlmodel.cpp \
@ -238,6 +239,7 @@ HEADERS += \
task/taskworker.h \
task/taskzonedownloader.h \
translationmanager.h \
util/classhelpers.h \
util/conf/addressrange.h \
util/conf/confappswalker.h \
util/conf/confutil.h \
@ -251,6 +253,7 @@ HEADERS += \
util/json/jsonutil.h \
util/json/mapwrapper.h \
util/logger.h \
util/metaclassutil.h \
util/model/stringlistmodel.h \
util/model/tableitemmodel.h \
util/model/tablesqlmodel.h \

View File

@ -5,10 +5,16 @@
namespace Control {
enum Command : qint8 {
CommandNone = 0,
CommandConf,
CommandProg,
enum Command : qint8 { CommandNone = 0, CommandConf, CommandProg, CommandRpc };
enum RpcObject : qint8 {
Rpc_None = 0,
Rpc_AppInfoManager,
Rpc_ConfManager,
Rpc_DriverManager,
Rpc_QuotaManager,
Rpc_StatManager,
Rpc_TaskManager,
};
}

View File

@ -85,7 +85,7 @@ bool ControlManager::postCommand()
if (args.isEmpty())
return false;
return worker.postCommand(command, args);
return worker.sendCommand(command, Control::Rpc_None, 0, args) && worker.waitForSent();
}
void ControlManager::onNewConnection()

View File

@ -9,20 +9,57 @@ constexpr int commandMaxArgs = 7;
constexpr int commandArgMaxSize = 4 * 1024;
constexpr int dataMaxSize = 4 * 1024 * 1024;
struct DataHeader
template<typename T>
T *bufferAs(QByteArray &buffer, int offset = 0)
{
DataHeader(Control::Command command = Control::CommandNone, int dataSize = 0) :
m_command(command), m_dataSize(dataSize)
{
return reinterpret_cast<T *>(buffer.data() + offset);
}
bool buildArgsData(QByteArray &data, const QVariantList &args)
{
const int argsCount = args.count();
if (argsCount == 0)
return true;
if (argsCount > commandMaxArgs)
return false;
QDataStream stream(&data,
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QIODevice::WriteOnly
#else
QDataStream::WriteOnly
#endif
);
stream << qint8(argsCount);
for (const auto &arg : args) {
stream << arg;
}
Control::Command command() const { return static_cast<Control::Command>(m_command); }
int dataSize() const { return m_dataSize; }
return true;
}
private:
quint32 m_command : 8;
quint32 m_dataSize : 24;
};
bool parseArgsData(const QByteArray &data, QVariantList &args)
{
QDataStream stream(data);
qint8 argsCount;
stream >> argsCount;
if (argsCount > commandMaxArgs)
return false;
while (--argsCount >= 0) {
QVariant arg;
stream >> arg;
args.append(arg);
}
return true;
}
}
@ -45,16 +82,25 @@ void ControlWorker::abort()
socket()->close();
}
bool ControlWorker::postCommand(Control::Command command, const QVariantList &args)
bool ControlWorker::sendCommand(Control::Command command, Control::RpcObject rpcObj,
int methodIndex, const QVariantList &args)
{
QByteArray data;
if (!buildArgsData(data, args))
QByteArray buffer;
if (!buildArgsData(buffer, args))
return false;
writeDataHeader(command, data.size());
writeData(data);
new (bufferAs<DataHeader>(buffer))
DataHeader(command, rpcObj, methodIndex, buffer.size() - sizeof(DataHeader));
return socket()->waitForBytesWritten(1000);
socket()->write(buffer);
return true;
}
bool ControlWorker::waitForSent(int msecs) const
{
return socket()->waitForBytesWritten(msecs);
}
void ControlWorker::processRequest()
@ -67,29 +113,26 @@ void ControlWorker::processRequest()
void ControlWorker::clearRequest()
{
m_requestCommand = Control::CommandNone;
m_requestDataSize = 0;
m_request.clear();
m_requestData.clear();
}
bool ControlWorker::readRequest()
{
if (m_requestCommand == Control::CommandNone
&& !readDataHeader(m_requestCommand, m_requestDataSize))
if (m_request.command() == Control::CommandNone && !readRequestHeader())
return false;
if (m_requestDataSize > 0) {
if (m_request.dataSize() > 0) {
if (socket()->bytesAvailable() == 0)
return true; // need more data
const QByteArray data = readData(m_requestDataSize);
const QByteArray data = socket()->read(m_request.dataSize() - m_requestData.size());
if (data.isEmpty())
return false;
m_requestData += data;
m_requestDataSize -= data.size();
if (m_requestDataSize > 0)
if (m_requestData.size() < m_request.dataSize())
return true; // need more data
}
@ -97,85 +140,23 @@ bool ControlWorker::readRequest()
if (!m_requestData.isEmpty() && !parseArgsData(m_requestData, args))
return false;
emit requestReady(m_requestCommand, args);
emit requestReady(m_request.command(), args);
clearRequest();
return true;
}
void ControlWorker::writeDataHeader(Control::Command command, int dataSize)
bool ControlWorker::readRequestHeader()
{
DataHeader dataHeader(command, dataSize);
socket()->write((const char *) &dataHeader, sizeof(DataHeader));
}
bool ControlWorker::readDataHeader(Control::Command &command, int &dataSize)
{
DataHeader dataHeader;
if (socket()->read((char *) &dataHeader, sizeof(DataHeader)) != sizeof(DataHeader))
if (socket()->read((char *) &m_request, sizeof(DataHeader)) != sizeof(DataHeader))
return false;
command = dataHeader.command();
dataSize = dataHeader.dataSize();
if (dataSize > dataMaxSize)
if (m_request.dataSize() > dataMaxSize)
return false;
return true;
}
void ControlWorker::writeData(const QByteArray &data)
{
socket()->write(data);
}
QByteArray ControlWorker::readData(int dataSize)
{
return socket()->read(dataSize);
}
bool ControlWorker::buildArgsData(QByteArray &data, const QVariantList &args)
{
QDataStream stream(&data,
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QIODevice::WriteOnly
#else
QDataStream::WriteOnly
#endif
);
const int argsCount = args.count();
if (argsCount > commandMaxArgs)
return false;
stream << qint8(argsCount);
for (const auto &arg : args) {
stream << arg;
}
return true;
}
bool ControlWorker::parseArgsData(const QByteArray &data, QVariantList &args)
{
QDataStream stream(data);
qint8 argsCount;
stream >> argsCount;
if (argsCount > commandMaxArgs)
return false;
while (--argsCount >= 0) {
QVariant arg;
stream >> arg;
args.append(arg);
}
return true;
}
QVariantList ControlWorker::buildArgs(const QStringList &list)
{
QVariantList args;

View File

@ -22,7 +22,10 @@ public:
void setupForAsync();
bool postCommand(Control::Command command, const QVariantList &args);
bool sendCommand(Control::Command command, Control::RpcObject rpcObj, int methodIndex,
const QVariantList &args);
bool waitForSent(int msecs = 1000) const;
static QVariantList buildArgs(const QStringList &list);
@ -39,20 +42,41 @@ private:
void clearRequest();
bool readRequest();
void writeDataHeader(Control::Command command, int dataSize);
bool readDataHeader(Control::Command &command, int &dataSize);
void writeData(const QByteArray &data);
QByteArray readData(int dataSize);
static bool buildArgsData(QByteArray &data, const QVariantList &args);
static bool parseArgsData(const QByteArray &data, QVariantList &args);
bool readRequestHeader();
private:
struct DataHeader
{
DataHeader(Control::Command command = Control::CommandNone,
Control::RpcObject rpcObj = Control::Rpc_None, qint16 methodIndex = 0,
qint32 dataSize = 0) :
m_command(command), m_rpcObj(rpcObj), m_methodIndex(methodIndex), m_dataSize(dataSize)
{
}
Control::Command command() const { return m_command; }
Control::RpcObject rpcObj() const { return m_rpcObj; }
qint16 methodIndex() const { return m_methodIndex; }
qint32 dataSize() const { return m_dataSize; }
void clear()
{
m_command = Control::CommandNone;
m_rpcObj = Control::Rpc_None;
m_methodIndex = 0;
m_dataSize = 0;
}
private:
Control::Command m_command;
Control::RpcObject m_rpcObj;
qint16 m_methodIndex;
quint32 m_dataSize;
};
bool m_isServiceClient = false;
Control::Command m_requestCommand = Control::CommandNone;
int m_requestDataSize = 0;
DataHeader m_request;
QByteArray m_requestData;
QLocalSocket *m_socket = nullptr;

View File

@ -4,6 +4,7 @@
#include "../fortmanager.h"
#include "../rpc/rpcmanager.h"
#include "../util/metaclassutil.h"
AppInfoManagerRpc::AppInfoManagerRpc(
const QString &filePath, FortManager *fortManager, QObject *parent) :
@ -18,7 +19,8 @@ RpcManager *AppInfoManagerRpc::rpcManager() const
void AppInfoManagerRpc::lookupAppInfo(const QString &appPath)
{
rpcManager()->invokeOnServer(RpcManager::Obj_AppInfoManager, "lookupAppInfo", { appPath });
static const int methodIndex = MetaClassUtil::indexOfMethod(&AppInfoManager::lookupAppInfo);
rpcManager()->invokeOnServer(Control::Rpc_AppInfoManager, methodIndex, { appPath });
}
void AppInfoManagerRpc::updateAppAccessTime(const QString & /*appPath*/) { }

View File

@ -5,7 +5,12 @@
#include "../fortmanager.h"
#include "../fortsettings.h"
#include "../rpc/appinfomanagerrpc.h"
#include "../rpc/confmanagerrpc.h"
#include "../rpc/drivermanagerrpc.h"
#include "../rpc/quotamanagerrpc.h"
#include "../rpc/statmanagerrpc.h"
#include "../rpc/taskmanagerrpc.h"
#include "../util/metaclassutil.h"
RpcManager::RpcManager(FortManager *fortManager, QObject *parent) :
QObject(parent), m_fortManager(fortManager)
@ -39,36 +44,63 @@ void RpcManager::setupServerSignals()
void RpcManager::setupAppInfoManagerSignals()
{
constexpr qint8 rpcObj = Obj_AppInfoManager;
constexpr Control::RpcObject rpcObj = Control::Rpc_AppInfoManager;
auto o = fortManager()->appInfoManager();
connect(o, &AppInfoManager::lookupFinished, this,
[&](const QString &appPath, const AppInfo & /*appInfo*/) {
invokeOnClients(rpcObj, "checkLookupFinished", { appPath });
static const int methodIndex =
MetaClassUtil::indexOfMethod(&AppInfoManager::checkLookupFinished);
invokeOnClients(rpcObj, methodIndex, { appPath });
});
}
void RpcManager::setupQuotaManagerSignals()
{
constexpr qint8 rpcObj = Obj_QuotaManager;
constexpr Control::RpcObject rpcObj = Control::Rpc_QuotaManager;
auto o = fortManager()->quotaManager();
connect(o, &QuotaManager::alert, this,
[&](qint8 alertType) { invokeOnClients(rpcObj, "alert", { alertType }); });
connect(o, &QuotaManager::alert, this, [&](qint8 alertType) {
static const int methodIndex = MetaClassUtil::indexOfSignal(&QuotaManager::alert);
invokeOnClients(rpcObj, methodIndex, { alertType });
});
}
void RpcManager::invokeOnServer(qint8 rpcObj, const char *member, const QVariantList &args)
void RpcManager::invokeOnServer(
Control::RpcObject rpcObj, int methodIndex, const QVariantList &args)
{
// TODO: Send RPC to Server
m_client->sendCommand(Control::CommandRpc, rpcObj, methodIndex, args);
}
void RpcManager::invokeOnClients(qint8 rpcObj, const char *member, const QVariantList &args)
void RpcManager::invokeOnClients(
Control::RpcObject rpcObj, int methodIndex, const QVariantList &args)
{
const auto clients = controlManager()->clients();
for (ControlWorker *w : clients) {
if (!w->isServiceClient())
continue;
// TODO: Send RPC to Client
w->sendCommand(Control::CommandRpc, rpcObj, methodIndex, args);
}
}
QObject *RpcManager::getRpcObject(Control::RpcObject rpcObj) const
{
switch (rpcObj) {
case Control::Rpc_AppInfoManager:
return fortManager()->appInfoManager();
case Control::Rpc_ConfManager:
return fortManager()->confManager();
case Control::Rpc_DriverManager:
return fortManager()->driverManager();
case Control::Rpc_QuotaManager:
return fortManager()->quotaManager();
case Control::Rpc_StatManager:
return fortManager()->statManager();
case Control::Rpc_TaskManager:
return fortManager()->taskManager();
default:
Q_UNREACHABLE();
return nullptr;
}
}

View File

@ -3,7 +3,10 @@
#include <QObject>
#include "../control/control.h"
class ControlManager;
class ControlWorker;
class FortManager;
class FortSettings;
@ -12,15 +15,6 @@ class RpcManager : public QObject
Q_OBJECT
public:
enum RpcObject : qint8 {
Obj_AppInfoManager = 1,
Obj_ConfManager,
Obj_DriverManager,
Obj_QuotaManager,
Obj_StatManager,
Obj_TaskManager,
};
explicit RpcManager(FortManager *fortManager, QObject *parent = nullptr);
FortManager *fortManager() const { return m_fortManager; }
@ -29,17 +23,21 @@ public:
void initialize();
void invokeOnServer(qint8 rpcObj, const char *member, const QVariantList &args);
void invokeOnServer(Control::RpcObject rpcObj, int methodIndex, const QVariantList &args);
private:
void setupServerSignals();
void setupAppInfoManagerSignals();
void setupQuotaManagerSignals();
void invokeOnClients(qint8 rpcObj, const char *member, const QVariantList &args);
void invokeOnClients(Control::RpcObject rpcObj, int methodIndex, const QVariantList &args);
QObject *getRpcObject(Control::RpcObject rpcObj) const;
private:
FortManager *m_fortManager = nullptr;
ControlWorker *m_client = nullptr;
};
#endif // RPCMANAGER_H

View File

@ -0,0 +1,9 @@
#include "metaclassutil.h"
int MetaClassUtil::getIndexOfMethod(const QMetaObject &metaObj, void **method)
{
int methodIndex = -1;
void *metaArgs[] = { &methodIndex, reinterpret_cast<void **>(&method) };
metaObj.static_metacall(QMetaObject::IndexOfMethod, 0, metaArgs);
return methodIndex;
}

View File

@ -0,0 +1,28 @@
#ifndef METACLASSUTIL_H
#define METACLASSUTIL_H
#include <QMetaMethod>
class MetaClassUtil
{
public:
template<typename Func>
static int indexOfSignal(Func signal)
{
const QMetaMethod method = QMetaMethod::fromSignal(signal);
return method.methodIndex();
}
template<typename Func>
static int indexOfMethod(Func method)
{
using FuncType = QtPrivate::FunctionPointer<Func>;
return getIndexOfMethod(
FuncType::Object::staticMetaObject, reinterpret_cast<void **>(&method));
}
private:
static int getIndexOfMethod(const QMetaObject &metaObj, void **method);
};
#endif // METACLASSUTIL_H