1 | // Copyright (C) 2017 Ford Motor Company |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qremoteobjectregistry.h" |
5 | #include "qremoteobjectreplica_p.h" |
6 | |
7 | #include <private/qobject_p.h> |
8 | #include <QtCore/qset.h> |
9 | #include <QtCore/qdatastream.h> |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | class QRemoteObjectRegistryPrivate : public QObjectPrivate |
14 | { |
15 | Q_DECLARE_PUBLIC(QRemoteObjectRegistry) |
16 | |
17 | QRemoteObjectSourceLocations sourceLocationsActualCalculation() const |
18 | { |
19 | return q_func()->propAsVariant(i: 0).value<QRemoteObjectSourceLocations>(); |
20 | } |
21 | Q_OBJECT_COMPUTED_PROPERTY(QRemoteObjectRegistryPrivate, QRemoteObjectSourceLocations, |
22 | sourceLocations, |
23 | &QRemoteObjectRegistryPrivate::sourceLocationsActualCalculation) |
24 | QRemoteObjectSourceLocations hostedSources; |
25 | }; |
26 | |
27 | /*! |
28 | \class QRemoteObjectRegistry |
29 | \inmodule QtRemoteObjects |
30 | \brief A class holding information about \l {Source} objects available on the Qt Remote Objects network. |
31 | |
32 | The Registry is a special Source/Replica pair held by a \l |
33 | {QRemoteObjectNode} {node} itself. It knows about all other \l {Source}s |
34 | available on the network, and simplifies the process of connecting to other |
35 | \l {QRemoteObjectNode} {node}s. |
36 | */ |
37 | QRemoteObjectRegistry::QRemoteObjectRegistry(QObject *parent) |
38 | : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent) |
39 | { |
40 | connect(sender: this, signal: &QRemoteObjectRegistry::stateChanged, context: this, slot: &QRemoteObjectRegistry::pushToRegistryIfNeeded); |
41 | } |
42 | |
43 | QRemoteObjectRegistry::QRemoteObjectRegistry(QRemoteObjectNode *node, const QString &name, QObject *parent) |
44 | : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent) |
45 | { |
46 | connect(sender: this, signal: &QRemoteObjectRegistry::stateChanged, context: this, slot: &QRemoteObjectRegistry::pushToRegistryIfNeeded); |
47 | initializeNode(node, name); |
48 | } |
49 | |
50 | /*! |
51 | \fn void QRemoteObjectRegistry::remoteObjectAdded(const QRemoteObjectSourceLocation &entry) |
52 | |
53 | This signal is emitted whenever a new source location is added to the registry. |
54 | |
55 | \a entry is a QRemoteObjectSourceLocation, a typedef for |
56 | QPair<QString, QRemoteObjectSourceLocationInfo>. |
57 | |
58 | \sa remoteObjectRemoved() |
59 | */ |
60 | |
61 | /*! |
62 | \fn void QRemoteObjectRegistry::remoteObjectRemoved(const QRemoteObjectSourceLocation &entry) |
63 | |
64 | This signal is emitted whenever a Source location is removed from the Registry. |
65 | |
66 | \a entry is a QRemoteObjectSourceLocation, a typedef for |
67 | QPair<QString, QRemoteObjectSourceLocationInfo>. |
68 | |
69 | \sa remoteObjectAdded() |
70 | */ |
71 | |
72 | /*! |
73 | \property QRemoteObjectRegistry::sourceLocations |
74 | \brief The set of sources known to the registry. |
75 | |
76 | This property is a QRemoteObjectSourceLocations, which is a typedef for |
77 | QHash<QString, QRemoteObjectSourceLocationInfo>. Each known \l Source is |
78 | contained as a QString key in the hash, and the corresponding value for |
79 | that key is the QRemoteObjectSourceLocationInfo for the host node. |
80 | */ |
81 | |
82 | /*! |
83 | Destructor for QRemoteObjectRegistry. |
84 | */ |
85 | QRemoteObjectRegistry::~QRemoteObjectRegistry() |
86 | {} |
87 | |
88 | void QRemoteObjectRegistry::registerMetatypes() |
89 | { |
90 | static bool initialized = false; |
91 | if (initialized) |
92 | return; |
93 | initialized = true; |
94 | qRegisterMetaType<QRemoteObjectSourceLocation>(); |
95 | qRegisterMetaType<QRemoteObjectSourceLocations>(); |
96 | } |
97 | |
98 | void QRemoteObjectRegistry::initialize() |
99 | { |
100 | QRemoteObjectRegistry::registerMetatypes(); |
101 | QVariantList properties; |
102 | properties.reserve(asize: 3); |
103 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocations()); |
104 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocation()); |
105 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocation()); |
106 | setProperties(std::move(properties)); |
107 | } |
108 | |
109 | void QRemoteObjectRegistry::notifySourceLocationsChanged() |
110 | { |
111 | d_func()->sourceLocations.notify(); |
112 | } |
113 | |
114 | /*! |
115 | Returns a QRemoteObjectSourceLocations object, which includes the name |
116 | and additional information of all sources known to the registry. |
117 | */ |
118 | QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const |
119 | { |
120 | return d_func()->sourceLocations.value(); |
121 | } |
122 | |
123 | QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const |
124 | { |
125 | return &d_func()->sourceLocations; |
126 | } |
127 | |
128 | /*! |
129 | \internal |
130 | */ |
131 | void QRemoteObjectRegistry::addSource(const QRemoteObjectSourceLocation &entry) |
132 | { |
133 | Q_D(QRemoteObjectRegistry); |
134 | if (d->hostedSources.contains(key: entry.first)) { |
135 | qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first |
136 | << "as this node already has a source by that name." ; |
137 | return; |
138 | } |
139 | d->hostedSources.insert(key: entry.first, value: entry.second); |
140 | if (state() != QRemoteObjectReplica::State::Valid) |
141 | return; |
142 | |
143 | if (sourceLocations().contains(key: entry.first)) { |
144 | qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first |
145 | << "as another source (" << sourceLocations().value(key: entry.first) |
146 | << ") has already registered that name." ; |
147 | return; |
148 | } |
149 | qCDebug(QT_REMOTEOBJECT) << "An entry was added to the registry - Sending to source" << entry.first << entry.second; |
150 | // This does not set any data to avoid a coherency problem between client and server |
151 | static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "addSource(QRemoteObjectSourceLocation)" ); |
152 | QVariantList args; |
153 | args << QVariant::fromValue(value: entry); |
154 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
155 | } |
156 | |
157 | /*! |
158 | \internal |
159 | */ |
160 | void QRemoteObjectRegistry::removeSource(const QRemoteObjectSourceLocation &entry) |
161 | { |
162 | Q_D(QRemoteObjectRegistry); |
163 | if (!d->hostedSources.contains(key: entry.first)) |
164 | return; |
165 | |
166 | d->hostedSources.remove(key: entry.first); |
167 | if (state() != QRemoteObjectReplica::State::Valid) |
168 | return; |
169 | |
170 | qCDebug(QT_REMOTEOBJECT) << "An entry was removed from the registry - Sending to source" << entry.first << entry.second; |
171 | // This does not set any data to avoid a coherency problem between client and server |
172 | static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "removeSource(QRemoteObjectSourceLocation)" ); |
173 | QVariantList args; |
174 | args << QVariant::fromValue(value: entry); |
175 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
176 | } |
177 | |
178 | /*! |
179 | \internal |
180 | This internal function supports the edge case where the \l Registry |
181 | is connected after \l Source objects are added to this \l Node, or |
182 | the connection to the \l Registry is lost. When connected/reconnected, this |
183 | function synchronizes local \l Source objects with the \l Registry. |
184 | */ |
185 | void QRemoteObjectRegistry::pushToRegistryIfNeeded() |
186 | { |
187 | Q_D(QRemoteObjectRegistry); |
188 | if (state() != QRemoteObjectReplica::State::Valid) |
189 | return; |
190 | |
191 | if (d->hostedSources.isEmpty()) |
192 | return; |
193 | |
194 | const auto &sourceLocs = sourceLocations(); |
195 | for (auto it = d->hostedSources.begin(); it != d->hostedSources.end(); ) { |
196 | const QString &loc = it.key(); |
197 | const auto sourceLocsIt = sourceLocs.constFind(key: loc); |
198 | if (sourceLocsIt != sourceLocs.cend()) { |
199 | qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << loc << "as another source (" |
200 | << sourceLocsIt.value() << ") has already registered that name." ; |
201 | it = d->hostedSources.erase(it); |
202 | } else { |
203 | static const int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "addSource(QRemoteObjectSourceLocation)" ); |
204 | QVariantList args{QVariant::fromValue(value: QRemoteObjectSourceLocation(loc, it.value()))}; |
205 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
206 | ++it; |
207 | } |
208 | } |
209 | } |
210 | |
211 | QT_END_NAMESPACE |
212 | |