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}
238
239#include "moc_connector.cpp"
240
241#include "moc_connector_p.cpp"
@ 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)
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 Fri Sep 6 2024 12:10:16 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.