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) {
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}
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)
QNetworkReply * deleteResource(const QNetworkRequest &request)
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
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)
void deleteLater()
void setParent(QObject *parent)
QVariant value(QAnyStringView key) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QByteArray toUtf8() const const
bool isValid() const const
QString path(ComponentFormattingOptions options) const const
void setPath(const QString &path, ParsingMode mode)
void setQuery(const QString &query, ParsingMode mode)
void setScheme(const QString &scheme)
QString toString(FormattingOptions options) const const
QString toString() const const
void close(QWebSocketProtocol::CloseCode closeCode, const QString &reason)
QString errorString() const const
void open(const QNetworkRequest &request)
QAbstractSocket::SocketState state() const const
void stateChanged(QAbstractSocket::SocketState state)
void textMessageReceived(const QString &message)
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.