File indexing completed on 2025-02-16 04:23:13
0001 /* 0002 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "ntfypushprovider.h" 0007 #include "client.h" 0008 #include "logging.h" 0009 #include "message.h" 0010 0011 #include <QJsonDocument> 0012 #include <QJsonObject> 0013 #include <QNetworkReply> 0014 #include <QSettings> 0015 #include <QUrlQuery> 0016 #include <QUuid> 0017 0018 using namespace KUnifiedPush; 0019 0020 NtfyPushProvider::NtfyPushProvider(QObject *parent) 0021 : AbstractPushProvider(Id, parent) 0022 { 0023 connect(&m_sseStream, &ServerSentEventsStream::messageReceived, this, [this](const SSEMessage &sse) { 0024 qCDebug(Log) << sse.event << sse.data; 0025 if (sse.event.isEmpty()) { 0026 QJsonObject msgObj = QJsonDocument::fromJson(sse.data).object(); 0027 Message msg; 0028 msg.clientRemoteId = msgObj.value(QLatin1String("topic")).toString(); 0029 msg.content = msgObj.value(QLatin1String("message")).toString().toUtf8(); 0030 if (msgObj.value(QLatin1String("encoding")).toString() == QLatin1String("base64")) { 0031 msg.content = QByteArray::fromBase64(msg.content); 0032 } 0033 m_lastMessageId = msgObj.value(QLatin1String("id")).toString(); 0034 Q_EMIT messageReceived(msg); 0035 storeState(); 0036 } 0037 }); 0038 } 0039 0040 NtfyPushProvider::~NtfyPushProvider() = default; 0041 0042 bool NtfyPushProvider::loadSettings(const QSettings &settings) 0043 { 0044 m_url = settings.value(QStringLiteral("Url"), QUrl()).toUrl(); 0045 0046 QSettings internal; 0047 internal.beginGroup(QLatin1String(providerId()) + QLatin1String("-internal")); 0048 m_topics = internal.value(QStringLiteral("Topics"), QStringList()).toStringList(); 0049 m_lastMessageId = internal.value(QStringLiteral("LastMessageId"), QString()).toString(); 0050 0051 return m_url.isValid(); 0052 } 0053 0054 void NtfyPushProvider::connectToProvider() 0055 { 0056 doConnectToProvider(); 0057 Q_EMIT connected(); 0058 } 0059 0060 void NtfyPushProvider::disconnectFromProvider() 0061 { 0062 if (m_sseReply) { 0063 m_sseReply->abort(); 0064 } 0065 Q_EMIT disconnected(NoError); 0066 } 0067 0068 void NtfyPushProvider::registerClient(const Client &client) 0069 { 0070 const QString topic = QLatin1String("upk") + QUuid::createUuid().toString(QUuid::Id128); 0071 auto newClient = client; 0072 newClient.remoteId = topic; 0073 0074 QUrl endpoint = m_url; 0075 auto path = endpoint.path(); 0076 path += QLatin1Char('/') + topic; 0077 endpoint.setPath(path); 0078 newClient.endpoint = endpoint.toString(); 0079 0080 m_topics.push_back(topic); 0081 storeState(); 0082 doConnectToProvider(); 0083 Q_EMIT clientRegistered(newClient); 0084 } 0085 0086 void NtfyPushProvider::unregisterClient(const Client &client) 0087 { 0088 m_topics.removeAll(client.remoteId); 0089 storeState(); 0090 doConnectToProvider(); 0091 Q_EMIT clientUnregistered(client); 0092 } 0093 0094 void NtfyPushProvider::doConnectToProvider() 0095 { 0096 if (m_sseReply) { 0097 m_sseReply->abort(); 0098 } 0099 0100 if (m_topics.empty()) { 0101 return; 0102 } 0103 0104 QUrl url = m_url; 0105 QString path = url.path(); 0106 path += QLatin1Char('/') + m_topics.join(QLatin1Char(',')) + QLatin1String("/sse"); 0107 url.setPath(path); 0108 QUrlQuery query; 0109 query.addQueryItem(QStringLiteral("up"), QStringLiteral("1")); 0110 query.addQueryItem(QStringLiteral("since"), m_lastMessageId.isEmpty() ? QStringLiteral("all") : m_lastMessageId); 0111 url.setQuery(query); 0112 qCDebug(Log) << url; 0113 0114 auto reply = nam()->get(QNetworkRequest(url)); 0115 connect(reply, &QNetworkReply::finished, this, [reply, this]() { 0116 reply->deleteLater(); 0117 if (reply->error() == QNetworkReply::OperationCanceledError) { 0118 return; // we triggered this ourselves 0119 } 0120 qCDebug(Log) << reply->error() << reply->errorString(); 0121 Q_EMIT disconnected(TransientNetworkError, reply->errorString()); 0122 }); 0123 0124 m_sseReply = reply; 0125 m_sseStream.read(reply); 0126 } 0127 0128 void NtfyPushProvider::storeState() 0129 { 0130 QSettings settings; 0131 settings.beginGroup(QLatin1String(providerId()) + QLatin1String("-internal")); 0132 settings.setValue(QStringLiteral("Topics"), m_topics); 0133 settings.setValue(QStringLiteral("LastMessageId"), m_lastMessageId); 0134 }