File indexing completed on 2024-11-17 04:18:46
0001 /* 0002 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "connector.h" 0007 #include "connector_p.h" 0008 #include "logging.h" 0009 0010 #include "../shared/unifiedpush-constants.h" 0011 #include "../shared/connectorutils_p.h" 0012 0013 #include <QFile> 0014 #include <QSettings> 0015 #include <QStandardPaths> 0016 #include <QUuid> 0017 0018 using namespace KUnifiedPush; 0019 0020 ConnectorPrivate::ConnectorPrivate(Connector *qq) 0021 : QObject(qq) 0022 , q(qq) 0023 { 0024 init(); 0025 } 0026 0027 ConnectorPrivate::~ConnectorPrivate() 0028 { 0029 deinit(); 0030 } 0031 0032 void ConnectorPrivate::Message(const QString &token, const QByteArray &message, const QString &messageIdentifier) 0033 { 0034 qCDebug(Log) << token << message << messageIdentifier; 0035 if (token != m_token) { 0036 qCWarning(Log) << "Got message for a different token??"; 0037 return; 0038 } 0039 Q_EMIT q->messageReceived(message); 0040 } 0041 0042 void ConnectorPrivate::NewEndpoint(const QString &token, const QString &endpoint) 0043 { 0044 qCDebug(Log) << token << endpoint; 0045 if (token != m_token) { 0046 qCWarning(Log) << "Got new endpoint for a different token??"; 0047 return; 0048 } 0049 0050 // ### Gotify workaround... 0051 QString actuallyWorkingEndpoint(endpoint); 0052 actuallyWorkingEndpoint.replace(QLatin1String("/UP?"), QLatin1String("/message?")); 0053 0054 if (m_endpoint != actuallyWorkingEndpoint) { 0055 m_endpoint = actuallyWorkingEndpoint; 0056 Q_EMIT q->endpointChanged(m_endpoint); 0057 } 0058 storeState(); 0059 setState(Connector::Registered); 0060 } 0061 0062 void ConnectorPrivate::Unregistered(const QString &token) 0063 { 0064 qCDebug(Log) << token; 0065 0066 // confirmation of our unregistration request 0067 if (token.isEmpty()) { 0068 m_token.clear(); 0069 m_endpoint.clear(); 0070 Q_EMIT q->endpointChanged(m_endpoint); 0071 const auto res = QFile::remove(stateFile()); 0072 qCDebug(Log) << "Removing" << stateFile() << res; 0073 setState(Connector::Unregistered); 0074 } 0075 0076 // we got unregistered by the distributor 0077 else if (token == m_token) { 0078 m_endpoint.clear(); 0079 Q_EMIT q->endpointChanged(m_endpoint); 0080 setState(Connector::Unregistered); 0081 storeState(); 0082 } 0083 0084 if (m_currentCommand == Command::Unregister) { 0085 m_currentCommand = Command::None; 0086 } 0087 processNextCommand(); 0088 } 0089 0090 QString ConnectorPrivate::stateFile() const 0091 { 0092 return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/kunifiedpush-") + m_serviceName; 0093 } 0094 0095 void ConnectorPrivate::loadState() 0096 { 0097 QSettings settings(stateFile(), QSettings::IniFormat); 0098 settings.beginGroup(QStringLiteral("Client")); 0099 m_token = settings.value(QStringLiteral("Token"), QString()).toString(); 0100 m_endpoint = settings.value(QStringLiteral("Endpoint"), QString()).toString(); 0101 m_description = settings.value(QStringLiteral("Description"), QString()).toString(); 0102 } 0103 0104 void ConnectorPrivate::storeState() const 0105 { 0106 QSettings settings(stateFile(), QSettings::IniFormat); 0107 settings.beginGroup(QStringLiteral("Client")); 0108 settings.setValue(QStringLiteral("Token"), m_token); 0109 settings.setValue(QStringLiteral("Endpoint"), m_endpoint); 0110 settings.setValue(QStringLiteral("Description"), m_description); 0111 } 0112 0113 void ConnectorPrivate::setDistributor(const QString &distServiceName) 0114 { 0115 if (distServiceName.isEmpty()) { 0116 qCWarning(Log) << "No UnifiedPush distributor found."; 0117 setState(Connector::NoDistributor); 0118 return; 0119 } 0120 0121 doSetDistributor(distServiceName); 0122 qCDebug(Log) << "Selected distributor" << distServiceName; 0123 setState(Connector::Unregistered); 0124 0125 if (!m_token.isEmpty()) { // re-register if we have been registered before 0126 q->registerClient(m_description); 0127 } 0128 } 0129 0130 void ConnectorPrivate::setState(Connector::State state) 0131 { 0132 qCDebug(Log) << state; 0133 if (m_state == state) { 0134 return; 0135 } 0136 0137 m_state = state; 0138 Q_EMIT q->stateChanged(m_state); 0139 } 0140 0141 void ConnectorPrivate::addCommand(ConnectorPrivate::Command cmd) 0142 { 0143 // ignore new commands that are already in the queue or cancel each other out 0144 if (!m_commandQueue.empty()) { 0145 if (m_commandQueue.back() == cmd) { 0146 return; 0147 } 0148 if ((m_commandQueue.back() == Command::Register && cmd == Command::Unregister) || (m_commandQueue.back() == Command::Unregister && cmd == Command::Register)) { 0149 m_commandQueue.pop_back(); 0150 return; 0151 } 0152 } else if (m_currentCommand == cmd) { 0153 return; 0154 } 0155 0156 m_commandQueue.push_back(cmd); 0157 processNextCommand(); 0158 } 0159 0160 void ConnectorPrivate::processNextCommand() 0161 { 0162 if (m_currentCommand != Command::None || !hasDistributor() || m_commandQueue.empty()) { 0163 return; 0164 } 0165 0166 m_currentCommand = m_commandQueue.front(); 0167 m_commandQueue.pop_front(); 0168 0169 switch (m_currentCommand) { 0170 case Command::None: 0171 break; 0172 case Command::Register: 0173 { 0174 if (m_state == Connector::Registered) { 0175 m_currentCommand = Command::None; 0176 break; 0177 } 0178 setState(Connector::Registering); 0179 if (m_token.isEmpty()) { 0180 m_token = QUuid::createUuid().toString(); 0181 } 0182 qCDebug(Log) << "Registering"; 0183 doRegister(); 0184 break; 0185 } 0186 case Command::Unregister: 0187 if (m_state == Connector::Unregistered) { 0188 m_currentCommand = Command::None; 0189 break; 0190 } 0191 qCDebug(Log) << "Unregistering"; 0192 doUnregister(); 0193 break; 0194 } 0195 0196 processNextCommand(); 0197 } 0198 0199 0200 Connector::Connector(const QString &serviceName, QObject *parent) 0201 : QObject(parent) 0202 , d(new ConnectorPrivate(this)) 0203 { 0204 d->m_serviceName = serviceName; 0205 if (d->m_serviceName.isEmpty()) { 0206 qCWarning(Log) << "empty D-Bus service name!"; 0207 return; 0208 } 0209 0210 d->loadState(); 0211 d->setDistributor(ConnectorUtils::selectDistributor()); 0212 } 0213 0214 Connector::~Connector() = default; 0215 0216 QString Connector::endpoint() const 0217 { 0218 return d->m_endpoint; 0219 } 0220 0221 void Connector::registerClient(const QString &description) 0222 { 0223 qCDebug(Log) << d->m_state; 0224 d->m_description = description; 0225 d->addCommand(ConnectorPrivate::Command::Register); 0226 } 0227 0228 void Connector::unregisterClient() 0229 { 0230 qCDebug(Log) << d->m_state; 0231 d->addCommand(ConnectorPrivate::Command::Unregister); 0232 } 0233 0234 Connector::State Connector::state() const 0235 { 0236 return d->m_state; 0237 }