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
11QT_BEGIN_NAMESPACE
12
13class 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*/
37QRemoteObjectRegistry::QRemoteObjectRegistry(QObject *parent)
38 : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent)
39{
40 connect(sender: this, signal: &QRemoteObjectRegistry::stateChanged, context: this, slot: &QRemoteObjectRegistry::pushToRegistryIfNeeded);
41}
42
43QRemoteObjectRegistry::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*/
82QRemoteObjectRegistry::~QRemoteObjectRegistry()
83{}
84
85void QRemoteObjectRegistry::registerMetatypes()
86{
87 static bool initialized = false;
88 if (initialized)
89 return;
90 initialized = true;
91 qRegisterMetaType<QRemoteObjectSourceLocation>();
92 qRegisterMetaType<QRemoteObjectSourceLocations>();
93}
94
95void 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
106void 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*/
115QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const
116{
117 return d_func()->sourceLocations.value();
118}
119
120QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const
121{
122 return &d_func()->sourceLocations;
123}
124
125/*!
126 \internal
127*/
128void 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*/
157void 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*/
182void 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
208QT_END_NAMESPACE
209

source code of qtremoteobjects/src/remoteobjects/qremoteobjectregistry.cpp