swift
Loading...
Searching...
No Matches
datalinkdbus.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (C) 2017 swift Project Community / Contributors
2// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3
5
7
8#include <QDBusConnection>
9#include <QDBusServiceWatcher>
10
11#include "misc/dbusserver.h"
17
18using namespace swift::misc::shared_state::dbus;
19
21{
23 {
24 connect(&m_watchTimer, &QTimer::timeout, this, &CDataLinkDBus::checkConnection);
25 m_watchTimer.setInterval(1000);
26 }
27
29
30 void CDataLinkDBus::overrideIdentifier(const CIdentifier &id) { m_identifier = id; }
31
33 {
34 Q_ASSERT_X(!m_hub, Q_FUNC_INFO, "Already initialized");
35 m_hub = IHub::create(false, server, QDBusConnection("unused"), {}, this);
36 m_watchTimer.start();
37 checkConnection();
38 }
39
40 void CDataLinkDBus::initializeRemote(const QDBusConnection &connection, const QString &service)
41 {
42 Q_ASSERT_X(!m_hub, Q_FUNC_INFO, "Already initialized");
43 m_hub = IHub::create(true, nullptr, connection, service, this);
44 m_watchTimer.start();
45 checkConnection();
46 }
47
48 void CDataLinkDBus::checkConnection()
49 {
50 if (m_hub->isConnected())
51 {
52 onConnected();
53 }
54 else
55 {
56 onDisconnected();
57 }
58 }
59
60 void CDataLinkDBus::onConnected()
61 {
62 if (m_duplex)
63 {
64 return;
65 }
66
67 QFuture<void> ready;
68 std::tie(m_duplex, ready) = m_hub->getDuplex(m_identifier);
69 connect(m_duplex.get(), &IDuplex::eventPosted, this, &CDataLinkDBus::handlePeerEvent);
70 connect(m_duplex.get(), &IDuplex::peerSubscriptionsReceived, this, &CDataLinkDBus::setPeerSubscriptions);
71 connect(m_duplex.get(), &IDuplex::requestReceived, this, &CDataLinkDBus::handlePeerRequest);
72 doAfter(ready, m_duplex.get(), [this] {
73 m_duplex->requestPeerSubscriptions();
74 announceLocalSubscriptions();
75 setConnectionStatus(true);
76 });
77 }
78
79 void CDataLinkDBus::onDisconnected()
80 {
81 m_duplex.reset();
83 }
84
85 void CDataLinkDBus::handleLocalEvent(const QString &channel, const CVariant &param)
86 {
87 handlePeerEvent(channel, param);
88
89 if (!m_duplex)
90 {
91 return;
92 }
93
94 for (const auto &filter : std::as_const(getChannel(channel).peerSubscriptions))
95 {
96 if (filter.matches(param))
97 {
98 m_duplex->postEvent(channel, param);
99 return;
100 }
101 }
102 }
103
104 void CDataLinkDBus::handlePeerEvent(const QString &channel, const CVariant &param)
105 {
106 for (const auto &observerWeak : std::as_const(getChannel(channel).passiveObservers))
107 {
108 auto observer = observerWeak.lock();
109 if (observer && observer->eventSubscription().matches(param))
110 {
111 observer->handleEvent(param);
112 }
113 }
114 }
115
116 void CDataLinkDBus::announceLocalSubscriptions()
117 {
118 for (const auto &channel : getChannelNames())
119 {
120 announceLocalSubscriptions(channel);
121 }
122 }
123
124 void CDataLinkDBus::announceLocalSubscriptions(const QString &channel)
125 {
126 CVariantList filters;
127 for (const auto &observerWeak : std::as_const(getChannel(channel).passiveObservers))
128 {
129 auto observer = observerWeak.lock();
130 if (observer)
131 {
132 filters.push_back(observer->eventSubscription());
133 }
134 }
135 m_duplex->setSubscription(channel, filters);
136 }
137
138 void CDataLinkDBus::setPeerSubscriptions(const QString &channel, const CVariantList &filters)
139 {
140 getChannel(channel).peerSubscriptions = filters;
141 }
142
143 QFuture<CVariant> CDataLinkDBus::handleLocalRequest(const QString &channel, const CVariant &param)
144 {
145 auto mutator = getChannel(channel).activeMutator.lock();
146 if (mutator)
147 {
148 return mutator->handleRequest(param);
149 }
150
151 if (!m_duplex)
152 {
153 return {};
154 }
155
156 return m_duplex->submitRequest(channel, param);
157 }
158
159 void CDataLinkDBus::handlePeerRequest(const QString &channel, const CVariant &param, quint32 token)
160 {
161 auto mutator = getChannel(channel).activeMutator.lock();
162 if (mutator)
163 {
164 doAfter(mutator->handleRequest(param), this, [this, token](auto future) {
165 if (m_duplex)
166 {
167 m_duplex->reply(future.result(), token);
168 }
169 });
170 }
171 }
172
174 {
176 [this, channel = getChannelName(mutator)](const CVariant &param) { handleLocalEvent(channel, param); });
177 }
178
180 {
181 publish(static_cast<const CPassiveMutator *>(mutator));
182
183 auto &channel = getChannel(mutator);
184 Q_ASSERT_X(!channel.activeMutator, Q_FUNC_INFO, "Tried to publish two active mutators on one channel");
185 channel.activeMutator = mutator->weakRef();
186
187 if (m_duplex)
188 {
189 m_duplex->advertise(getChannelName(mutator));
190 }
191 connect(mutator, &QObject::destroyed, this, [this, channel = getChannelName(mutator)] {
192 if (m_duplex)
193 {
194 m_duplex->withdraw(channel);
195 }
196 });
197 }
198
200 {
201 getChannel(observer).passiveObservers.push_back(observer->weakRef());
202
203 auto announce = [this, channel = getChannelName(observer)] {
204 if (m_duplex)
205 {
206 announceLocalSubscriptions(channel);
207 }
208 };
209 connect(observer, &CPassiveObserver::eventSubscriptionChanged, this, announce);
210 connect(observer, &QObject::destroyed, this, announce);
211 announce();
212 }
213
215 {
216 subscribe(static_cast<const CPassiveObserver *>(observer));
217
219 [this, channel = getChannelName(observer)](const CVariant &param, CPromise<CVariant> reply) {
220 reply.chainResult(handleLocalRequest(channel, param));
221 });
222 }
223
224 QStringList CDataLinkDBus::getChannelNames() const
225 {
226 QMutexLocker lock(&m_channelsMutex);
227 return m_channels.keys();
228 }
229
230 CDataLinkDBus::Channel &CDataLinkDBus::getChannel(const QString &name)
231 {
232 QMutexLocker lock(&m_channelsMutex);
233 return m_channels[name];
234 }
235
236 CDataLinkDBus::Channel &CDataLinkDBus::getChannel(const QObject *object)
237 {
238 return getChannel(getChannelName(object));
239 }
240} // namespace swift::misc::shared_state
Custom DBusServer.
Definition dbusserver.h:34
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition identifier.h:29
A promise-based interface to QFuture, similar to std::promise for std::future.
Definition promise.h:87
void chainResult(QFuture< U > future)
When the given future is ready, use its result to set the result of this promise.
Definition promise.h:112
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition sequence.h:308
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
Definition variant.h:69
Extends CPassiveMutator with the ability to respond to requests.
QWeakPointer< const CActiveMutator > weakRef() const
Get a QWeakPointer pointing to this object.
Extends CPassiveObserver with the ability to send requests and receive replies.
void requestPosted(const swift::misc::CVariant &param, swift::misc::CPromise< swift::misc::CVariant > o_reply)
Emitted by request and requestAsync.
Endpoint which can emit events to subscribers.
void eventPosted(const swift::misc::CVariant &param)
Emitted by postEvent.
Endpoint which can subscribe to events emitted by CPassiveMutator.
QWeakPointer< const CPassiveObserver > weakRef() const
Get a QWeakPointer pointing to this object.
void eventSubscriptionChanged(const swift::misc::CVariant &param)
Emitted by setEventSubscription.
void requestReceived(const QString &channel, const swift::misc::CVariant &param, quint32 token, QPrivateSignal)
Server has submitted a request to be handled by the client.
void eventPosted(const QString &channel, const swift::misc::CVariant &param)
Server has notified the client that an event has been posted.
void peerSubscriptionsReceived(const QString &channel, const swift::misc::CVariantList &filters)
Server has notified the client that other clients' event subscriptions have changed.
virtual bool isConnected() const =0
Is connected?
static IHub * create(bool proxy, CDBusServer *server, const QDBusConnection &connection, const QString &service, QObject *parent=nullptr)
Construct a new hub.
Definition hub.cpp:17
Utilities for sharing state between multiple objects.
Definition application.h:48
void doAfter(QFuture< T > future, QObject *context, F &&func)
Connect a slot or function to be invoked in the given context when a QFuture is finished.
Definition promise.h:68
QObject(QObject *parent)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
QObject * parent() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
void timeout()