diff --git a/src/ui/FortFirewallUI.pro b/src/ui/FortFirewallUI.pro index dd153cfa..2dcd1bb7 100644 --- a/src/ui/FortFirewallUI.pro +++ b/src/ui/FortFirewallUI.pro @@ -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 \ diff --git a/src/ui/control/control.h b/src/ui/control/control.h index e451dbf5..aad79335 100644 --- a/src/ui/control/control.h +++ b/src/ui/control/control.h @@ -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, }; } diff --git a/src/ui/control/controlmanager.cpp b/src/ui/control/controlmanager.cpp index 54312031..d40ca2c5 100644 --- a/src/ui/control/controlmanager.cpp +++ b/src/ui/control/controlmanager.cpp @@ -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() diff --git a/src/ui/control/controlworker.cpp b/src/ui/control/controlworker.cpp index 08872e1b..ed720d8b 100644 --- a/src/ui/control/controlworker.cpp +++ b/src/ui/control/controlworker.cpp @@ -9,20 +9,57 @@ constexpr int commandMaxArgs = 7; constexpr int commandArgMaxSize = 4 * 1024; constexpr int dataMaxSize = 4 * 1024 * 1024; -struct DataHeader +template +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(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(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(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; diff --git a/src/ui/control/controlworker.h b/src/ui/control/controlworker.h index 18f5a185..cd101283 100644 --- a/src/ui/control/controlworker.h +++ b/src/ui/control/controlworker.h @@ -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; diff --git a/src/ui/rpc/appinfomanagerrpc.cpp b/src/ui/rpc/appinfomanagerrpc.cpp index 9398f93b..415cacc0 100644 --- a/src/ui/rpc/appinfomanagerrpc.cpp +++ b/src/ui/rpc/appinfomanagerrpc.cpp @@ -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*/) { } diff --git a/src/ui/rpc/rpcmanager.cpp b/src/ui/rpc/rpcmanager.cpp index 27f14a71..a43724c0 100644 --- a/src/ui/rpc/rpcmanager.cpp +++ b/src/ui/rpc/rpcmanager.cpp @@ -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; } } diff --git a/src/ui/rpc/rpcmanager.h b/src/ui/rpc/rpcmanager.h index 9d2165ad..9423aeb1 100644 --- a/src/ui/rpc/rpcmanager.h +++ b/src/ui/rpc/rpcmanager.h @@ -3,7 +3,10 @@ #include +#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 diff --git a/src/ui/util/metaclassutil.cpp b/src/ui/util/metaclassutil.cpp new file mode 100644 index 00000000..47fcd3fb --- /dev/null +++ b/src/ui/util/metaclassutil.cpp @@ -0,0 +1,9 @@ +#include "metaclassutil.h" + +int MetaClassUtil::getIndexOfMethod(const QMetaObject &metaObj, void **method) +{ + int methodIndex = -1; + void *metaArgs[] = { &methodIndex, reinterpret_cast(&method) }; + metaObj.static_metacall(QMetaObject::IndexOfMethod, 0, metaArgs); + return methodIndex; +} diff --git a/src/ui/util/metaclassutil.h b/src/ui/util/metaclassutil.h new file mode 100644 index 00000000..190e133c --- /dev/null +++ b/src/ui/util/metaclassutil.h @@ -0,0 +1,28 @@ +#ifndef METACLASSUTIL_H +#define METACLASSUTIL_H + +#include + +class MetaClassUtil +{ +public: + template + static int indexOfSignal(Func signal) + { + const QMetaMethod method = QMetaMethod::fromSignal(signal); + return method.methodIndex(); + } + + template + static int indexOfMethod(Func method) + { + using FuncType = QtPrivate::FunctionPointer; + return getIndexOfMethod( + FuncType::Object::staticMetaObject, reinterpret_cast(&method)); + } + +private: + static int getIndexOfMethod(const QMetaObject &metaObj, void **method); +}; + +#endif // METACLASSUTIL_H