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

KDE's Doxygen guidelines are available online.