Warning, file /plasma/ksystemstats/src/daemon.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org> 0003 SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "daemon.h" 0009 0010 #include <algorithm> 0011 #include <chrono> 0012 0013 #include <QDBusConnection> 0014 #include <QDBusMetaType> 0015 #include <QDBusServiceWatcher> 0016 0017 #include <QTimer> 0018 0019 #include <systemstats/DBusInterface.h> 0020 #include <systemstats/SensorPlugin.h> 0021 #include <systemstats/SensorObject.h> 0022 #include <systemstats/SensorContainer.h> 0023 #include <systemstats/SensorProperty.h> 0024 0025 #include <KPluginMetaData> 0026 #include <KPluginFactory> 0027 0028 #ifdef Q_OS_LINUX 0029 #include <sensors/sensors.h> 0030 #endif 0031 0032 #include "ksystemstats1adaptor.h" 0033 0034 #include "client.h" 0035 0036 using namespace Qt::StringLiterals; 0037 0038 constexpr auto UpdateRate = std::chrono::milliseconds{500}; 0039 0040 Daemon::Daemon() 0041 : m_serviceWatcher(new QDBusServiceWatcher(this)) 0042 { 0043 qDBusRegisterMetaType<KSysGuard::SensorData>(); 0044 qDBusRegisterMetaType<KSysGuard::SensorInfo>(); 0045 qRegisterMetaType<KSysGuard::SensorDataList>("SDL"); 0046 qDBusRegisterMetaType<KSysGuard::SensorDataList>(); 0047 qDBusRegisterMetaType<KSysGuard::SensorInfoMap>(); 0048 qDBusRegisterMetaType<QStringList>(); 0049 0050 new Ksystemstats1Adaptor(this); 0051 0052 m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); 0053 connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Daemon::onServiceDisconnected); 0054 0055 auto timer = new QTimer(this); 0056 timer->setInterval(UpdateRate); 0057 connect(timer, &QTimer::timeout, this, &Daemon::sendFrame); 0058 timer->start(); 0059 } 0060 0061 Daemon::~Daemon() 0062 { 0063 for (Client* c : m_clients) { 0064 delete c; 0065 } 0066 #ifdef Q_OS_LINUX 0067 sensors_cleanup(); 0068 #endif 0069 } 0070 0071 bool Daemon::init(ReplaceIfRunning replaceIfRunning) 0072 { 0073 #ifdef Q_OS_LINUX 0074 sensors_init(nullptr); 0075 #endif 0076 loadProviders(); 0077 0078 QDBusConnection::sessionBus().registerObject(KSysGuard::SystemStats::ObjectPath, this, QDBusConnection::ExportAdaptors); 0079 0080 if (!registerDBusService(KSysGuard::SystemStats::ServiceName, replaceIfRunning)) { 0081 return false; 0082 } 0083 0084 return true; 0085 } 0086 0087 void Daemon::setQuitOnLastClientDisconnect(bool quit) 0088 { 0089 m_quitOnLastClientDisconnect = quit; 0090 } 0091 0092 void Daemon::loadProviders() 0093 { 0094 const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("ksystemstats")); 0095 if (plugins.isEmpty()) { 0096 qWarning() << "No plugins found"; 0097 } 0098 for (const KPluginMetaData &metaData : plugins) { 0099 auto provider = KPluginFactory::instantiatePlugin<KSysGuard::SensorPlugin>(metaData); 0100 if (!provider.plugin) { 0101 qWarning() << "Could not load plugin:" << metaData.pluginId() << "with file name" << metaData.fileName(); 0102 } else { 0103 registerProvider(provider.plugin); 0104 qDebug() << "Loaded plugin" << metaData.pluginId() << "from file" << metaData.fileName(); 0105 } 0106 } 0107 } 0108 0109 void Daemon::registerProvider(KSysGuard::SensorPlugin *provider) { 0110 bool alreadyHasProvider = std::any_of(m_providers.begin(), m_providers.end(), [provider](KSysGuard::SensorPlugin *provider2){ 0111 return provider2->providerName() == provider->providerName(); 0112 }); 0113 if (alreadyHasProvider) { 0114 qWarning() << "Provider" << provider->providerName() << "is already registered"; 0115 return; 0116 } 0117 m_providers.append(provider); 0118 const auto containers = provider->containers(); 0119 for (auto container : containers) { 0120 m_containers[container->id()] = container; 0121 connect(container, &KSysGuard::SensorContainer::objectAdded, this, [this](KSysGuard::SensorObject *obj) { 0122 for (auto sensor: obj->sensors()) { 0123 emit sensorAdded(sensor->path()); 0124 } 0125 }); 0126 connect(container, &KSysGuard::SensorContainer::objectRemoved, this, [this](KSysGuard::SensorObject *obj) { 0127 for (auto sensor: obj->sensors()) { 0128 emit sensorRemoved(sensor->path()); 0129 } 0130 }); 0131 } 0132 } 0133 0134 KSysGuard::SensorInfoMap Daemon::allSensors() const 0135 { 0136 KSysGuard::SensorInfoMap infoMap; 0137 for (auto c : std::as_const(m_containers)) { 0138 auto containerInfo = KSysGuard::SensorInfo{}; 0139 containerInfo.name = c->name(); 0140 infoMap.insert(c->id(), containerInfo); 0141 0142 const auto objects = c->objects(); 0143 for(auto object : objects) { 0144 auto objectInfo = KSysGuard::SensorInfo{}; 0145 objectInfo.name = object->name(); 0146 infoMap.insert(object->path(), objectInfo); 0147 0148 const auto sensors = object->sensors(); 0149 for (auto sensor : sensors) { 0150 infoMap[sensor->path()] = sensor->info(); 0151 } 0152 } 0153 } 0154 return infoMap; 0155 } 0156 0157 KSysGuard::SensorInfoMap Daemon::sensors(const QStringList &sensorPaths) const 0158 { 0159 KSysGuard::SensorInfoMap si; 0160 for (const QString &path : sensorPaths) { 0161 if (auto sensor = findSensor(path)) { 0162 si[path] = sensor->info(); 0163 } 0164 } 0165 return si; 0166 } 0167 0168 void Daemon::subscribe(const QStringList &sensorIds) 0169 { 0170 const QString sender = QDBusContext::message().service(); 0171 m_serviceWatcher->addWatchedService(sender); 0172 0173 Client *client = m_clients.value(sender); 0174 if (!client) { 0175 client = new Client(this, sender); 0176 m_clients[sender] = client; 0177 } 0178 client->subscribeSensors(sensorIds); 0179 } 0180 0181 void Daemon::unsubscribe(const QStringList &sensorIds) 0182 { 0183 const QString sender = QDBusContext::message().service(); 0184 Client *client = m_clients.value(sender); 0185 if (!client) { 0186 return; 0187 } 0188 client->unsubscribeSensors(sensorIds); 0189 } 0190 0191 KSysGuard::SensorDataList Daemon::sensorData(const QStringList &sensorIds) 0192 { 0193 KSysGuard::SensorDataList sensorData; 0194 for (const QString &sensorId: sensorIds) { 0195 if (KSysGuard::SensorProperty *sensorProperty = findSensor(sensorId)) { 0196 const QVariant value = sensorProperty->value(); 0197 if (value.isValid()) { 0198 sensorData << KSysGuard::SensorData(sensorId, value); 0199 } 0200 } 0201 } 0202 return sensorData; 0203 } 0204 0205 KSysGuard::SensorProperty *Daemon::findSensor(const QString &path) const 0206 { 0207 int subsystemIndex = path.indexOf('/'); 0208 int propertyIndex = path.lastIndexOf('/'); 0209 0210 const QString subsystem = path.left(subsystemIndex); 0211 const QString object = path.mid(subsystemIndex + 1, propertyIndex - (subsystemIndex + 1)); 0212 const QString property = path.mid(propertyIndex + 1); 0213 0214 auto c = m_containers.value(subsystem); 0215 if (!c) { 0216 return nullptr; 0217 } 0218 auto o = c->object(object); 0219 if (!o) { 0220 return nullptr; 0221 } 0222 return o->sensor(property); 0223 } 0224 0225 void Daemon::onServiceDisconnected(const QString &service) 0226 { 0227 if (service == KSysGuard::SystemStats::ServiceName) { 0228 return; 0229 } 0230 0231 delete m_clients.take(service); 0232 if (m_clients.isEmpty() && m_quitOnLastClientDisconnect) { 0233 QCoreApplication::quit(); 0234 }; 0235 } 0236 0237 bool Daemon::registerDBusService(const QString& serviceName, ReplaceIfRunning replace) 0238 { 0239 auto interface = QDBusConnection::sessionBus().interface(); 0240 0241 if (interface->isServiceRegistered(serviceName) && replace != ReplaceIfRunning::Replace) { 0242 qWarning() << "ksystemstats is already running"; 0243 return false; 0244 } 0245 0246 connect(interface, &QDBusConnectionInterface::serviceUnregistered, this, [](const QString &service) { 0247 if (service == KSysGuard::SystemStats::ServiceName) { 0248 QCoreApplication::instance()->quit(); 0249 } 0250 }); 0251 0252 auto result = interface->registerService(KSysGuard::SystemStats::ServiceName, QDBusConnectionInterface::ReplaceExistingService, QDBusConnectionInterface::AllowReplacement); 0253 if (result != QDBusConnectionInterface::ServiceRegistered) { 0254 qWarning() << "Could not register name" << KSysGuard::SystemStats::ServiceName; 0255 return false; 0256 } 0257 0258 return true; 0259 } 0260 0261 void Daemon::sendFrame() 0262 { 0263 for (auto provider : std::as_const(m_providers)) { 0264 provider->update(); 0265 } 0266 0267 for (auto client: std::as_const(m_clients)) { 0268 client->sendFrame(); 0269 } 0270 } 0271 0272 #include "moc_daemon.cpp"