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
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*/
85QRemoteObjectRegistry::~QRemoteObjectRegistry()
86{}
87
88void QRemoteObjectRegistry::registerMetatypes()
89{
90 static bool initialized = false;
91 if (initialized)
92 return;
93 initialized = true;
94 qRegisterMetaType<QRemoteObjectSourceLocation>();
95 qRegisterMetaType<QRemoteObjectSourceLocations>();
96}
97
98void 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
109void 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*/
118QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const
119{
120 return d_func()->sourceLocations.value();
121}
122
123QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const
124{
125 return &d_func()->sourceLocations;
126}
127
128/*!
129 \internal
130*/
131void 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*/
160void 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*/
185void 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
211QT_END_NAMESPACE
212

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