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 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 == GotifyPushProvider::Id) {
262 m_pushProvider.reset(
new GotifyPushProvider);
263 }
else if (pushProviderName == NextPushProvider::Id) {
264 m_pushProvider.reset(
new NextPushProvider);
265 }
else if (pushProviderName == NtfyPushProvider::Id) {
266 m_pushProvider.reset(
new NtfyPushProvider);
267 }
else if (pushProviderName == 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);
308 if (m_pushProvider->metaObject() == &MockPushProvider::staticMetaObject) [[unlikely]] {
312 for (
const auto &token : tokensToUnregister) {
317bool Distributor::hasCurrentCommand()
const
319 return m_currentCommand.type != Command::NoCommand;
322void Distributor::processNextCommand()
324 if (hasCurrentCommand() || m_commandQueue.empty() || !isNetworkAvailable()) {
328 m_currentCommand = m_commandQueue.front();
329 m_commandQueue.pop_front();
330 switch (m_currentCommand.type) {
331 case Command::NoCommand:
333 processNextCommand();
335 case Command::Register:
336 m_pushProvider->registerClient(m_currentCommand.client);
340 m_pushProvider->unregisterClient(m_currentCommand.client);
342 case Command::Connect:
343 m_pushProvider->connectToProvider();
345 case Command::Disconnect:
346 m_pushProvider->disconnectFromProvider();
348 case Command::ChangePushProvider:
351 settings.
setValue(QLatin1String(
"PushProvider/Type"), m_currentCommand.pushProvider);
352 m_currentCommand = {};
353 if (setupPushProvider()) {
354 processNextCommand();
361int Distributor::status()
const
366void Distributor::setStatus(DistributorStatus::Status
status)
368 if (m_status == status) {
376QString Distributor::pushProviderId()
const
379 return settings.
value(QStringLiteral(
"PushProvider/Type"), QString()).
toString();
382QVariantMap Distributor::pushProviderConfiguration(
const QString &pushProviderId)
const
384 if (pushProviderId.isEmpty()) {
390 const auto keys = settings.
allKeys();
393 for (
const auto &key : keys) {
394 const auto v = settings.
value(key);
396 config.insert(key, settings.
value(key));
403void Distributor::setPushProvider(
const QString &pushProviderId,
const QVariantMap &config)
406 bool configChanged =
false;
409 for (
auto it = config.begin(); it != config.end(); ++it) {
410 const auto oldValue = settings.
value(it.key());
411 configChanged |= oldValue != it.value();
412 settings.
setValue(it.key(), it.value());
415 if (!configChanged && pushProviderId == this->pushProviderId()) {
420 if (m_status != DistributorStatus::NoSetup) {
421 for (
const auto &client : m_clients) {
422 forceUnregisterClient(client.token);
424 if (m_status == DistributorStatus::Connected) {
426 cmd.type = Command::Disconnect;
427 m_commandQueue.push_back(std::move(cmd));
431 cmd.type = Command::ChangePushProvider;
432 cmd.pushProvider = pushProviderId;
433 m_commandQueue.
push_back(std::move(cmd));
437 if (!m_clients.empty()) {
439 cmd.type = Command::Connect;
440 m_commandQueue.push_back(std::move(cmd));
444 for (
const auto &client : m_clients) {
446 cmd.type = Command::Register;
448 m_commandQueue.push_back(std::move(cmd));
454 if (!m_commandQueue.empty()) {
456 cmd.type = Command::Connect;
457 m_commandQueue.push_front(std::move(cmd));
461 cmd.type = Command::ChangePushProvider;
462 cmd.pushProvider = pushProviderId;
466 processNextCommand();
469QList<KUnifiedPush::ClientInfo> Distributor::registeredClients()
const
471 QList<KUnifiedPush::ClientInfo> result;
472 result.
reserve(m_clients.size());
474 for (
const auto &client : m_clients) {
476 info.token = client.token;
477 info.serviceName = client.serviceName;
478 info.description = client.description;
485void Distributor::forceUnregisterClient(
const QString &token)
487 qCDebug(Log) << token;
488 const auto it = std::find_if(m_clients.begin(), m_clients.end(), [&token](
const auto &client) {
489 return client.token == token;
491 if (it == m_clients.end()) {
492 qCWarning(Log) <<
"Unregistration request for unknown client.";
499 m_commandQueue.push_back(std::move(cmd));
500 processNextCommand();
503bool Distributor::isNetworkAvailable()
const
508 return reachability == QNetworkInformation::Reachability::Online || reachability == QNetworkInformation::Reachability::Unknown;
513#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