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 QPair<QString, QUrl>. |
56 | |
57 | \sa remoteObjectRemoved() |
58 | */ |
59 | |
60 | /*! |
61 | \fn void QRemoteObjectRegistry::remoteObjectRemoved(const QRemoteObjectSourceLocation &entry) |
62 | |
63 | This signal is emitted whenever a Source location is removed from the Registry. |
64 | |
65 | \a entry is a QRemoteObjectSourceLocation, a typedef for QPair<QString, QUrl>. |
66 | |
67 | \sa remoteObjectAdded() |
68 | */ |
69 | |
70 | /*! |
71 | \property QRemoteObjectRegistry::sourceLocations |
72 | \brief The set of sources known to the registry. |
73 | |
74 | This property is a QRemoteObjectSourceLocations, which is a typedef for |
75 | QHash<QString, QUrl>. Each known \l Source is the QString key, while the |
76 | url for the host node is the corresponding value for that key in the hash. |
77 | */ |
78 | |
79 | /*! |
80 | Destructor for QRemoteObjectRegistry. |
81 | */ |
82 | QRemoteObjectRegistry::~QRemoteObjectRegistry() |
83 | {} |
84 | |
85 | void QRemoteObjectRegistry::registerMetatypes() |
86 | { |
87 | static bool initialized = false; |
88 | if (initialized) |
89 | return; |
90 | initialized = true; |
91 | qRegisterMetaType<QRemoteObjectSourceLocation>(); |
92 | qRegisterMetaType<QRemoteObjectSourceLocations>(); |
93 | } |
94 | |
95 | void QRemoteObjectRegistry::initialize() |
96 | { |
97 | QRemoteObjectRegistry::registerMetatypes(); |
98 | QVariantList properties; |
99 | properties.reserve(asize: 3); |
100 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocations()); |
101 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocation()); |
102 | properties << QVariant::fromValue(value: QRemoteObjectSourceLocation()); |
103 | setProperties(std::move(properties)); |
104 | } |
105 | |
106 | void QRemoteObjectRegistry::notifySourceLocationsChanged() |
107 | { |
108 | d_func()->sourceLocations.notify(); |
109 | } |
110 | |
111 | /*! |
112 | Returns a QRemoteObjectSourceLocations object, which includes the name |
113 | and additional information of all sources known to the registry. |
114 | */ |
115 | QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const |
116 | { |
117 | return d_func()->sourceLocations.value(); |
118 | } |
119 | |
120 | QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const |
121 | { |
122 | return &d_func()->sourceLocations; |
123 | } |
124 | |
125 | /*! |
126 | \internal |
127 | */ |
128 | void QRemoteObjectRegistry::addSource(const QRemoteObjectSourceLocation &entry) |
129 | { |
130 | Q_D(QRemoteObjectRegistry); |
131 | if (d->hostedSources.contains(key: entry.first)) { |
132 | qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first |
133 | << "as this node already has a source by that name." ; |
134 | return; |
135 | } |
136 | d->hostedSources.insert(key: entry.first, value: entry.second); |
137 | if (state() != QRemoteObjectReplica::State::Valid) |
138 | return; |
139 | |
140 | if (sourceLocations().contains(key: entry.first)) { |
141 | qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first |
142 | << "as another source (" << sourceLocations().value(key: entry.first) |
143 | << ") has already registered that name." ; |
144 | return; |
145 | } |
146 | qCDebug(QT_REMOTEOBJECT) << "An entry was added to the registry - Sending to source" << entry.first << entry.second; |
147 | // This does not set any data to avoid a coherency problem between client and server |
148 | static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "addSource(QRemoteObjectSourceLocation)" ); |
149 | QVariantList args; |
150 | args << QVariant::fromValue(value: entry); |
151 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
152 | } |
153 | |
154 | /*! |
155 | \internal |
156 | */ |
157 | void QRemoteObjectRegistry::removeSource(const QRemoteObjectSourceLocation &entry) |
158 | { |
159 | Q_D(QRemoteObjectRegistry); |
160 | if (!d->hostedSources.contains(key: entry.first)) |
161 | return; |
162 | |
163 | d->hostedSources.remove(key: entry.first); |
164 | if (state() != QRemoteObjectReplica::State::Valid) |
165 | return; |
166 | |
167 | qCDebug(QT_REMOTEOBJECT) << "An entry was removed from the registry - Sending to source" << entry.first << entry.second; |
168 | // This does not set any data to avoid a coherency problem between client and server |
169 | static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "removeSource(QRemoteObjectSourceLocation)" ); |
170 | QVariantList args; |
171 | args << QVariant::fromValue(value: entry); |
172 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
173 | } |
174 | |
175 | /*! |
176 | \internal |
177 | This internal function supports the edge case where the \l Registry |
178 | is connected after \l Source objects are added to this \l Node, or |
179 | the connection to the \l Registry is lost. When connected/reconnected, this |
180 | function synchronizes local \l Source objects with the \l Registry. |
181 | */ |
182 | void QRemoteObjectRegistry::pushToRegistryIfNeeded() |
183 | { |
184 | Q_D(QRemoteObjectRegistry); |
185 | if (state() != QRemoteObjectReplica::State::Valid) |
186 | return; |
187 | |
188 | if (d->hostedSources.isEmpty()) |
189 | return; |
190 | |
191 | const auto &sourceLocs = sourceLocations(); |
192 | for (auto it = d->hostedSources.begin(); it != d->hostedSources.end(); ) { |
193 | const QString &loc = it.key(); |
194 | const auto sourceLocsIt = sourceLocs.constFind(key: loc); |
195 | if (sourceLocsIt != sourceLocs.cend()) { |
196 | qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << loc << "as another source (" |
197 | << sourceLocsIt.value() << ") has already registered that name." ; |
198 | it = d->hostedSources.erase(it); |
199 | } else { |
200 | static const int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod(method: "addSource(QRemoteObjectSourceLocation)" ); |
201 | QVariantList args{QVariant::fromValue(value: QRemoteObjectSourceLocation(loc, it.value()))}; |
202 | send(call: QMetaObject::InvokeMetaMethod, index, args); |
203 | ++it; |
204 | } |
205 | } |
206 | } |
207 | |
208 | QT_END_NAMESPACE |
209 | |