6#include "distributor.h"
7#include "distributor1adaptor.h"
8#include "managementadaptor.h"
11#include "connector1iface.h"
12#include "gotifypushprovider.h"
15#include "mockpushprovider.h"
16#include "nextpushprovider.h"
17#include "ntfypushprovider.h"
19#include "../shared/unifiedpush-constants.h"
21#include <QDBusConnection>
24#include <QNetworkInformation>
28Distributor::Distributor(
QObject *parent)
31 qDBusRegisterMetaType<KUnifiedPush::ClientInfo>();
32 qDBusRegisterMetaType<QList<KUnifiedPush::ClientInfo>>();
42 new Distributor1Adaptor(
this);
45 new ManagementAdaptor(
this);
49 if (!setupPushProvider()) {
57 m_clients.
reserve(clientTokens.size());
58 for (
const auto &token : clientTokens) {
59 auto client = Client::load(token, settings);
60 if (client.isValid()) {
61 m_clients.push_back(std::move(client));
64 qCDebug(
Log) << m_clients.size() <<
"registered clients loaded";
67 purgeUnavailableClients();
70 if (!m_clients.empty())
72 setStatus(DistributorStatus::NoNetwork);
74 cmd.type = Command::Connect;
75 m_commandQueue.push_back(std::move(cmd));
77 setStatus(DistributorStatus::Idle);
83Distributor::~Distributor() =
default;
87 qCDebug(Log) << serviceName << token;
88 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&token](
const auto &client) {
89 return client.token == token;
91 if (it == m_clients.end()) {
92 qCDebug(Log) <<
"Registering new client";
96 if (m_clients.empty()) {
98 cmd.type = Command::Connect;
99 m_commandQueue.push_back(std::move(cmd));
103 cmd.type = Command::Register;
104 cmd.client.token = token;
105 cmd.client.serviceName = serviceName;
106 cmd.client.description = description;
109 m_commandQueue.push_back(std::move(cmd));
111 processNextCommand();
115 qCDebug(Log) <<
"Registering known client";
117 (*it).connector().NewEndpoint((*it).token, (*it).endpoint);
118 registrationResultReason.
clear();
119 return QLatin1String(UP_REGISTER_RESULT_SUCCESS);
122void Distributor::Unregister(
const QString& token)
124 qCDebug(Log) << token;
125 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&token](
const auto &client) {
126 return client.token == token;
128 if (it == m_clients.end()) {
129 qCWarning(Log) <<
"Unregistration request for unknown client.";
136 m_commandQueue.push_back(std::move(cmd));
137 processNextCommand();
140void Distributor::messageReceived(
const Message &msg)
const
142 qCDebug(Log) << msg.clientRemoteId << msg.content;
143 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&msg](
const auto &client) {
144 return client.remoteId == msg.clientRemoteId;
146 if (it == m_clients.end()) {
147 qCWarning(Log) <<
"Received message for unknown client";
152 (*it).connector().Message((*it).token, msg.content, {});
157 qCDebug(Log) << client.token << client.remoteId << client.serviceName <<
error << errorMsg;
162 m_clients.push_back(client);
165 client.store(settings);
166 settings.
setValue(QStringLiteral(
"Clients/Tokens"), clientTokens());
167 Q_EMIT registeredClientsChanged();
169 client.
connector().NewEndpoint(client.token, client.endpoint);
179 m_commandQueue.push_front(std::move(m_currentCommand));
187 m_currentCommand = {};
188 processNextCommand();
193 qCDebug(Log) << client.token << client.remoteId << client.serviceName <<
error;
201 settings.
remove(client.token);
202 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&client](
const auto &c) {
203 return c.token == client.token;
205 if (it != m_clients.end()) {
209 if (m_clients.empty()) {
211 cmd.type = Command::Disconnect;
212 m_commandQueue.push_back(std::move(cmd));
215 settings.
setValue(QStringLiteral(
"Clients/Tokens"), clientTokens());
216 Q_EMIT registeredClientsChanged();
221 m_commandQueue.push_front(std::move(m_currentCommand));
225 m_currentCommand = {};
226 processNextCommand();
229void Distributor::providerConnected()
232 setStatus(DistributorStatus::Connected);
233 m_currentCommand = {};
234 processNextCommand();
239 qCDebug(Log) <<
error << errorMsg;
240 if (m_currentCommand.type == Command::Disconnect) {
241 m_currentCommand = {};
242 setStatus(m_clients.empty() ? DistributorStatus::Idle : DistributorStatus::NoNetwork);
244 setStatus(DistributorStatus::NoNetwork);
246 processNextCommand();
249QStringList Distributor::clientTokens()
const
253 std::transform(m_clients.begin(), m_clients.end(), std::back_inserter(l), [](
const auto &client) { return client.token; });
257bool Distributor::setupPushProvider()
260 const auto pushProviderName = pushProviderId();
261 if (pushProviderName == QLatin1String(GotifyPushProvider::Id)) {
262 m_pushProvider.reset(
new GotifyPushProvider);
263 }
else if (pushProviderName == QLatin1String(NextPushProvider::Id)) {
264 m_pushProvider.reset(
new NextPushProvider);
265 }
else if (pushProviderName == QLatin1String(NtfyPushProvider::Id)) {
266 m_pushProvider.reset(
new NtfyPushProvider);
267 }
else if (pushProviderName == QLatin1String(MockPushProvider::Id)) {
268 m_pushProvider.reset(
new MockPushProvider);
270 qCWarning(Log) <<
"Unknown push provider:" << pushProviderName;
271 m_pushProvider.reset();
272 setStatus(DistributorStatus::NoSetup);
278 if (!m_pushProvider->loadSettings(settings)) {
279 qCWarning(Log) <<
"Invalid push provider settings!";
280 setStatus(DistributorStatus::NoSetup);
293void Distributor::purgeUnavailableClients()
296 std::sort(activatableServiceNames.
begin(), activatableServiceNames.
end());
299 QStringList tokensToUnregister;
300 for (
const auto &client : m_clients) {
301 if (!std::binary_search(activatableServiceNames.
begin(), activatableServiceNames.
end(), client.serviceName)) {
302 tokensToUnregister.
push_back(client.token);
306 for (
const auto &token : tokensToUnregister) {
311bool Distributor::hasCurrentCommand()
const
313 return m_currentCommand.type != Command::NoCommand;
316void Distributor::processNextCommand()
318 if (hasCurrentCommand() || m_commandQueue.empty() || !isNetworkAvailable()) {
322 m_currentCommand = m_commandQueue.front();
323 m_commandQueue.pop_front();
324 switch (m_currentCommand.type) {
325 case Command::NoCommand:
327 processNextCommand();
329 case Command::Register:
330 m_pushProvider->registerClient(m_currentCommand.client);
334 m_pushProvider->unregisterClient(m_currentCommand.client);
336 case Command::Connect:
337 m_pushProvider->connectToProvider();
339 case Command::Disconnect:
340 m_pushProvider->disconnectFromProvider();
342 case Command::ChangePushProvider:
345 settings.
setValue(QLatin1String(
"PushProvider/Type"), m_currentCommand.pushProvider);
346 m_currentCommand = {};
347 if (setupPushProvider()) {
348 processNextCommand();
355int Distributor::status()
const
360void Distributor::setStatus(DistributorStatus::Status
status)
362 if (m_status == status) {
370QString Distributor::pushProviderId()
const
373 return settings.
value(QStringLiteral(
"PushProvider/Type"), QString()).
toString();
376QVariantMap Distributor::pushProviderConfiguration(
const QString &pushProviderId)
const
378 if (pushProviderId.isEmpty()) {
384 const auto keys = settings.
allKeys();
387 for (
const auto &key : keys) {
388 const auto v = settings.
value(key);
390 config.insert(key, settings.
value(key));
397void Distributor::setPushProvider(
const QString &pushProviderId,
const QVariantMap &config)
400 bool configChanged =
false;
403 for (
auto it = config.begin(); it != config.end(); ++it) {
404 const auto oldValue = settings.
value(it.key());
405 configChanged |= oldValue != it.value();
406 settings.
setValue(it.key(), it.value());
409 if (!configChanged && pushProviderId == this->pushProviderId()) {
414 if (m_status != DistributorStatus::NoSetup) {
415 for (
const auto &client : m_clients) {
416 forceUnregisterClient(client.token);
418 if (m_status == DistributorStatus::Connected) {
420 cmd.type = Command::Disconnect;
421 m_commandQueue.push_back(std::move(cmd));
425 cmd.type = Command::ChangePushProvider;
426 cmd.pushProvider = pushProviderId;
427 m_commandQueue.
push_back(std::move(cmd));
431 if (!m_clients.empty()) {
433 cmd.type = Command::Connect;
434 m_commandQueue.push_back(std::move(cmd));
438 for (
const auto &client : m_clients) {
440 cmd.type = Command::Register;
442 m_commandQueue.push_back(std::move(cmd));
448 if (!m_commandQueue.empty()) {
450 cmd.type = Command::Connect;
451 m_commandQueue.push_front(std::move(cmd));
455 cmd.type = Command::ChangePushProvider;
456 cmd.pushProvider = pushProviderId;
460 processNextCommand();
463QList<KUnifiedPush::ClientInfo> Distributor::registeredClients()
const
465 QList<KUnifiedPush::ClientInfo> result;
466 result.
reserve(m_clients.size());
468 for (
const auto &client : m_clients) {
470 info.token = client.token;
471 info.serviceName = client.serviceName;
472 info.description = client.description;
479void Distributor::forceUnregisterClient(
const QString &token)
481 qCDebug(Log) << token;
482 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&token](
const auto &client) {
483 return client.token == token;
485 if (it == m_clients.end()) {
486 qCWarning(Log) <<
"Unregistration request for unknown client.";
493 m_commandQueue.push_back(std::move(cmd));
494 processNextCommand();
497bool Distributor::isNetworkAvailable()
const
502 return reachability == QNetworkInformation::Reachability::Online || reachability == QNetworkInformation::Reachability::Unknown;
507#include "moc_distributor.cpp"
void messageReceived(const KUnifiedPush::Message &msg)
Inform about a received push notification.
void connected()
Emitted after the connection to the push provider has been established successfully.
void clientUnregistered(const KUnifiedPush::Client &client, KUnifiedPush::AbstractPushProvider::Error error=NoError)
Emitted after successful client unregistration.
void disconnected(KUnifiedPush::AbstractPushProvider::Error error, const QString &errorMsg={})
Emitted after the connection to the push provider disconnected or failed to be established.
void clientRegistered(const KUnifiedPush::Client &client, KUnifiedPush::AbstractPushProvider::Error error=NoError, const QString &errorMsg={})
Emitted after successful client registration.
@ ProviderRejected
communication worked, but the provider refused to complete the operation
@ TransientNetworkError
temporary network error, try again
@ NoError
operation succeeded
Information about a registered client.
OrgUnifiedpushConnector1Interface connector() const
D-Bus UnifiedPush connector interface.
Distributor command queue entries.
@ Unregister
unregistration requested by client
@ ForceUnregister
unregistration triggered by distributor
A received push notification message.
Q_SCRIPTABLE CaptureState status()
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
Client-side integration with UnifiedPush.
QDBusConnectionInterface * interface() const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
bool send(const QDBusMessage &message) const const
QDBusConnection sessionBus()
const QDBusMessage & message() const const
void setDelayedReply(bool enable) const const
QDBusMessage createReply(const QList< QVariant > &arguments) const const
void push_back(parameter_type value)
void reserve(qsizetype size)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QStringList allKeys() const const
void beginGroup(QAnyStringView prefix)
void remove(QAnyStringView key)
void setValue(QAnyStringView key, const QVariant &value)
QVariant value(QAnyStringView key) const const
QString fromLatin1(QByteArrayView str)
void push_front(QChar ch)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const
QStringList toStringList() const const