forked from quickshell/quickshell
io/ipchandler: add prop get
This commit is contained in:
parent
9417d6fa57
commit
4f2610dece
|
@ -1,9 +1,12 @@
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
#include <cstring>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <qcolor.h>
|
#include <qcolor.h>
|
||||||
#include <qmetatype.h>
|
#include <qmetatype.h>
|
||||||
#include <qobjectdefs.h>
|
#include <qobjectdefs.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
#include <qvariant.h>
|
||||||
|
|
||||||
namespace qs::io::ipc {
|
namespace qs::io::ipc {
|
||||||
|
|
||||||
|
@ -14,6 +17,12 @@ const BoolIpcType BoolIpcType::INSTANCE {};
|
||||||
const DoubleIpcType DoubleIpcType::INSTANCE {};
|
const DoubleIpcType DoubleIpcType::INSTANCE {};
|
||||||
const ColorIpcType ColorIpcType::INSTANCE {};
|
const ColorIpcType ColorIpcType::INSTANCE {};
|
||||||
|
|
||||||
|
void* IpcType::copyStorage(const void* data) const {
|
||||||
|
auto* storage = this->createStorage();
|
||||||
|
memcpy(storage, data, this->size());
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
const IpcType* IpcType::ipcType(const QMetaType& metaType) {
|
const IpcType* IpcType::ipcType(const QMetaType& metaType) {
|
||||||
if (metaType.id() == QMetaType::Void) return &VoidIpcType::INSTANCE;
|
if (metaType.id() == QMetaType::Void) return &VoidIpcType::INSTANCE;
|
||||||
if (metaType.id() == QMetaType::QString) return &StringIpcType::INSTANCE;
|
if (metaType.id() == QMetaType::QString) return &StringIpcType::INSTANCE;
|
||||||
|
@ -70,12 +79,18 @@ void IpcTypeSlot::replace(void* value) {
|
||||||
this->storage = value;
|
this->storage = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IpcTypeSlot::replace(const QVariant& value) {
|
||||||
|
this->replace(this->mType->copyStorage(value.constData()));
|
||||||
|
}
|
||||||
|
|
||||||
const char* VoidIpcType::name() const { return "void"; }
|
const char* VoidIpcType::name() const { return "void"; }
|
||||||
const char* VoidIpcType::genericArgumentName() const { return "void"; }
|
const char* VoidIpcType::genericArgumentName() const { return "void"; }
|
||||||
|
qsizetype VoidIpcType::size() const { return 0; }
|
||||||
|
|
||||||
// string
|
// string
|
||||||
const char* StringIpcType::name() const { return "string"; }
|
const char* StringIpcType::name() const { return "string"; }
|
||||||
const char* StringIpcType::genericArgumentName() const { return "QString"; }
|
const char* StringIpcType::genericArgumentName() const { return "QString"; }
|
||||||
|
qsizetype StringIpcType::size() const { return sizeof(QString); }
|
||||||
void* StringIpcType::fromString(const QString& string) const { return new QString(string); }
|
void* StringIpcType::fromString(const QString& string) const { return new QString(string); }
|
||||||
QString StringIpcType::toString(void* slot) const { return *static_cast<QString*>(slot); }
|
QString StringIpcType::toString(void* slot) const { return *static_cast<QString*>(slot); }
|
||||||
void* StringIpcType::createStorage() const { return new QString(); }
|
void* StringIpcType::createStorage() const { return new QString(); }
|
||||||
|
@ -84,6 +99,7 @@ void StringIpcType::destroyStorage(void* slot) const { delete static_cast<QStrin
|
||||||
// int
|
// int
|
||||||
const char* IntIpcType::name() const { return "int"; }
|
const char* IntIpcType::name() const { return "int"; }
|
||||||
const char* IntIpcType::genericArgumentName() const { return "int"; }
|
const char* IntIpcType::genericArgumentName() const { return "int"; }
|
||||||
|
qsizetype IntIpcType::size() const { return sizeof(int); }
|
||||||
|
|
||||||
void* IntIpcType::fromString(const QString& string) const {
|
void* IntIpcType::fromString(const QString& string) const {
|
||||||
auto ok = false;
|
auto ok = false;
|
||||||
|
@ -100,6 +116,7 @@ void IntIpcType::destroyStorage(void* slot) const { delete static_cast<int*>(slo
|
||||||
// bool
|
// bool
|
||||||
const char* BoolIpcType::name() const { return "bool"; }
|
const char* BoolIpcType::name() const { return "bool"; }
|
||||||
const char* BoolIpcType::genericArgumentName() const { return "bool"; }
|
const char* BoolIpcType::genericArgumentName() const { return "bool"; }
|
||||||
|
qsizetype BoolIpcType::size() const { return sizeof(bool); }
|
||||||
|
|
||||||
void* BoolIpcType::fromString(const QString& string) const {
|
void* BoolIpcType::fromString(const QString& string) const {
|
||||||
if (string == "true") return new bool(true);
|
if (string == "true") return new bool(true);
|
||||||
|
@ -121,6 +138,7 @@ void BoolIpcType::destroyStorage(void* slot) const { delete static_cast<bool*>(s
|
||||||
// double
|
// double
|
||||||
const char* DoubleIpcType::name() const { return "real"; }
|
const char* DoubleIpcType::name() const { return "real"; }
|
||||||
const char* DoubleIpcType::genericArgumentName() const { return "double"; }
|
const char* DoubleIpcType::genericArgumentName() const { return "double"; }
|
||||||
|
qsizetype DoubleIpcType::size() const { return sizeof(double); }
|
||||||
|
|
||||||
void* DoubleIpcType::fromString(const QString& string) const {
|
void* DoubleIpcType::fromString(const QString& string) const {
|
||||||
auto ok = false;
|
auto ok = false;
|
||||||
|
@ -139,6 +157,7 @@ void DoubleIpcType::destroyStorage(void* slot) const { delete static_cast<double
|
||||||
// color
|
// color
|
||||||
const char* ColorIpcType::name() const { return "color"; }
|
const char* ColorIpcType::name() const { return "color"; }
|
||||||
const char* ColorIpcType::genericArgumentName() const { return "QColor"; }
|
const char* ColorIpcType::genericArgumentName() const { return "QColor"; }
|
||||||
|
qsizetype ColorIpcType::size() const { return sizeof(QColor); }
|
||||||
|
|
||||||
void* ColorIpcType::fromString(const QString& string) const {
|
void* ColorIpcType::fromString(const QString& string) const {
|
||||||
auto color = QColor::fromString(string);
|
auto color = QColor::fromString(string);
|
||||||
|
@ -167,6 +186,10 @@ QString WireFunctionDefinition::toString() const {
|
||||||
return "function " % this->name % '(' % paramString % "): " % this->returnType;
|
return "function " % this->name % '(' % paramString % "): " % this->returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString WirePropertyDefinition::toString() const {
|
||||||
|
return "property " % this->name % ": " % this->type;
|
||||||
|
}
|
||||||
|
|
||||||
QString WireTargetDefinition::toString() const {
|
QString WireTargetDefinition::toString() const {
|
||||||
QString accum = "target " % this->name;
|
QString accum = "target " % this->name;
|
||||||
|
|
||||||
|
@ -174,6 +197,10 @@ QString WireTargetDefinition::toString() const {
|
||||||
accum += "\n " % func.toString();
|
accum += "\n " % func.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& prop: this->properties) {
|
||||||
|
accum += "\n " % prop.toString();
|
||||||
|
}
|
||||||
|
|
||||||
return accum;
|
return accum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qobjectdefs.h>
|
#include <qobjectdefs.h>
|
||||||
#include <qtclasshelpermacros.h>
|
#include <qtclasshelpermacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
#include "../ipc/ipc.hpp"
|
#include "../ipc/ipc.hpp"
|
||||||
|
|
||||||
|
@ -21,10 +22,12 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] virtual const char* name() const = 0;
|
[[nodiscard]] virtual const char* name() const = 0;
|
||||||
[[nodiscard]] virtual const char* genericArgumentName() const = 0;
|
[[nodiscard]] virtual const char* genericArgumentName() const = 0;
|
||||||
|
[[nodiscard]] virtual qsizetype size() const = 0;
|
||||||
[[nodiscard]] virtual void* fromString(const QString& /*string*/) const { return nullptr; }
|
[[nodiscard]] virtual void* fromString(const QString& /*string*/) const { return nullptr; }
|
||||||
[[nodiscard]] virtual QString toString(void* /*slot*/) const { return ""; }
|
[[nodiscard]] virtual QString toString(void* /*slot*/) const { return ""; }
|
||||||
[[nodiscard]] virtual void* createStorage() const { return nullptr; }
|
[[nodiscard]] virtual void* createStorage() const { return nullptr; }
|
||||||
virtual void destroyStorage(void* /*slot*/) const {}
|
virtual void destroyStorage(void* /*slot*/) const {}
|
||||||
|
void* copyStorage(const void* data) const;
|
||||||
|
|
||||||
static const IpcType* ipcType(const QMetaType& metaType);
|
static const IpcType* ipcType(const QMetaType& metaType);
|
||||||
};
|
};
|
||||||
|
@ -43,6 +46,7 @@ public:
|
||||||
[[nodiscard]] QGenericReturnArgument asGenericReturnArgument();
|
[[nodiscard]] QGenericReturnArgument asGenericReturnArgument();
|
||||||
|
|
||||||
void replace(void* value);
|
void replace(void* value);
|
||||||
|
void replace(const QVariant& value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const IpcType* mType = nullptr;
|
const IpcType* mType = nullptr;
|
||||||
|
@ -53,6 +57,7 @@ class VoidIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
|
|
||||||
static const VoidIpcType INSTANCE;
|
static const VoidIpcType INSTANCE;
|
||||||
};
|
};
|
||||||
|
@ -61,6 +66,7 @@ class StringIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||||
[[nodiscard]] QString toString(void* slot) const override;
|
[[nodiscard]] QString toString(void* slot) const override;
|
||||||
[[nodiscard]] void* createStorage() const override;
|
[[nodiscard]] void* createStorage() const override;
|
||||||
|
@ -73,6 +79,7 @@ class IntIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||||
[[nodiscard]] QString toString(void* slot) const override;
|
[[nodiscard]] QString toString(void* slot) const override;
|
||||||
[[nodiscard]] void* createStorage() const override;
|
[[nodiscard]] void* createStorage() const override;
|
||||||
|
@ -85,6 +92,7 @@ class BoolIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||||
[[nodiscard]] QString toString(void* slot) const override;
|
[[nodiscard]] QString toString(void* slot) const override;
|
||||||
[[nodiscard]] void* createStorage() const override;
|
[[nodiscard]] void* createStorage() const override;
|
||||||
|
@ -97,6 +105,7 @@ class DoubleIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||||
[[nodiscard]] QString toString(void* slot) const override;
|
[[nodiscard]] QString toString(void* slot) const override;
|
||||||
[[nodiscard]] void* createStorage() const override;
|
[[nodiscard]] void* createStorage() const override;
|
||||||
|
@ -109,6 +118,7 @@ class ColorIpcType: public IpcType {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] const char* name() const override;
|
[[nodiscard]] const char* name() const override;
|
||||||
[[nodiscard]] const char* genericArgumentName() const override;
|
[[nodiscard]] const char* genericArgumentName() const override;
|
||||||
|
[[nodiscard]] qsizetype size() const override;
|
||||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||||
[[nodiscard]] QString toString(void* slot) const override;
|
[[nodiscard]] QString toString(void* slot) const override;
|
||||||
[[nodiscard]] void* createStorage() const override;
|
[[nodiscard]] void* createStorage() const override;
|
||||||
|
@ -127,13 +137,23 @@ struct WireFunctionDefinition {
|
||||||
|
|
||||||
DEFINE_SIMPLE_DATASTREAM_OPS(WireFunctionDefinition, data.name, data.returnType, data.arguments);
|
DEFINE_SIMPLE_DATASTREAM_OPS(WireFunctionDefinition, data.name, data.returnType, data.arguments);
|
||||||
|
|
||||||
struct WireTargetDefinition {
|
struct WirePropertyDefinition {
|
||||||
QString name;
|
QString name;
|
||||||
QVector<WireFunctionDefinition> functions;
|
QString type;
|
||||||
|
|
||||||
[[nodiscard]] QString toString() const;
|
[[nodiscard]] QString toString() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SIMPLE_DATASTREAM_OPS(WireTargetDefinition, data.name, data.functions);
|
DEFINE_SIMPLE_DATASTREAM_OPS(WirePropertyDefinition, data.name, data.type);
|
||||||
|
|
||||||
|
struct WireTargetDefinition {
|
||||||
|
QString name;
|
||||||
|
QVector<WireFunctionDefinition> functions;
|
||||||
|
QVector<WirePropertyDefinition> properties;
|
||||||
|
|
||||||
|
[[nodiscard]] QString toString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_DATASTREAM_OPS(WireTargetDefinition, data.name, data.functions, data.properties);
|
||||||
|
|
||||||
} // namespace qs::io::ipc
|
} // namespace qs::io::ipc
|
||||||
|
|
|
@ -21,16 +21,17 @@ namespace qs::io::ipc::comm {
|
||||||
|
|
||||||
struct NoCurrentGeneration: std::monostate {};
|
struct NoCurrentGeneration: std::monostate {};
|
||||||
struct TargetNotFound: std::monostate {};
|
struct TargetNotFound: std::monostate {};
|
||||||
struct FunctionNotFound: std::monostate {};
|
struct EntryNotFound: std::monostate {};
|
||||||
|
|
||||||
using QueryResponse = std::variant<
|
using QueryResponse = std::variant<
|
||||||
std::monostate,
|
std::monostate,
|
||||||
NoCurrentGeneration,
|
NoCurrentGeneration,
|
||||||
TargetNotFound,
|
TargetNotFound,
|
||||||
FunctionNotFound,
|
EntryNotFound,
|
||||||
QVector<WireTargetDefinition>,
|
QVector<WireTargetDefinition>,
|
||||||
WireTargetDefinition,
|
WireTargetDefinition,
|
||||||
WireFunctionDefinition>;
|
WireFunctionDefinition,
|
||||||
|
WirePropertyDefinition>;
|
||||||
|
|
||||||
void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||||
auto resp = conn->responseStream<QueryResponse>();
|
auto resp = conn->responseStream<QueryResponse>();
|
||||||
|
@ -44,16 +45,24 @@ void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||||
auto* handler = registry->findHandler(this->target);
|
auto* handler = registry->findHandler(this->target);
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
if (this->function.isEmpty()) {
|
if (this->name.isEmpty()) {
|
||||||
resp << handler->wireDef();
|
resp << handler->wireDef();
|
||||||
} else {
|
} else {
|
||||||
auto* func = handler->findFunction(this->function);
|
auto* func = handler->findFunction(this->name);
|
||||||
|
|
||||||
if (func) {
|
if (func) {
|
||||||
resp << func->wireDef();
|
resp << func->wireDef();
|
||||||
} else {
|
return;
|
||||||
resp << FunctionNotFound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* prop = handler->findProperty(this->name);
|
||||||
|
|
||||||
|
if (prop) {
|
||||||
|
resp << prop->wireDef();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resp << EntryNotFound();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resp << TargetNotFound();
|
resp << TargetNotFound();
|
||||||
|
@ -64,8 +73,8 @@ void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int queryMetadata(IpcClient* client, const QString& target, const QString& function) {
|
int queryMetadata(IpcClient* client, const QString& target, const QString& name) {
|
||||||
client->sendMessage(IpcCommand(QueryMetadataCommand {.target = target, .function = function}));
|
client->sendMessage(IpcCommand(QueryMetadataCommand {.target = target, .name = name}));
|
||||||
|
|
||||||
QueryResponse slot;
|
QueryResponse slot;
|
||||||
if (!client->waitForResponse(slot)) return -1;
|
if (!client->waitForResponse(slot)) return -1;
|
||||||
|
@ -82,9 +91,11 @@ int queryMetadata(IpcClient* client, const QString& target, const QString& funct
|
||||||
qCInfo(logBare).noquote() << std::get<WireTargetDefinition>(slot).toString();
|
qCInfo(logBare).noquote() << std::get<WireTargetDefinition>(slot).toString();
|
||||||
} else if (std::holds_alternative<WireFunctionDefinition>(slot)) {
|
} else if (std::holds_alternative<WireFunctionDefinition>(slot)) {
|
||||||
qCInfo(logBare).noquote() << std::get<WireFunctionDefinition>(slot).toString();
|
qCInfo(logBare).noquote() << std::get<WireFunctionDefinition>(slot).toString();
|
||||||
|
} else if (std::holds_alternative<WirePropertyDefinition>(slot)) {
|
||||||
|
qCInfo(logBare).noquote() << std::get<WirePropertyDefinition>(slot).toString();
|
||||||
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||||
qCCritical(logBare) << "Target not found.";
|
qCCritical(logBare) << "Target not found.";
|
||||||
} else if (std::holds_alternative<FunctionNotFound>(slot)) {
|
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||||
qCCritical(logBare) << "Function not found.";
|
qCCritical(logBare) << "Function not found.";
|
||||||
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||||
qCCritical(logBare) << "Not ready to accept queries yet.";
|
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||||
|
@ -119,7 +130,7 @@ using StringCallResponse = std::variant<
|
||||||
std::monostate,
|
std::monostate,
|
||||||
NoCurrentGeneration,
|
NoCurrentGeneration,
|
||||||
TargetNotFound,
|
TargetNotFound,
|
||||||
FunctionNotFound,
|
EntryNotFound,
|
||||||
ArgParseFailed,
|
ArgParseFailed,
|
||||||
Completed>;
|
Completed>;
|
||||||
|
|
||||||
|
@ -137,7 +148,7 @@ void StringCallCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||||
|
|
||||||
auto* func = handler->findFunction(this->function);
|
auto* func = handler->findFunction(this->function);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
resp << FunctionNotFound();
|
resp << EntryNotFound();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +234,7 @@ int callFunction(
|
||||||
qCCritical(logBare).noquote() << "Function definition:" << error.definition.toString();
|
qCCritical(logBare).noquote() << "Function definition:" << error.definition.toString();
|
||||||
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||||
qCCritical(logBare) << "Target not found.";
|
qCCritical(logBare) << "Target not found.";
|
||||||
} else if (std::holds_alternative<FunctionNotFound>(slot)) {
|
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||||
qCCritical(logBare) << "Function not found.";
|
qCCritical(logBare) << "Function not found.";
|
||||||
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||||
qCCritical(logBare) << "Not ready to accept queries yet.";
|
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||||
|
@ -233,4 +244,74 @@ int callFunction(
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PropertyValue {
|
||||||
|
QString value;
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_DATASTREAM_OPS(PropertyValue, data.value);
|
||||||
|
|
||||||
|
using StringPropReadResponse =
|
||||||
|
std::variant<std::monostate, NoCurrentGeneration, TargetNotFound, EntryNotFound, PropertyValue>;
|
||||||
|
|
||||||
|
void StringPropReadCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||||
|
auto resp = conn->responseStream<StringPropReadResponse>();
|
||||||
|
|
||||||
|
if (auto* generation = EngineGeneration::currentGeneration()) {
|
||||||
|
auto* registry = IpcHandlerRegistry::forGeneration(generation);
|
||||||
|
|
||||||
|
auto* handler = registry->findHandler(this->target);
|
||||||
|
if (!handler) {
|
||||||
|
resp << TargetNotFound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* prop = handler->findProperty(this->property);
|
||||||
|
if (!prop) {
|
||||||
|
resp << EntryNotFound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto slot = IpcTypeSlot(prop->type);
|
||||||
|
prop->read(handler, slot);
|
||||||
|
|
||||||
|
resp << PropertyValue {
|
||||||
|
.value = slot.type()->toString(slot.get()),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
conn->respond(StringCallResponse(NoCurrentGeneration()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getProperty(IpcClient* client, const QString& target, const QString& property) {
|
||||||
|
if (target.isEmpty()) {
|
||||||
|
qCCritical(logBare) << "Target required to send message.";
|
||||||
|
return -1;
|
||||||
|
} else if (property.isEmpty()) {
|
||||||
|
qCCritical(logBare) << "Property required to send message.";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->sendMessage(IpcCommand(StringPropReadCommand {.target = target, .property = property}));
|
||||||
|
|
||||||
|
StringPropReadResponse slot;
|
||||||
|
if (!client->waitForResponse(slot)) return -1;
|
||||||
|
|
||||||
|
if (std::holds_alternative<PropertyValue>(slot)) {
|
||||||
|
auto& result = std::get<PropertyValue>(slot);
|
||||||
|
QTextStream(stdout) << result.value << Qt::endl;
|
||||||
|
return 0;
|
||||||
|
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||||
|
qCCritical(logBare) << "Target not found.";
|
||||||
|
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||||
|
qCCritical(logBare) << "Property not found.";
|
||||||
|
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||||
|
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||||
|
} else {
|
||||||
|
qCCritical(logIpc) << "Received invalid IPC response from" << client;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace qs::io::ipc::comm
|
} // namespace qs::io::ipc::comm
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qflags.h>
|
#include <qflags.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
#include "../ipc/ipc.hpp"
|
#include "../ipc/ipc.hpp"
|
||||||
|
|
||||||
|
@ -9,12 +10,12 @@ namespace qs::io::ipc::comm {
|
||||||
|
|
||||||
struct QueryMetadataCommand {
|
struct QueryMetadataCommand {
|
||||||
QString target;
|
QString target;
|
||||||
QString function;
|
QString name;
|
||||||
|
|
||||||
void exec(qs::ipc::IpcServerConnection* conn) const;
|
void exec(qs::ipc::IpcServerConnection* conn) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SIMPLE_DATASTREAM_OPS(QueryMetadataCommand, data.target, data.function);
|
DEFINE_SIMPLE_DATASTREAM_OPS(QueryMetadataCommand, data.target, data.name);
|
||||||
|
|
||||||
struct StringCallCommand {
|
struct StringCallCommand {
|
||||||
QString target;
|
QString target;
|
||||||
|
@ -27,7 +28,7 @@ struct StringCallCommand {
|
||||||
DEFINE_SIMPLE_DATASTREAM_OPS(StringCallCommand, data.target, data.function, data.arguments);
|
DEFINE_SIMPLE_DATASTREAM_OPS(StringCallCommand, data.target, data.function, data.arguments);
|
||||||
|
|
||||||
void handleMsg(qs::ipc::IpcServerConnection* conn);
|
void handleMsg(qs::ipc::IpcServerConnection* conn);
|
||||||
int queryMetadata(qs::ipc::IpcClient* client, const QString& target, const QString& function);
|
int queryMetadata(qs::ipc::IpcClient* client, const QString& target, const QString& name);
|
||||||
|
|
||||||
int callFunction(
|
int callFunction(
|
||||||
qs::ipc::IpcClient* client,
|
qs::ipc::IpcClient* client,
|
||||||
|
@ -36,4 +37,15 @@ int callFunction(
|
||||||
const QVector<QString>& arguments
|
const QVector<QString>& arguments
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct StringPropReadCommand {
|
||||||
|
QString target;
|
||||||
|
QString property;
|
||||||
|
|
||||||
|
void exec(qs::ipc::IpcServerConnection* conn) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_DATASTREAM_OPS(StringPropReadCommand, data.target, data.property);
|
||||||
|
|
||||||
|
int getProperty(qs::ipc::IpcClient* client, const QString& target, const QString& property);
|
||||||
|
|
||||||
} // namespace qs::io::ipc::comm
|
} // namespace qs::io::ipc::comm
|
||||||
|
|
|
@ -107,6 +107,32 @@ WireFunctionDefinition IpcFunction::wireDef() const {
|
||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IpcProperty::resolve(QString& error) {
|
||||||
|
this->type = IpcType::ipcType(this->property.metaType());
|
||||||
|
|
||||||
|
if (!this->type) {
|
||||||
|
error = QString("Type %1 cannot be used across IPC.").arg(this->property.metaType().name());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcProperty::read(QObject* target, IpcTypeSlot& slot) const {
|
||||||
|
slot.replace(this->property.read(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IpcProperty::toString() const {
|
||||||
|
return QString("property ") % this->property.name() % ": " % this->type->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
WirePropertyDefinition IpcProperty::wireDef() const {
|
||||||
|
WirePropertyDefinition wire;
|
||||||
|
wire.name = this->property.name();
|
||||||
|
wire.type = this->type->name();
|
||||||
|
return wire;
|
||||||
|
}
|
||||||
|
|
||||||
IpcCallStorage::IpcCallStorage(const IpcFunction& function): returnSlot(function.returnType) {
|
IpcCallStorage::IpcCallStorage(const IpcFunction& function): returnSlot(function.returnType) {
|
||||||
for (const auto& arg: function.argumentTypes) {
|
for (const auto& arg: function.argumentTypes) {
|
||||||
this->argumentSlots.emplace_back(arg);
|
this->argumentSlots.emplace_back(arg);
|
||||||
|
@ -153,6 +179,21 @@ void IpcHandler::onPostReload() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto i = smeta.propertyCount(); i != meta->propertyCount(); i++) {
|
||||||
|
const auto& property = meta->property(i);
|
||||||
|
if (!property.isReadable() || !property.hasNotifySignal()) continue;
|
||||||
|
|
||||||
|
auto ipcProp = IpcProperty(property);
|
||||||
|
QString error;
|
||||||
|
|
||||||
|
if (!ipcProp.resolve(error)) {
|
||||||
|
qmlWarning(this).nospace().noquote()
|
||||||
|
<< "Error parsing property \"" << property.name() << "\": " << error;
|
||||||
|
} else {
|
||||||
|
this->propertyMap.insert(property.name(), ipcProp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->complete = true;
|
this->complete = true;
|
||||||
this->updateRegistration();
|
this->updateRegistration();
|
||||||
|
|
||||||
|
@ -270,6 +311,10 @@ WireTargetDefinition IpcHandler::wireDef() const {
|
||||||
wire.functions += func.wireDef();
|
wire.functions += func.wireDef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& prop: this->propertyMap.values()) {
|
||||||
|
wire.properties += prop.wireDef();
|
||||||
|
}
|
||||||
|
|
||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +352,13 @@ IpcFunction* IpcHandler::findFunction(const QString& name) {
|
||||||
else return &*itr;
|
else return &*itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IpcProperty* IpcHandler::findProperty(const QString& name) {
|
||||||
|
auto itr = this->propertyMap.find(name);
|
||||||
|
|
||||||
|
if (itr == this->propertyMap.end()) return nullptr;
|
||||||
|
else return &*itr;
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler* IpcHandlerRegistry::findHandler(const QString& target) {
|
IpcHandler* IpcHandlerRegistry::findHandler(const QString& target) {
|
||||||
return this->handlers.value(target);
|
return this->handlers.value(target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,14 +53,28 @@ private:
|
||||||
friend class IpcFunction;
|
friend class IpcFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IpcProperty {
|
||||||
|
public:
|
||||||
|
explicit IpcProperty(QMetaProperty property): property(property) {}
|
||||||
|
|
||||||
|
bool resolve(QString& error);
|
||||||
|
void read(QObject* target, IpcTypeSlot& slot) const;
|
||||||
|
|
||||||
|
[[nodiscard]] QString toString() const;
|
||||||
|
[[nodiscard]] WirePropertyDefinition wireDef() const;
|
||||||
|
|
||||||
|
QMetaProperty property;
|
||||||
|
const IpcType* type = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class IpcHandlerRegistry;
|
class IpcHandlerRegistry;
|
||||||
|
|
||||||
///! Handler for IPC message calls.
|
///! Handler for IPC message calls.
|
||||||
/// Each IpcHandler is registered into a per-instance map by its unique @@target.
|
/// Each IpcHandler is registered into a per-instance map by its unique @@target.
|
||||||
/// Functions defined on the IpcHandler can be called by `qs msg`.
|
/// Functions and properties defined on the IpcHandler can be accessed via `qs ipc`.
|
||||||
///
|
///
|
||||||
/// #### Handler Functions
|
/// #### Handler Functions
|
||||||
/// IPC handler functions can be called by `qs msg` as long as they have at most 10
|
/// IPC handler functions can be called by `qs ipc call` as long as they have at most 10
|
||||||
/// arguments, and all argument types along with the return type are listed below.
|
/// arguments, and all argument types along with the return type are listed below.
|
||||||
///
|
///
|
||||||
/// **Argument and return types must be explicitly specified or they will not
|
/// **Argument and return types must be explicitly specified or they will not
|
||||||
|
@ -112,9 +126,9 @@ class IpcHandlerRegistry;
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// The list of registered targets can be inspected using `qs msg -s`.
|
/// The list of registered targets can be inspected using `qs ipc show`.
|
||||||
/// ```sh
|
/// ```sh
|
||||||
/// $ qs msg -s
|
/// $ qs ipc show
|
||||||
/// target rect
|
/// target rect
|
||||||
/// function setColor(color: color): void
|
/// function setColor(color: color): void
|
||||||
/// function getColor(): color
|
/// function getColor(): color
|
||||||
|
@ -124,18 +138,22 @@ class IpcHandlerRegistry;
|
||||||
/// function getRadius(): int
|
/// function getRadius(): int
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// and then invoked using `qs msg`.
|
/// and then invoked using `qs ipc call`.
|
||||||
/// ```sh
|
/// ```sh
|
||||||
/// $ qs msg rect setColor orange
|
/// $ qs ipc call rect setColor orange
|
||||||
/// $ qs msg rect setAngle 40.5
|
/// $ qs ipc call rect setAngle 40.5
|
||||||
/// $ qs msg rect setRadius 30
|
/// $ qs ipc call rect setRadius 30
|
||||||
/// $ qs msg rect getColor
|
/// $ qs ipc call rect getColor
|
||||||
/// #ffffa500
|
/// #ffffa500
|
||||||
/// $ qs msg rect getAngle
|
/// $ qs ipc call rect getAngle
|
||||||
/// 40.5
|
/// 40.5
|
||||||
/// $ qs msg rect getRadius
|
/// $ qs ipc call rect getRadius
|
||||||
/// 30
|
/// 30
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// #### Properties
|
||||||
|
/// Properties of an IpcHanlder can be read using `qs ipc prop get` as long as they are
|
||||||
|
/// of an IPC compatible type. See the table above for compatible types.
|
||||||
class IpcHandler
|
class IpcHandler
|
||||||
: public QObject
|
: public QObject
|
||||||
, public PostReloadHook {
|
, public PostReloadHook {
|
||||||
|
@ -162,12 +180,16 @@ public:
|
||||||
|
|
||||||
QString listMembers(qsizetype indent);
|
QString listMembers(qsizetype indent);
|
||||||
[[nodiscard]] IpcFunction* findFunction(const QString& name);
|
[[nodiscard]] IpcFunction* findFunction(const QString& name);
|
||||||
|
[[nodiscard]] IpcProperty* findProperty(const QString& name);
|
||||||
[[nodiscard]] WireTargetDefinition wireDef() const;
|
[[nodiscard]] WireTargetDefinition wireDef() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enabledChanged();
|
void enabledChanged();
|
||||||
void targetChanged();
|
void targetChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
//void handleIpcPropertyChange();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateRegistration(bool destroying = false);
|
void updateRegistration(bool destroying = false);
|
||||||
|
|
||||||
|
@ -183,6 +205,7 @@ private:
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
|
|
||||||
QHash<QString, IpcFunction> functionMap;
|
QHash<QString, IpcFunction> functionMap;
|
||||||
|
QHash<QString, IpcProperty> propertyMap;
|
||||||
|
|
||||||
friend class IpcHandlerRegistry;
|
friend class IpcHandlerRegistry;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@ using IpcCommand = std::variant<
|
||||||
std::monostate,
|
std::monostate,
|
||||||
IpcKillCommand,
|
IpcKillCommand,
|
||||||
qs::io::ipc::comm::QueryMetadataCommand,
|
qs::io::ipc::comm::QueryMetadataCommand,
|
||||||
qs::io::ipc::comm::StringCallCommand>;
|
qs::io::ipc::comm::StringCallCommand,
|
||||||
|
qs::io::ipc::comm::StringPropReadCommand>;
|
||||||
|
|
||||||
} // namespace qs::ipc
|
} // namespace qs::ipc
|
||||||
|
|
|
@ -293,6 +293,8 @@ int ipcCommand(CommandState& cmd) {
|
||||||
return IpcClient::connect(instance.instance.instanceId, [&](IpcClient& client) {
|
return IpcClient::connect(instance.instance.instanceId, [&](IpcClient& client) {
|
||||||
if (*cmd.ipc.show || cmd.ipc.showOld) {
|
if (*cmd.ipc.show || cmd.ipc.showOld) {
|
||||||
return qs::io::ipc::comm::queryMetadata(&client, *cmd.ipc.target, *cmd.ipc.name);
|
return qs::io::ipc::comm::queryMetadata(&client, *cmd.ipc.target, *cmd.ipc.name);
|
||||||
|
} else if (*cmd.ipc.getprop) {
|
||||||
|
return qs::io::ipc::comm::getProperty(&client, *cmd.ipc.target, *cmd.ipc.name);
|
||||||
} else {
|
} else {
|
||||||
QVector<QString> arguments;
|
QVector<QString> arguments;
|
||||||
for (auto& arg: cmd.ipc.arguments) {
|
for (auto& arg: cmd.ipc.arguments) {
|
||||||
|
|
|
@ -71,6 +71,7 @@ struct CommandState {
|
||||||
CLI::App* ipc = nullptr;
|
CLI::App* ipc = nullptr;
|
||||||
CLI::App* show = nullptr;
|
CLI::App* show = nullptr;
|
||||||
CLI::App* call = nullptr;
|
CLI::App* call = nullptr;
|
||||||
|
CLI::App* getprop = nullptr;
|
||||||
bool showOld = false;
|
bool showOld = false;
|
||||||
QStringOption target;
|
QStringOption target;
|
||||||
QStringOption name;
|
QStringOption name;
|
||||||
|
|
|
@ -194,6 +194,18 @@ int parseCommand(int argc, char** argv, CommandState& state) {
|
||||||
->description("Arguments to the called function.")
|
->description("Arguments to the called function.")
|
||||||
->allow_extra_args();
|
->allow_extra_args();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* prop =
|
||||||
|
sub->add_subcommand("prop", "Manipulate IpcHandler properties.")->require_subcommand();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* get = prop->add_subcommand("get", "Read the value of a property.");
|
||||||
|
state.ipc.getprop = get;
|
||||||
|
get->add_option("target", state.ipc.target, "The target to read the property of.");
|
||||||
|
get->add_option("property", state.ipc.name)->description("The property to read.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue