1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
23 #include "common-export.h"
26 #include <initializer_list>
39 class COMMON_EXPORT SignalProxy : public QObject
54 RemovePeerEvent = QEvent::User
57 SignalProxy(QObject* parent);
58 SignalProxy(ProxyMode mode, QObject* parent);
59 ~SignalProxy() override;
61 void setProxyMode(ProxyMode mode);
62 inline ProxyMode proxyMode() const { return _proxyMode; }
64 void setHeartBeatInterval(int secs);
65 inline int heartBeatInterval() const { return _heartBeatInterval; }
66 void setMaxHeartBeatCount(int max);
67 inline int maxHeartBeatCount() const { return _maxHeartBeatCount; }
69 bool addPeer(Peer* peer);
71 bool attachSignal(QObject* sender, const char* signal, const QByteArray& sigName = QByteArray());
72 bool attachSlot(const QByteArray& sigName, QObject* recv, const char* slot);
74 void synchronize(SyncableObject* obj);
75 void stopSynchronize(SyncableObject* obj);
77 class ExtendedMetaObject;
78 ExtendedMetaObject* extendedMetaObject(const QMetaObject* meta) const;
79 ExtendedMetaObject* createExtendedMetaObject(const QMetaObject* meta, bool checkConflicts = false);
80 inline ExtendedMetaObject* extendedMetaObject(const QObject* obj) const { return extendedMetaObject(metaObject(obj)); }
81 inline ExtendedMetaObject* createExtendedMetaObject(const QObject* obj, bool checkConflicts = false)
83 return createExtendedMetaObject(metaObject(obj), checkConflicts);
86 bool isSecure() const { return _secure; }
87 void dumpProxyStats();
88 void dumpSyncMap(SyncableObject* object);
90 static SignalProxy* current();
94 * This method allows to send a signal only to a limited set of peers
95 * @param peers A list of peers that should receive it
96 * @param closure Code you want to execute within of that restricted environment
98 void restrictTargetPeers(QSet<Peer*> peers, std::function<void()> closure);
99 void restrictTargetPeers(Peer* peer, std::function<void()> closure)
103 restrictTargetPeers(set, std::move(closure));
106 // A better version, but only implemented on Qt5 if Initializer Lists exist
107 #ifdef Q_COMPILER_INITIALIZER_LISTS
108 void restrictTargetPeers(std::initializer_list<Peer*> peers, std::function<void()> closure)
110 restrictTargetPeers(QSet<Peer*>(peers), std::move(closure));
115 inline int peerCount() const { return _peerMap.size(); }
116 QVariantList peerData();
118 Peer* peerById(int peerId);
121 * @return If handling a signal, the Peer from which the current signal originates
124 void setSourcePeer(Peer* sourcePeer);
127 * @return If sending a signal, the Peer to which the current signal is directed
130 void setTargetPeer(Peer* targetPeer);
133 void detachObject(QObject* obj);
134 void detachSignals(QObject* sender);
135 void detachSlots(QObject* receiver);
138 void customEvent(QEvent* event) override;
139 void sync_call__(const SyncableObject* obj, ProxyMode modeType, const char* funcname, va_list ap);
140 void renameObject(const SyncableObject* obj, const QString& newname, const QString& oldname);
143 void removePeerBySender();
144 void objectRenamed(const QByteArray& classname, const QString& newname, const QString& oldname);
145 void updateSecureState();
148 void peerRemoved(Peer* peer);
151 void objectInitialized(SyncableObject*);
152 void heartBeatIntervalChanged(int secs);
153 void maxHeartBeatCountChanged(int max);
154 void lagUpdated(int lag);
155 void secureStateChanged(bool);
159 class PeerMessageEvent;
165 static const QMetaObject* metaObject(const QObject* obj);
167 void removePeer(Peer* peer);
168 void removeAllPeers();
170 int nextPeerId() { return _lastPeerId++; }
173 void dispatch(const T& protoMessage);
175 void dispatch(Peer* peer, const T& protoMessage);
177 void handle(Peer* peer, const Protocol::SyncMessage& syncMessage);
178 void handle(Peer* peer, const Protocol::RpcCall& rpcCall);
179 void handle(Peer* peer, const Protocol::InitRequest& initRequest);
180 void handle(Peer* peer, const Protocol::InitData& initData);
183 void handle(Peer*, T)
188 bool invokeSlot(QObject* receiver, int methodId, const QVariantList& params, QVariant& returnValue, Peer* peer = nullptr);
189 bool invokeSlot(QObject* receiver, int methodId, const QVariantList& params = QVariantList(), Peer* peer = nullptr);
191 void requestInit(SyncableObject* obj);
192 QVariantMap initData(SyncableObject* obj) const;
193 void setInitData(SyncableObject* obj, const QVariantMap& properties);
195 static void disconnectDevice(QIODevice* dev, const QString& reason = QString());
197 QHash<int, Peer*> _peerMap;
199 // containg a list of argtypes for fast access
200 QHash<const QMetaObject*, ExtendedMetaObject*> _extendedMetaObjects;
202 // SignalRelay for all manually attached signals
203 SignalRelay* _signalRelay;
205 // RPC function -> (object, slot ID)
206 using MethodId = QPair<QObject*, int>;
207 using SlotHash = QMultiHash<QByteArray, MethodId>;
208 SlotHash _attachedSlots;
211 using ObjectId = QHash<QString, SyncableObject*>;
212 QHash<QByteArray, ObjectId> _syncSlave;
214 ProxyMode _proxyMode;
215 int _heartBeatInterval;
216 int _maxHeartBeatCount;
218 bool _secure; // determines if all connections are in a secured state (using ssl or internal connections)
222 QSet<Peer*> _restrictedTargets;
223 bool _restrictMessageTarget = false;
225 Peer* _sourcePeer = nullptr;
226 Peer* _targetPeer = nullptr;
228 friend class SignalRelay;
229 friend class SyncableObject;
233 // ==================================================
234 // ExtendedMetaObject
235 // ==================================================
236 class SignalProxy::ExtendedMetaObject
238 class MethodDescriptor
241 MethodDescriptor(const QMetaMethod& method);
242 MethodDescriptor() = default;
244 inline const QByteArray& methodName() const { return _methodName; }
245 inline const QList<int>& argTypes() const { return _argTypes; }
246 inline int returnType() const { return _returnType; }
247 inline int minArgCount() const { return _minArgCount; }
248 inline SignalProxy::ProxyMode receiverMode() const { return _receiverMode; }
251 QByteArray _methodName;
252 QList<int> _argTypes;
254 int _minArgCount{-1};
255 SignalProxy::ProxyMode _receiverMode{
256 SignalProxy::Client}; // Only acceptable as a Sync Call if the receiving SignalProxy is in this mode.
260 ExtendedMetaObject(const QMetaObject* meta, bool checkConflicts);
262 inline const QByteArray& methodName(int methodId) { return methodDescriptor(methodId).methodName(); }
263 inline const QList<int>& argTypes(int methodId) { return methodDescriptor(methodId).argTypes(); }
264 inline int returnType(int methodId) { return methodDescriptor(methodId).returnType(); }
265 inline int minArgCount(int methodId) { return methodDescriptor(methodId).minArgCount(); }
266 inline SignalProxy::ProxyMode receiverMode(int methodId) { return methodDescriptor(methodId).receiverMode(); }
268 inline int methodId(const QByteArray& methodName) { return _methodIds.contains(methodName) ? _methodIds[methodName] : -1; }
270 inline int updatedRemotelyId() { return _updatedRemotelyId; }
272 inline const QHash<QByteArray, int>& slotMap() { return _methodIds; }
273 const QHash<int, int>& receiveMap();
275 const QMetaObject* metaObject() const { return _meta; }
277 static QByteArray methodName(const QMetaMethod& method);
278 static QString methodBaseName(const QMetaMethod& method);
281 const MethodDescriptor& methodDescriptor(int methodId);
283 const QMetaObject* _meta;
284 int _updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster
286 QHash<int, MethodDescriptor> _methods;
287 QHash<QByteArray, int> _methodIds;
288 QHash<int, int> _receiveMap; // if slot x is called then hand over the result to slot y