KUnifiedPush

ntfypushprovider.cpp
1/*
2 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "ntfypushprovider.h"
7#include "client.h"
8#include "logging.h"
9#include "message.h"
10
11#include <QJsonDocument>
12#include <QJsonObject>
13#include <QNetworkReply>
14#include <QSettings>
15#include <QUrlQuery>
16#include <QUuid>
17
18using namespace KUnifiedPush;
19
20NtfyPushProvider::NtfyPushProvider(QObject *parent)
21 : AbstractPushProvider(Id, parent)
22{
23 connect(&m_sseStream, &ServerSentEventsStream::messageReceived, this, [this](const SSEMessage &sse) {
24 qCDebug(Log) << sse.event << sse.data;
25 if (sse.event.isEmpty()) {
26 QJsonObject msgObj = QJsonDocument::fromJson(sse.data).object();
27 Message msg;
28 msg.clientRemoteId = msgObj.value(QLatin1String("topic")).toString();
29 msg.content = msgObj.value(QLatin1String("message")).toString().toUtf8();
30 if (msgObj.value(QLatin1String("encoding")).toString() == QLatin1String("base64")) {
31 msg.content = QByteArray::fromBase64(msg.content);
32 }
33 m_lastMessageId = msgObj.value(QLatin1String("id")).toString();
34 Q_EMIT messageReceived(msg);
35 storeState();
36 }
37 });
38}
39
40NtfyPushProvider::~NtfyPushProvider() = default;
41
43{
44 m_url = settings.value(QStringLiteral("Url"), QUrl()).toUrl();
45
46 QSettings internal;
47 internal.beginGroup(QLatin1String(providerId()) + QLatin1String("-internal"));
48 m_topics = internal.value(QStringLiteral("Topics"), QStringList()).toStringList();
49 m_lastMessageId = internal.value(QStringLiteral("LastMessageId"), QString()).toString();
50
51 return m_url.isValid();
52}
53
55{
56 doConnectToProvider();
58}
59
61{
62 if (m_sseReply) {
63 m_sseReply->abort();
64 }
66}
67
69{
71 auto newClient = client;
72 newClient.remoteId = topic;
73
74 QUrl endpoint = m_url;
75 auto path = endpoint.path();
76 path += QLatin1Char('/') + topic;
77 endpoint.setPath(path);
78 newClient.endpoint = endpoint.toString();
79
80 m_topics.push_back(topic);
81 storeState();
82 doConnectToProvider();
83 Q_EMIT clientRegistered(newClient);
84}
85
87{
88 m_topics.removeAll(client.remoteId);
89 storeState();
90 doConnectToProvider();
92}
93
94void NtfyPushProvider::doConnectToProvider()
95{
96 if (m_sseReply) {
97 m_sseReply->abort();
98 }
99
100 if (m_topics.empty()) {
101 return;
102 }
103
104 QUrl url = m_url;
105 QString path = url.path();
106 path += QLatin1Char('/') + m_topics.join(QLatin1Char(',')) + QLatin1String("/sse");
107 url.setPath(path);
109 query.addQueryItem(QStringLiteral("up"), QStringLiteral("1"));
110 query.addQueryItem(QStringLiteral("since"), m_lastMessageId.isEmpty() ? QStringLiteral("all") : m_lastMessageId);
111 url.setQuery(query);
112 qCDebug(Log) << url;
113
114 auto reply = nam()->get(QNetworkRequest(url));
115 connect(reply, &QNetworkReply::finished, this, [reply, this]() {
116 reply->deleteLater();
117 if (reply->error() == QNetworkReply::OperationCanceledError) {
118 return; // we triggered this ourselves
119 }
120 qCDebug(Log) << reply->error() << reply->errorString();
121 Q_EMIT disconnected(TransientNetworkError, reply->errorString());
122 });
123
124 m_sseReply = reply;
125 m_sseStream.read(reply);
126}
127
128void NtfyPushProvider::storeState()
129{
130 QSettings settings;
131 settings.beginGroup(QLatin1String(providerId()) + QLatin1String("-internal"));
132 settings.setValue(QStringLiteral("Topics"), m_topics);
133 settings.setValue(QStringLiteral("LastMessageId"), m_lastMessageId);
134}
Base class for push provider protocol implementations.
void connected()
Emitted after the connection to the push provider has been established successfully.
const char * providerId() const
Provider id used e.g.
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.
@ TransientNetworkError
temporary network error, try again
Information about a registered client.
Definition client.h:19
A received push notification message.
Definition message.h:15
void registerClient(const Client &client) override
Register a new client with the provider.
bool loadSettings(const QSettings &settings) override
Load connection settings.
void connectToProvider() override
Attempt to establish a connection to the push provider.
void unregisterClient(const Client &client) override
Unregister a client from the provider.
void disconnectFromProvider() override
Disconnect and existing connection to the push provider.
char * toString(const EngineQuery &query)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
QString path(const QString &relativePath)
Client-side integration with UnifiedPush.
Definition connector.h:16
int64_t Id
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
bool isEmpty() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
bool empty() const const
void push_back(parameter_type value)
qsizetype removeAll(const AT &t)
QNetworkReply * get(const QNetworkRequest &request)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void beginGroup(QAnyStringView prefix)
void setValue(QAnyStringView key, const QVariant &value)
QVariant value(QAnyStringView key) const const
bool isEmpty() const const
QByteArray toUtf8() const const
QString join(QChar separator) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isValid() const const
QString path(ComponentFormattingOptions options) const const
void setPath(const QString &path, ParsingMode mode)
void setQuery(const QString &query, ParsingMode mode)
QString toString(FormattingOptions options) const const
QUuid createUuid()
QString toString(StringFormat mode) const const
QString toString() const const
QStringList toStringList() const const
QUrl toUrl() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:21:15 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.