X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsignalproxy.cpp;h=caafb65ba9aa41dbb16453c0257ae888d0147db3;hp=9e47dd38bcf72816adb2850d301a6825f0a25369;hb=db00831bca59a012242d1ad5fac52a20c6cd2956;hpb=c1cf157116de7fc3da96203aa6f03c38c7ebb650 diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 9e47dd38..caafb65b 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -18,6 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include #include #include @@ -49,130 +50,6 @@ public: Peer* peer; }; -// ================================================== -// SignalRelay -// ================================================== -class SignalProxy::SignalRelay : public QObject -{ - /* Q_OBJECT is not necessary or even allowed, because we implement - qt_metacall ourselves (and don't use any other features of the meta - object system) - */ -public: - SignalRelay(SignalProxy* parent) - : QObject(parent) - , _proxy(parent) - {} - inline SignalProxy* proxy() const { return _proxy; } - - int qt_metacall(QMetaObject::Call _c, int _id, void** _a) override; - - void attachSignal(QObject* sender, int signalId, const QByteArray& funcName); - void detachSignal(QObject* sender, int signalId = -1); - -private: - struct Signal - { - QObject* sender{nullptr}; - int signalId{-1}; - QByteArray signature; - Signal(QObject* sender, int sigId, QByteArray signature) - : sender(sender) - , signalId(sigId) - , signature(std::move(signature)) - {} - Signal() = default; - }; - - SignalProxy* _proxy; - QHash _slots; -}; - -void SignalProxy::SignalRelay::attachSignal(QObject* sender, int signalId, const QByteArray& funcName) -{ - // we ride without safetybelts here... all checking for valid method etc pp has to be done by the caller - // all connected methodIds are offset by the standard methodCount of QObject - int slotId; - for (int i = 0;; i++) { - if (!_slots.contains(i)) { - slotId = i; - break; - } - } - - QByteArray fn; - if (!funcName.isEmpty()) { - fn = QMetaObject::normalizedSignature(funcName); - } - else { - fn = SIGNAL(fakeMethodSignature()); - fn = fn.replace("fakeMethodSignature()", sender->metaObject()->method(signalId).methodSignature()); - } - - _slots[slotId] = Signal(sender, signalId, fn); - - QMetaObject::connect(sender, signalId, this, QObject::staticMetaObject.methodCount() + slotId); -} - -void SignalProxy::SignalRelay::detachSignal(QObject* sender, int signalId) -{ - QHash::iterator slotIter = _slots.begin(); - while (slotIter != _slots.end()) { - if (slotIter->sender == sender && (signalId == -1 || slotIter->signalId == signalId)) { - slotIter = _slots.erase(slotIter); - if (signalId != -1) - break; - } - else { - ++slotIter; - } - } -} - -int SignalProxy::SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void** _a) -{ - _id = QObject::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - - if (_c == QMetaObject::InvokeMetaMethod) { - if (_slots.contains(_id)) { - QObject* caller = sender(); - - SignalProxy::ExtendedMetaObject* eMeta = proxy()->extendedMetaObject(caller->metaObject()); - Q_ASSERT(eMeta); - - const Signal& signal = _slots[_id]; - - QVariantList params; - - const QList& argTypes = eMeta->argTypes(signal.signalId); - for (int i = 0; i < argTypes.size(); i++) { - if (argTypes[i] == 0) { - qWarning() << "SignalRelay::qt_metacall(): received invalid data for argument number" << i << "of signal" - << QString("%1::%2") - .arg(caller->metaObject()->className()) - .arg(caller->metaObject()->method(signal.signalId).methodSignature().constData()); - qWarning() << " - make sure all your data types are known by the Qt MetaSystem"; - return _id; - } - params << QVariant(argTypes[i], _a[i + 1]); - } - - if (proxy()->_restrictMessageTarget) { - for (auto peer : proxy()->_restrictedTargets) { - if (peer != nullptr) - proxy()->dispatch(peer, RpcCall(signal.signature, params)); - } - } - else - proxy()->dispatch(RpcCall(signal.signature, params)); - } - _id -= _slots.count(); - } - return _id; -} - // ================================================== // SignalProxy // ================================================== @@ -211,6 +88,9 @@ SignalProxy::~SignalProxy() removeAllPeers(); + // Ensure that we don't try to clean up while destroying ourselves + disconnect(this, &QObject::destroyed, this, &SignalProxy::detachSlotObjects); + _current = nullptr; } @@ -237,7 +117,6 @@ void SignalProxy::init() { _heartBeatInterval = 0; _maxHeartBeatCount = 0; - _signalRelay = new SignalRelay(this); setHeartBeatInterval(30); setMaxHeartBeatCount(2); _secure = false; @@ -249,7 +128,7 @@ void SignalProxy::initServer() {} void SignalProxy::initClient() { - attachSlot("__objectRenamed__", this, SLOT(objectRenamed(QByteArray, QString, QString))); + attachSlot("__objectRenamed__", this, &SignalProxy::objectRenamed); } void SignalProxy::setHeartBeatInterval(int secs) @@ -372,9 +251,12 @@ void SignalProxy::renameObject(const SyncableObject* obj, const QString& newname void SignalProxy::objectRenamed(const QByteArray& classname, const QString& newname, const QString& oldname) { - if (_syncSlave.contains(classname) && _syncSlave[classname].contains(oldname) && oldname != newname) { - SyncableObject* obj = _syncSlave[classname][newname] = _syncSlave[classname].take(oldname); - requestInit(obj); + if (newname != oldname) { + if (_syncSlave.contains(classname) && _syncSlave[classname].contains(oldname)) { + SyncableObject* obj = _syncSlave[classname][newname] = _syncSlave[classname].take(oldname); + obj->setObjectName(newname); + requestInit(obj); + } } } @@ -402,41 +284,24 @@ SignalProxy::ExtendedMetaObject* SignalProxy::createExtendedMetaObject(const QMe return _extendedMetaObjects[meta]; } -bool SignalProxy::attachSignal(QObject* sender, const char* signal, const QByteArray& sigName) +void SignalProxy::attachSlotObject(const QByteArray& signalName, std::unique_ptr slotObject) { - const QMetaObject* meta = sender->metaObject(); - QByteArray sig(meta->normalizedSignature(signal).mid(1)); - int methodId = meta->indexOfMethod(sig.constData()); - if (methodId == -1 || meta->method(methodId).methodType() != QMetaMethod::Signal) { - qWarning() << "SignalProxy::attachSignal(): No such signal" << signal; - return false; - } - - createExtendedMetaObject(meta); - _signalRelay->attachSignal(sender, methodId, sigName); + // Remove all attached slots related to the context upon its destruction + connect(slotObject->context(), &QObject::destroyed, this, &SignalProxy::detachSlotObjects, Qt::UniqueConnection); - disconnect(sender, &QObject::destroyed, this, &SignalProxy::detachObject); - connect(sender, &QObject::destroyed, this, &SignalProxy::detachObject); - return true; + _attachedSlots.emplace(QMetaObject::normalizedSignature(signalName.constData()), std::move(slotObject)); } -bool SignalProxy::attachSlot(const QByteArray& sigName, QObject* recv, const char* slot) +void SignalProxy::detachSlotObjects(const QObject *context) { - const QMetaObject* meta = recv->metaObject(); - int methodId = meta->indexOfMethod(meta->normalizedSignature(slot).mid(1)); - if (methodId == -1 || meta->method(methodId).methodType() == QMetaMethod::Method) { - qWarning() << "SignalProxy::attachSlot(): No such slot" << slot; - return false; + for (auto&& it = _attachedSlots.begin(); it != _attachedSlots.end(); ) { + if (it->second->context() == context) { + it = _attachedSlots.erase(it); + } + else { + ++it; + } } - - createExtendedMetaObject(meta); - - QByteArray funcName = QMetaObject::normalizedSignature(sigName.constData()); - _attachedSlots.insert(funcName, qMakePair(recv, methodId)); - - disconnect(recv, &QObject::destroyed, this, &SignalProxy::detachObject); - connect(recv, &QObject::destroyed, this, &SignalProxy::detachObject); - return true; } void SignalProxy::synchronize(SyncableObject* obj) @@ -461,32 +326,6 @@ void SignalProxy::synchronize(SyncableObject* obj) obj->synchronize(this); } -void SignalProxy::detachObject(QObject* obj) -{ - // Don't try to connect SignalProxy from itself on shutdown - if (obj != this) { - detachSignals(obj); - detachSlots(obj); - } -} - -void SignalProxy::detachSignals(QObject* sender) -{ - _signalRelay->detachSignal(sender); -} - -void SignalProxy::detachSlots(QObject* receiver) -{ - SlotHash::iterator slotIter = _attachedSlots.begin(); - while (slotIter != _attachedSlots.end()) { - if (slotIter.value().first == receiver) { - slotIter = _attachedSlots.erase(slotIter); - } - else - ++slotIter; - } -} - void SignalProxy::stopSynchronize(SyncableObject* obj) { // we can't use a className here, since it might be effed up, if we receive the call as a result of a decon @@ -502,6 +341,19 @@ void SignalProxy::stopSynchronize(SyncableObject* obj) obj->stopSynchronize(this); } +void SignalProxy::dispatchSignal(QByteArray sigName, QVariantList params) +{ + RpcCall rpcCall{std::move(sigName), std::move(params)}; + if (_restrictMessageTarget) { + for (auto&& peer : _restrictedTargets) { + dispatch(peer, rpcCall); + } + } + else { + dispatch(rpcCall); + } +} + template void SignalProxy::dispatch(const T& protoMessage) { @@ -573,6 +425,18 @@ void SignalProxy::handle(Peer* peer, const SyncMessage& syncMessage) invokeSlot(receiver, eMeta->updatedRemotelyId()); } +void SignalProxy::handle(Peer* peer, const RpcCall& rpcCall) +{ + Q_UNUSED(peer) + + auto range = _attachedSlots.equal_range(rpcCall.signalName); + std::for_each(range.first, range.second, [&rpcCall](const auto& p) { + if (!p.second->invoke(rpcCall.params)) { + qWarning() << "Could not invoke slot for remote signal" << rpcCall.signalName; + } + }); +} + void SignalProxy::handle(Peer* peer, const InitRequest& initRequest) { if (!_syncSlave.contains(initRequest.className)) { @@ -610,22 +474,6 @@ void SignalProxy::handle(Peer* peer, const InitData& initData) setInitData(obj, initData.initData); } -void SignalProxy::handle(Peer* peer, const RpcCall& rpcCall) -{ - QObject* receiver; - int methodId; - SlotHash::const_iterator slot = _attachedSlots.constFind(rpcCall.slotName); - while (slot != _attachedSlots.constEnd() && slot.key() == rpcCall.slotName) { - receiver = (*slot).first; - methodId = (*slot).second; - if (!invokeSlot(receiver, methodId, rpcCall.params, peer)) { - ExtendedMetaObject* eMeta = extendedMetaObject(receiver); - qWarning("SignalProxy::handleSignal(): invokeMethod for \"%s\" failed ", eMeta->methodName(methodId).constData()); - } - ++slot; - } -} - bool SignalProxy::invokeSlot(QObject* receiver, int methodId, const QVariantList& params, QVariant& returnValue, Peer* peer) { ExtendedMetaObject* eMeta = extendedMetaObject(receiver); @@ -786,7 +634,7 @@ void SignalProxy::dumpProxyStats() qDebug() << this; qDebug() << " Proxy Mode:" << mode; - qDebug() << " attached Slots:" << _attachedSlots.count(); + qDebug() << " attached Slots:" << _attachedSlots.size(); qDebug() << " number of synced Slaves:" << slaveCount; qDebug() << "number of Classes cached:" << _extendedMetaObjects.count(); } @@ -865,9 +713,19 @@ void SignalProxy::setTargetPeer(Peer* targetPeer) _targetPeer = targetPeer; } -// ================================================== -// ExtendedMetaObject -// ================================================== +// ---- SlotObjectBase --------------------------------------------------------------------------------------------------------------------- + +SignalProxy::SlotObjectBase::SlotObjectBase(const QObject* context) + : _context{context} +{} + +const QObject* SignalProxy::SlotObjectBase::context() const +{ + return _context; +} + +// ---- ExtendedMetaObject ---------------------------------------------------------------------------------------------------------------- + SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject* meta, bool checkConflicts) : _meta(meta) , _updatedRemotelyId(_meta->indexOfSignal("updatedRemotely()"))