File indexing completed on 2025-02-16 04:23:12
0001 /* 0002 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "gotifypushprovider.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 <QWebSocket> 0017 0018 using namespace KUnifiedPush; 0019 0020 GotifyPushProvider::GotifyPushProvider(QObject *parent) 0021 : AbstractPushProvider(Id, parent) 0022 { 0023 qCDebug(Log); 0024 } 0025 0026 bool GotifyPushProvider::loadSettings(const QSettings &settings) 0027 { 0028 m_clientToken = settings.value(QStringLiteral("ClientToken"), QString()).toString(); 0029 m_url = QUrl(settings.value(QStringLiteral("Url"), QString()).toString()); 0030 qCDebug(Log) << m_clientToken << m_url; 0031 return m_url.isValid() && !m_clientToken.isEmpty(); 0032 } 0033 0034 void GotifyPushProvider::connectToProvider() 0035 { 0036 qCDebug(Log); 0037 m_socket = new QWebSocket(); 0038 m_socket->setParent(this); 0039 connect(m_socket, &QWebSocket::stateChanged, this, [this](auto state) { 0040 qCDebug(Log) << m_socket->state(); 0041 if (state == QAbstractSocket::ConnectedState) { 0042 Q_EMIT connected(); 0043 } else if (state == QAbstractSocket::UnconnectedState) { 0044 Q_EMIT disconnected(TransientNetworkError, m_socket->errorString()); 0045 m_socket->deleteLater(); 0046 } 0047 }); 0048 connect(m_socket, &QWebSocket::textMessageReceived, this, &GotifyPushProvider::wsMessageReceived); 0049 0050 auto wsUrl = m_url; 0051 if (wsUrl.scheme() == QLatin1String("https")) { 0052 wsUrl.setScheme(QStringLiteral("wss")); 0053 } else if (wsUrl.scheme() == QLatin1String("http")) { 0054 wsUrl.setScheme(QStringLiteral("ws")); 0055 } else { 0056 qCWarning(Log) << "Unknown URL scheme:" << m_url; 0057 Q_EMIT disconnected(ProviderRejected); 0058 return; 0059 } 0060 0061 auto path = wsUrl.path(); 0062 path += QLatin1String("/stream"); 0063 wsUrl.setPath(path); 0064 0065 QUrlQuery query(wsUrl); 0066 query.addQueryItem(QStringLiteral("token"), m_clientToken); 0067 wsUrl.setQuery(query); 0068 0069 m_socket->open(wsUrl); 0070 } 0071 0072 void GotifyPushProvider::disconnectFromProvider() 0073 { 0074 m_socket->close(); 0075 m_socket = nullptr; 0076 } 0077 0078 void GotifyPushProvider::wsMessageReceived(const QString &msg) 0079 { 0080 qCDebug(Log) << msg; 0081 const auto msgObj = QJsonDocument::fromJson(msg.toUtf8()).object(); 0082 Message m; 0083 m.clientRemoteId = QString::number(msgObj.value(QLatin1String("appid")).toInt()); 0084 m.content = msgObj.value(QLatin1String("message")).toString().toUtf8(); 0085 Q_EMIT messageReceived(m); 0086 } 0087 0088 void GotifyPushProvider::registerClient(const Client &client) 0089 { 0090 qCDebug(Log) << client.serviceName << client.token; 0091 0092 QUrl url = m_url; 0093 auto path = url.path(); 0094 path += QLatin1String("/application"); 0095 url.setPath(path); 0096 0097 QNetworkRequest req(url); 0098 req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json")); 0099 req.setRawHeader("X-Gotify-Key", m_clientToken.toUtf8()); 0100 0101 QJsonObject content; 0102 content.insert(QLatin1String("name"), client.serviceName); 0103 content.insert(QLatin1String("token"), client.token); 0104 0105 auto reply = nam()->post(req, QJsonDocument(content).toJson(QJsonDocument::Compact)); 0106 connect(reply, &QNetworkReply::finished, this, [reply, this, client]() { 0107 reply->deleteLater(); 0108 if (reply->error() != QNetworkReply::NoError) { 0109 Q_EMIT clientRegistered(client, TransientNetworkError, reply->errorString()); 0110 return; 0111 } 0112 0113 const auto replyObj = QJsonDocument::fromJson(reply->readAll()).object(); 0114 qCDebug(Log) << QJsonDocument(replyObj).toJson(QJsonDocument::Compact); 0115 0116 auto newClient = client; 0117 newClient.remoteId = QString::number(replyObj.value(QLatin1String("id")).toInt()); 0118 0119 QUrl endpointUrl = m_url; 0120 auto path = endpointUrl.path(); 0121 path += QLatin1String("/message"); 0122 endpointUrl.setPath(path); 0123 QUrlQuery query(endpointUrl); 0124 query.addQueryItem(QStringLiteral("token"), replyObj.value(QLatin1String("token")).toString()); 0125 endpointUrl.setQuery(query); 0126 newClient.endpoint = endpointUrl.toString(); 0127 0128 Q_EMIT clientRegistered(newClient); 0129 }); 0130 } 0131 0132 void GotifyPushProvider::unregisterClient(const Client &client) 0133 { 0134 qCDebug(Log) << client.serviceName << client.token << client.remoteId; 0135 0136 QUrl url = m_url; 0137 auto path = url.path(); 0138 path += QLatin1String("/application/") + client.remoteId; 0139 url.setPath(path); 0140 0141 QNetworkRequest req(url); 0142 req.setRawHeader("X-Gotify-Key", m_clientToken.toUtf8()); 0143 0144 auto reply = nam()->deleteResource(req); 0145 connect(reply, &QNetworkReply::finished, this, [reply, client, this]() { 0146 reply->deleteLater(); 0147 qCDebug(Log) << reply->errorString() << reply->readAll(); // TODO 0148 if (reply->error() != QNetworkReply::NoError) { 0149 Q_EMIT clientUnregistered(client, TransientNetworkError); 0150 } else { 0151 Q_EMIT clientUnregistered(client); 0152 } 0153 }); 0154 }