File indexing completed on 2024-05-05 17:34:41
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/SensorPlugin.h> 0020 #include <systemstats/SensorObject.h> 0021 #include <systemstats/SensorContainer.h> 0022 #include <systemstats/SensorProperty.h> 0023 0024 #include <KDBusService> 0025 #include <KPluginMetaData> 0026 #include <KPluginFactory> 0027 0028 #ifdef Q_OS_LINUX 0029 #include <sensors/sensors.h> 0030 #endif 0031 0032 #include "ksystemstatsadaptor.h" 0033 0034 #include "client.h" 0035 0036 constexpr auto UpdateRate = std::chrono::milliseconds{500}; 0037 0038 Daemon::Daemon() 0039 : m_serviceWatcher(new QDBusServiceWatcher(this)) 0040 { 0041 qDBusRegisterMetaType<KSysGuard::SensorData>(); 0042 qDBusRegisterMetaType<KSysGuard::SensorInfo>(); 0043 qRegisterMetaType<KSysGuard::SensorDataList>("SDL"); 0044 qDBusRegisterMetaType<KSysGuard::SensorDataList>(); 0045 qDBusRegisterMetaType<KSysGuard::SensorInfoMap>(); 0046 qDBusRegisterMetaType<QStringList>(); 0047 0048 new KsystemstatsAdaptor(this); 0049 0050 m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); 0051 connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Daemon::onServiceDisconnected); 0052 0053 auto timer = new QTimer(this); 0054 timer->setInterval(UpdateRate); 0055 connect(timer, &QTimer::timeout, this, &Daemon::sendFrame); 0056 timer->start(); 0057 } 0058 0059 Daemon::~Daemon() 0060 { 0061 for (Client* c : m_clients) { 0062 delete c; 0063 } 0064 #ifdef Q_OS_LINUX 0065 sensors_cleanup(); 0066 #endif 0067 } 0068 0069 void Daemon::init(ReplaceIfRunning replaceIfRunning) 0070 { 0071 #ifdef Q_OS_LINUX 0072 sensors_init(nullptr); 0073 #endif 0074 loadProviders(); 0075 KDBusService::StartupOptions options = KDBusService::Unique; 0076 if (replaceIfRunning == ReplaceIfRunning::Replace) { 0077 options |= KDBusService::Replace; 0078 } 0079 QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportAdaptors); 0080 auto service = new KDBusService(options , this); 0081 service->setExitValue(1); 0082 } 0083 0084 void Daemon::setQuitOnLastClientDisconnect(bool quit) 0085 { 0086 m_quitOnLastClientDisconnect = quit; 0087 } 0088 0089 void Daemon::loadProviders() 0090 { 0091 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("ksystemstats")); 0092 if (plugins.isEmpty()) { 0093 qWarning() << "No plugins found"; 0094 } 0095 for (const KPluginMetaData &metaData : plugins) { 0096 auto provider = KPluginFactory::instantiatePlugin<KSysGuard::SensorPlugin>(metaData); 0097 if (!provider.plugin) { 0098 qWarning() << "Could not load plugin:" << metaData.pluginId() << "with file name" << metaData.fileName(); 0099 } else { 0100 registerProvider(provider.plugin); 0101 qDebug() << "Loaded plugin" << metaData.pluginId() << "from file" << metaData.fileName(); 0102 } 0103 } 0104 } 0105 0106 void Daemon::registerProvider(KSysGuard::SensorPlugin *provider) { 0107 bool alreadyHasProvider = std::any_of(m_providers.begin(), m_providers.end(), [provider](KSysGuard::SensorPlugin *provider2){ 0108 return provider2->providerName() == provider->providerName(); 0109 }); 0110 if (alreadyHasProvider) { 0111 qWarning() << "Provider" << provider->providerName() << "is already registered"; 0112 return; 0113 } 0114 m_providers.append(provider); 0115 const auto containers = provider->containers(); 0116 for (auto container : containers) { 0117 m_containers[container->id()] = container; 0118 connect(container, &KSysGuard::SensorContainer::objectAdded, this, [this](KSysGuard::SensorObject *obj) { 0119 for (auto sensor: obj->sensors()) { 0120 emit sensorAdded(sensor->path()); 0121 } 0122 }); 0123 connect(container, &KSysGuard::SensorContainer::objectRemoved, this, [this](KSysGuard::SensorObject *obj) { 0124 for (auto sensor: obj->sensors()) { 0125 emit sensorRemoved(sensor->path()); 0126 } 0127 }); 0128 } 0129 } 0130 0131 KSysGuard::SensorInfoMap Daemon::allSensors() const 0132 { 0133 KSysGuard::SensorInfoMap infoMap; 0134 for (auto c : qAsConst(m_containers)) { 0135 auto containerInfo = KSysGuard::SensorInfo{}; 0136 containerInfo.name = c->name(); 0137 infoMap.insert(c->id(), containerInfo); 0138 0139 const auto objects = c->objects(); 0140 for(auto object : objects) { 0141 auto objectInfo = KSysGuard::SensorInfo{}; 0142 objectInfo.name = object->name(); 0143 infoMap.insert(object->path(), objectInfo); 0144 0145 const auto sensors = object->sensors(); 0146 for (auto sensor : sensors) { 0147 infoMap[sensor->path()] = sensor->info(); 0148 } 0149 } 0150 } 0151 return infoMap; 0152 } 0153 0154 KSysGuard::SensorInfoMap Daemon::sensors(const QStringList &sensorPaths) const 0155 { 0156 KSysGuard::SensorInfoMap si; 0157 for (const QString &path : sensorPaths) { 0158 if (auto sensor = findSensor(path)) { 0159 si[path] = sensor->info(); 0160 } 0161 } 0162 return si; 0163 } 0164 0165 void Daemon::subscribe(const QStringList &sensorIds) 0166 { 0167 const QString sender = QDBusContext::message().service(); 0168 m_serviceWatcher->addWatchedService(sender); 0169 0170 Client *client = m_clients.value(sender); 0171 if (!client) { 0172 client = new Client(this, sender); 0173 m_clients[sender] = client; 0174 } 0175 client->subscribeSensors(sensorIds); 0176 } 0177 0178 void Daemon::unsubscribe(const QStringList &sensorIds) 0179 { 0180 const QString sender = QDBusContext::message().service(); 0181 Client *client = m_clients.value(sender); 0182 if (!client) { 0183 return; 0184 } 0185 client->unsubscribeSensors(sensorIds); 0186 } 0187 0188 KSysGuard::SensorDataList Daemon::sensorData(const QStringList &sensorIds) 0189 { 0190 KSysGuard::SensorDataList sensorData; 0191 for (const QString &sensorId: sensorIds) { 0192 if (KSysGuard::SensorProperty *sensorProperty = findSensor(sensorId)) { 0193 const QVariant value = sensorProperty->value(); 0194 if (value.isValid()) { 0195 sensorData << KSysGuard::SensorData(sensorId, value); 0196 } 0197 } 0198 } 0199 return sensorData; 0200 } 0201 0202 KSysGuard::SensorProperty *Daemon::findSensor(const QString &path) const 0203 { 0204 int subsystemIndex = path.indexOf('/'); 0205 int propertyIndex = path.lastIndexOf('/'); 0206 0207 const QString subsystem = path.left(subsystemIndex); 0208 const QString object = path.mid(subsystemIndex + 1, propertyIndex - (subsystemIndex + 1)); 0209 const QString property = path.mid(propertyIndex + 1); 0210 0211 auto c = m_containers.value(subsystem); 0212 if (!c) { 0213 return nullptr; 0214 } 0215 auto o = c->object(object); 0216 if (!o) { 0217 return nullptr; 0218 } 0219 return o->sensor(property); 0220 } 0221 0222 void Daemon::onServiceDisconnected(const QString &service) 0223 { 0224 delete m_clients.take(service); 0225 if (m_clients.isEmpty() && m_quitOnLastClientDisconnect) { 0226 QCoreApplication::quit(); 0227 }; 0228 } 0229 0230 void Daemon::sendFrame() 0231 { 0232 for (auto provider : qAsConst(m_providers)) { 0233 provider->update(); 0234 } 0235 0236 for (auto client: qAsConst(m_clients)) { 0237 client->sendFrame(); 0238 } 0239 }