KUnifiedPush

connector.cpp
1/*
2 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "connector.h"
7#include "connector_p.h"
8#include "logging.h"
9
10#include "../shared/unifiedpush-constants.h"
11#include "../shared/connectorutils_p.h"
12
13#include <QFile>
14#include <QSettings>
15#include <QStandardPaths>
16#include <QUuid>
17
18using namespace KUnifiedPush;
19
20ConnectorPrivate::ConnectorPrivate(Connector *qq)
21 : QObject(qq)
22 , q(qq)
23{
24 init();
25}
26
27ConnectorPrivate::~ConnectorPrivate()
28{
29 deinit();
30}
31
32void ConnectorPrivate::Message(const QString &token, const QByteArray &message, const QString &messageIdentifier)
33{
34 qCDebug(Log) << token << message << messageIdentifier;
35 if (token != m_token) {
36 qCWarning(Log) << "Got message for a different token??";
37 return;
38 }
39 Q_EMIT q->messageReceived(message);
40}
41
42void ConnectorPrivate::NewEndpoint(const QString &token, const QString &endpoint)
43{
44 qCDebug(Log) << token << endpoint;
45 if (token != m_token) {
46 qCWarning(Log) << "Got new endpoint for a different token??";
47 return;
48 }
49
50 // ### Gotify workaround...
51 QString actuallyWorkingEndpoint(endpoint);
52 actuallyWorkingEndpoint.replace(QLatin1String("/UP?"), QLatin1String("/message?"));
53
54 if (m_endpoint != actuallyWorkingEndpoint) {
55 m_endpoint = actuallyWorkingEndpoint;
56 Q_EMIT q->endpointChanged(m_endpoint);
57 }
58 storeState();
59 setState(Connector::Registered);
60}
61
62void ConnectorPrivate::Unregistered(const QString &token)
63{
64 qCDebug(Log) << token;
65
66 // confirmation of our unregistration request
67 if (token.isEmpty()) {
68 m_token.clear();
69 m_endpoint.clear();
70 Q_EMIT q->endpointChanged(m_endpoint);
71 const auto res = QFile::remove(stateFile());
72 qCDebug(Log) << "Removing" << stateFile() << res;
74 }
75
76 // we got unregistered by the distributor
77 else if (token == m_token) {
78 m_endpoint.clear();
79 Q_EMIT q->endpointChanged(m_endpoint);
81 storeState();
82 }
83
84 if (m_currentCommand == Command::Unregister) {
85 m_currentCommand = Command::None;
86 }
87 processNextCommand();
88}
89
90QString ConnectorPrivate::stateFile() const
91{
92 return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/kunifiedpush-") + m_serviceName;
93}
94
95void ConnectorPrivate::loadState()
96{
97 QSettings settings(stateFile(), QSettings::IniFormat);
98 settings.beginGroup(QStringLiteral("Client"));
99 m_token = settings.value(QStringLiteral("Token"), QString()).toString();
100 m_endpoint = settings.value(QStringLiteral("Endpoint"), QString()).toString();
101 m_description = settings.value(QStringLiteral("Description"), QString()).toString();
102}
103
104void ConnectorPrivate::storeState() const
105{
106 QSettings settings(stateFile(), QSettings::IniFormat);
107 settings.beginGroup(QStringLiteral("Client"));
108 settings.setValue(QStringLiteral("Token"), m_token);
109 settings.setValue(QStringLiteral("Endpoint"), m_endpoint);
110 settings.setValue(QStringLiteral("Description"), m_description);
111}
112
113void ConnectorPrivate::setDistributor(const QString &distServiceName)
114{
115 if (distServiceName.isEmpty()) {
116 qCWarning(Log) << "No UnifiedPush distributor found.";
117 setState(Connector::NoDistributor);
118 return;
119 }
120
121 doSetDistributor(distServiceName);
122 qCDebug(Log) << "Selected distributor" << distServiceName;
123 setState(Connector::Unregistered);
124
125 if (!m_token.isEmpty()) { // re-register if we have been registered before
126 q->registerClient(m_description);
127 }
128}
129
130void ConnectorPrivate::setState(Connector::State state)
131{
132 qCDebug(Log) << state;
133 if (m_state == state) {
134 return;
135 }
136
137 m_state = state;
138 Q_EMIT q->stateChanged(m_state);
139}
140
141void ConnectorPrivate::addCommand(ConnectorPrivate::Command cmd)
142{
143 // ignore new commands that are already in the queue or cancel each other out
144 if (!m_commandQueue.empty()) {
145 if (m_commandQueue.back() == cmd) {
146 return;
147 }
148 if ((m_commandQueue.back() == Command::Register && cmd == Command::Unregister) || (m_commandQueue.back() == Command::Unregister && cmd == Command::Register)) {
149 m_commandQueue.pop_back();
150 return;
151 }
152 } else if (m_currentCommand == cmd) {
153 return;
154 }
155
156 m_commandQueue.push_back(cmd);
157 processNextCommand();
158}
159
160void ConnectorPrivate::processNextCommand()
161{
162 if (m_currentCommand != Command::None || !hasDistributor() || m_commandQueue.empty()) {
163 return;
164 }
165
166 m_currentCommand = m_commandQueue.front();
167 m_commandQueue.pop_front();
168
169 switch (m_currentCommand) {
170 case Command::None:
171 break;
172 case Command::Register:
173 {
174 if (m_state == Connector::Registered) {
175 m_currentCommand = Command::None;
176 break;
177 }
178 setState(Connector::Registering);
179 if (m_token.isEmpty()) {
180 m_token = QUuid::createUuid().toString();
181 }
182 qCDebug(Log) << "Registering";
183 doRegister();
184 break;
185 }
187 if (m_state == Connector::Unregistered) {
188 m_currentCommand = Command::None;
189 break;
190 }
191 qCDebug(Log) << "Unregistering";
192 doUnregister();
193 break;
194 }
195
196 processNextCommand();
197}
198
199
200Connector::Connector(const QString &serviceName, QObject *parent)
201 : QObject(parent)
202 , d(new ConnectorPrivate(this))
203{
204 d->m_serviceName = serviceName;
205 if (d->m_serviceName.isEmpty()) {
206 qCWarning(Log) << "empty D-Bus service name!";
207 return;
208 }
209
210 d->loadState();
211 d->setDistributor(ConnectorUtils::selectDistributor());
212}
213
214Connector::~Connector() = default;
215
216QString Connector::endpoint() const
217{
218 return d->m_endpoint;
219}
220
221void Connector::registerClient(const QString &description)
222{
223 qCDebug(Log) << d->m_state;
224 d->m_description = description;
225 d->addCommand(ConnectorPrivate::Command::Register);
226}
227
229{
230 qCDebug(Log) << d->m_state;
231 d->addCommand(ConnectorPrivate::Command::Unregister);
232}
233
234Connector::State Connector::state() const
235{
236 return d->m_state;
237}
@ Unregister
unregistration requested by client
Definition command.h:22
Client connector to UnifiedPush.
Definition connector.h:25
Connector(const QString &serviceName, QObject *parent=nullptr)
Create a new connector instance.
void unregisterClient()
Unregister this client.
State
Connector state.
Definition connector.h:58
@ NoDistributor
Connector cannot find a UnifiedPush distributor to register at.
Definition connector.h:62
@ Registering
Connector is registering with the push provider.
Definition connector.h:60
@ Registered
Connector is registered and thus operational.
Definition connector.h:61
@ Unregistered
Connector is not yet registered, or explicitly unregistered.
Definition connector.h:59
void registerClient(const QString &description)
Register this client.
Client-side integration with UnifiedPush.
Definition connector.h:16
QCA_EXPORT void init()
QCA_EXPORT void deinit()
bool remove()
QString writableLocation(StandardLocation type)
void clear()
bool isEmpty() const const
QUuid createUuid()
QString toString(StringFormat mode) 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.