1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 by the Quassel Project * |
3 | * devel@quassel-irc.org * |
4 | * * |
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. * |
9 | * * |
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. * |
14 | * * |
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 | ***************************************************************************/ |
20 | |
21 | #ifndef SIGNALPROXY_H |
22 | #define SIGNALPROXY_H |
23 | |
24 | #include <QEvent> |
25 | #include <QSet> |
26 | |
27 | #include "protocol.h" |
28 | |
29 | struct QMetaObject; |
30 | class QIODevice; |
31 | |
32 | class Peer; |
33 | class SyncableObject; |
34 | |
35 | class SignalProxy : public QObject |
36 | { |
37 | Q_OBJECT |
38 | |
39 | class SignalRelay; |
40 | |
41 | public: |
42 | enum ProxyMode { |
43 | Server, |
44 | Client |
45 | }; |
46 | |
47 | enum EventType { |
48 | RemovePeerEvent = QEvent::User |
49 | }; |
50 | |
51 | SignalProxy(QObject *parent); |
52 | SignalProxy(ProxyMode mode, QObject *parent); |
53 | virtual ~SignalProxy(); |
54 | |
55 | void setProxyMode(ProxyMode mode); |
56 | inline ProxyMode proxyMode() const { return _proxyMode; } |
57 | |
58 | void setHeartBeatInterval(int secs); |
59 | inline int heartBeatInterval() const { return _heartBeatInterval; } |
60 | void setMaxHeartBeatCount(int max); |
61 | inline int maxHeartBeatCount() const { return _maxHeartBeatCount; } |
62 | |
63 | bool addPeer(Peer *peer); |
64 | |
65 | bool attachSignal(QObject *sender, const char *signal, const QByteArray &sigName = QByteArray()); |
66 | bool attachSlot(const QByteArray &sigName, QObject *recv, const char *slot); |
67 | |
68 | void synchronize(SyncableObject *obj); |
69 | void stopSynchronize(SyncableObject *obj); |
70 | |
71 | class ExtendedMetaObject; |
72 | ExtendedMetaObject *extendedMetaObject(const QMetaObject *meta) const; |
73 | ExtendedMetaObject *createExtendedMetaObject(const QMetaObject *meta, bool checkConflicts = false); |
74 | inline ExtendedMetaObject *extendedMetaObject(const QObject *obj) const { return extendedMetaObject(metaObject(obj)); } |
75 | inline ExtendedMetaObject *createExtendedMetaObject(const QObject *obj, bool checkConflicts = false) { return createExtendedMetaObject(metaObject(obj), checkConflicts); } |
76 | |
77 | bool isSecure() const { return _secure; } |
78 | void dumpProxyStats(); |
79 | void dumpSyncMap(SyncableObject *object); |
80 | inline int peerCount() const { return _peers.size(); } |
81 | |
82 | public slots: |
83 | void detachObject(QObject *obj); |
84 | void detachSignals(QObject *sender); |
85 | void detachSlots(QObject *receiver); |
86 | |
87 | protected: |
88 | void customEvent(QEvent *event); |
89 | void sync_call__(const SyncableObject *obj, ProxyMode modeType, const char *funcname, va_list ap); |
90 | void renameObject(const SyncableObject *obj, const QString &newname, const QString &oldname); |
91 | |
92 | private slots: |
93 | void removePeerBySender(); |
94 | void objectRenamed(const QByteArray &classname, const QString &newname, const QString &oldname); |
95 | void updateSecureState(); |
96 | |
97 | signals: |
98 | void peerRemoved(Peer *peer); |
99 | void connected(); |
100 | void disconnected(); |
101 | void objectInitialized(SyncableObject *); |
102 | void heartBeatIntervalChanged(int secs); |
103 | void maxHeartBeatCountChanged(int max); |
104 | void lagUpdated(int lag); |
105 | void secureStateChanged(bool); |
106 | |
107 | private: |
108 | template<class T> |
109 | class PeerMessageEvent; |
110 | |
111 | void init(); |
112 | void initServer(); |
113 | void initClient(); |
114 | |
115 | static const QMetaObject *metaObject(const QObject *obj); |
116 | |
117 | void removePeer(Peer *peer); |
118 | void removeAllPeers(); |
119 | |
120 | template<class T> |
121 | void dispatch(const T &protoMessage); |
122 | template<class T> |
123 | void dispatch(Peer *peer, const T &protoMessage); |
124 | |
125 | void handle(Peer *peer, const Protocol::SyncMessage &syncMessage); |
126 | void handle(Peer *peer, const Protocol::RpcCall &rpcCall); |
127 | void handle(Peer *peer, const Protocol::InitRequest &initRequest); |
128 | void handle(Peer *peer, const Protocol::InitData &initData); |
129 | |
130 | template<class T> |
131 | void handle(Peer *, T) { Q_ASSERT(0); } |
132 | |
133 | bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue, Peer *peer = 0); |
134 | bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms = QVariantList(), Peer *peer = 0); |
135 | |
136 | void requestInit(SyncableObject *obj); |
137 | QVariantMap initData(SyncableObject *obj) const; |
138 | void setInitData(SyncableObject *obj, const QVariantMap &properties); |
139 | |
140 | static void disconnectDevice(QIODevice *dev, const QString &reason = QString()); |
141 | |
142 | QSet<Peer *> _peers; |
143 | |
144 | // containg a list of argtypes for fast access |
145 | QHash<const QMetaObject *, ExtendedMetaObject *> _extendedMetaObjects; |
146 | |
147 | // SignalRelay for all manually attached signals |
148 | SignalRelay *_signalRelay; |
149 | |
150 | // RPC function -> (object, slot ID) |
151 | typedef QPair<QObject *, int> MethodId; |
152 | typedef QMultiHash<QByteArray, MethodId> SlotHash; |
153 | SlotHash _attachedSlots; |
154 | |
155 | // slaves for sync |
156 | typedef QHash<QString, SyncableObject *> ObjectId; |
157 | QHash<QByteArray, ObjectId> _syncSlave; |
158 | |
159 | ProxyMode _proxyMode; |
160 | int _heartBeatInterval; |
161 | int _maxHeartBeatCount; |
162 | |
163 | bool _secure; // determines if all connections are in a secured state (using ssl or internal connections) |
164 | |
165 | friend class SignalRelay; |
166 | friend class SyncableObject; |
167 | friend class Peer; |
168 | }; |
169 | |
170 | |
171 | // ================================================== |
172 | // ExtendedMetaObject |
173 | // ================================================== |
174 | class SignalProxy::ExtendedMetaObject |
175 | { |
176 | class MethodDescriptor |
177 | { |
178 | public: |
179 | MethodDescriptor(const QMetaMethod &method); |
180 | MethodDescriptor() : _returnType(-1), _minArgCount(-1), _receiverMode(SignalProxy::Client) {} |
181 | |
182 | inline const QByteArray &methodName() const { return _methodName; } |
183 | inline const QList<int> &argTypes() const { return _argTypes; } |
184 | inline int returnType() const { return _returnType; } |
185 | inline int minArgCount() const { return _minArgCount; } |
186 | inline SignalProxy::ProxyMode receiverMode() const { return _receiverMode; } |
187 | |
188 | private: |
189 | QByteArray _methodName; |
190 | QList<int> _argTypes; |
191 | int _returnType; |
192 | int _minArgCount; |
193 | SignalProxy::ProxyMode _receiverMode; // Only acceptable as a Sync Call if the receiving SignalProxy is in this mode. |
194 | }; |
195 | |
196 | |
197 | public: |
198 | ExtendedMetaObject(const QMetaObject *meta, bool checkConflicts); |
199 | |
200 | inline const QByteArray &methodName(int methodId) { return methodDescriptor(methodId).methodName(); } |
201 | inline const QList<int> &argTypes(int methodId) { return methodDescriptor(methodId).argTypes(); } |
202 | inline int returnType(int methodId) { return methodDescriptor(methodId).returnType(); } |
203 | inline int minArgCount(int methodId) { return methodDescriptor(methodId).minArgCount(); } |
204 | inline SignalProxy::ProxyMode receiverMode(int methodId) { return methodDescriptor(methodId).receiverMode(); } |
205 | |
206 | inline int methodId(const QByteArray &methodName) { return _methodIds.contains(methodName) ? _methodIds[methodName] : -1; } |
207 | |
208 | inline int updatedRemotelyId() { return _updatedRemotelyId; } |
209 | |
210 | inline const QHash<QByteArray, int> &slotMap() { return _methodIds; } |
211 | const QHash<int, int> &receiveMap(); |
212 | |
213 | const QMetaObject *metaObject() const { return _meta; } |
214 | |
215 | static QByteArray methodName(const QMetaMethod &method); |
216 | static QString methodBaseName(const QMetaMethod &method); |
217 | |
218 | private: |
219 | const MethodDescriptor &methodDescriptor(int methodId); |
220 | |
221 | const QMetaObject *_meta; |
222 | int _updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster |
223 | |
224 | QHash<int, MethodDescriptor> _methods; |
225 | QHash<QByteArray, int> _methodIds; |
226 | QHash<int, int> _receiveMap; // if slot x is called then hand over the result to slot y |
227 | }; |
228 | |
229 | #endif |
230 | |