KUnifiedPush

gotifypushprovider.cpp
1/*
2 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "gotifypushprovider.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 <QWebSocket>
17
18using namespace KUnifiedPush;
19
20GotifyPushProvider::GotifyPushProvider(QObject *parent)
21 : AbstractPushProvider(Id, parent)
22{
23 qCDebug(Log);
24}
25
27{
28 m_clientToken = settings.value(QStringLiteral("ClientToken"), QString()).toString();
29 m_url = QUrl(settings.value(QStringLiteral("Url"), QString()).toString());
30 qCDebug(Log) << m_clientToken << m_url;
31 return m_url.isValid() && !m_clientToken.isEmpty();
32}
33
35{
36 qCDebug(Log);
37 m_socket = new QWebSocket();
38 m_socket->setParent(this);
39 connect(m_socket, &QWebSocket::stateChanged, this, [this](auto state) {
40 qCDebug(Log) << m_socket->state();
43 } else if (state == QAbstractSocket::UnconnectedState) {
44 Q_EMIT disconnected(TransientNetworkError, m_socket->errorString());
45 m_socket->deleteLater();
46 }
47 });
48 connect(m_socket, &QWebSocket::textMessageReceived, this, &GotifyPushProvider::wsMessageReceived);
49
50 auto wsUrl = m_url;
51 if (wsUrl.scheme() == QLatin1String("https")) {
52 wsUrl.setScheme(QStringLiteral("wss"));
53 } else if (wsUrl.scheme() == QLatin1String("http")) {
54 wsUrl.setScheme(QStringLiteral("ws"));
55 } else {
56 qCWarning(Log) << "Unknown URL scheme:" << m_url;
58 return;
59 }
60
61 auto path = wsUrl.path();
62 path += QLatin1String("/stream");
63 wsUrl.setPath(path);
64
65 QUrlQuery query(wsUrl);
66 query.addQueryItem(QStringLiteral("token"), m_clientToken);
67 wsUrl.setQuery(query);
68
69 m_socket->open(wsUrl);
70}
71
73{
74 m_socket->close();
75 m_socket = nullptr;
76}
77
78void GotifyPushProvider::wsMessageReceived(const QString &msg)
79{
80 qCDebug(Log) << msg;
81 const auto msgObj = QJsonDocument::fromJson(msg.toUtf8()).object();
82 Message m;
83 m.clientRemoteId = QString::number(msgObj.value(QLatin1String("appid")).toInt());
84 m.content = msgObj.value(QLatin1String("message")).toString().toUtf8();
86}
87
89{
90 qCDebug(Log) << client.serviceName << client.token;
91
92 QUrl url = m_url;
93 auto path = url.path();
94 path += QLatin1String("/application");
95 url.setPath(path);
96
97 QNetworkRequest req(url);
98 req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));
99 req.setRawHeader("X-Gotify-Key", m_clientToken.toUtf8());
100
101 QJsonObject content;
102 content.insert(QLatin1String("name"), client.serviceName);
103 content.insert(QLatin1String("token"), client.token);
104
105 auto reply = nam()->post(req, QJsonDocument(content).toJson(QJsonDocument::Compact));
106 connect(reply, &QNetworkReply::finished, this, [reply, this, client]() {
107 reply->deleteLater();
108 if (reply->error() != QNetworkReply::NoError) {
109 Q_EMIT clientRegistered(client, TransientNetworkError, reply->errorString());
110 return;
111 }
112
113 const auto replyObj = QJsonDocument::fromJson(reply->readAll()).object();
114 qCDebug(Log) << QJsonDocument(replyObj).toJson(QJsonDocument::Compact);
115
116 auto newClient = client;
117 newClient.remoteId = QString::number(replyObj.value(QLatin1String("id")).toInt());
118
119 QUrl endpointUrl = m_url;
120 auto path = endpointUrl.path();
121 path += QLatin1String("/message");
122 endpointUrl.setPath(path);
123 QUrlQuery query(endpointUrl);
124 query.addQueryItem(QStringLiteral("token"), replyObj.value(QLatin1String("token")).toString());
125 endpointUrl.setQuery(query);
126 newClient.endpoint = endpointUrl.toString();
127
128 Q_EMIT clientRegistered(newClient);
129 });
130}
131
133{
134 qCDebug(Log) << client.serviceName << client.token << client.remoteId;
135
136 QUrl url = m_url;
137 auto path = url.path();
138 path += QLatin1String("/application/") + client.remoteId;
139 url.setPath(path);
140
141 QNetworkRequest req(url);
142 req.setRawHeader("X-Gotify-Key", m_clientToken.toUtf8());
143
144 auto reply = nam()->deleteResource(req);
145 connect(reply, &QNetworkReply::finished, this, [reply, client, this]() {
146 reply->deleteLater();
147 qCDebug(Log) << reply->errorString() << reply->readAll(); // TODO
148 if (reply->error() != QNetworkReply::NoError) {
150 } else {
152 }
153 });
154}
155
156#include "moc_gotifypushprovider.cpp"
Base class for push provider protocol implementations.
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
Information about a registered client.
Definition client.h:19
void unregisterClient(const Client &client) override
Unregister a client from the provider.
void connectToProvider() override
Attempt to establish a connection to the push provider.
void registerClient(const Client &client) override
Register a new client with the provider.
bool loadSettings(const QSettings &settings) override
Load connection settings.
void disconnectFromProvider() override
Disconnect and existing connection to the push provider.
A received push notification message.
Definition message.h:15
Client-side integration with UnifiedPush.
Definition connector.h:16
int64_t Id
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QByteArray toJson(JsonFormat format) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
void setHeader(KnownHeaders header, const QVariant &value)
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant value(QAnyStringView key) const const
QString number(double n, char format, int precision)
QByteArray toUtf8() 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
QString toString() const const
void stateChanged(QAbstractSocket::SocketState state)
void textMessageReceived(const QString &message)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Thu Jan 23 2025 19:01:03 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.