ksysguarddaemon.cpp 7.46 KB
Newer Older
1
2
/*
    Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
3
    Copyright (c) 2020 David Redondo <kde@david-redondo.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "ksysguarddaemon.h"

23
24
#include <chrono>

25
26
27
28
29
30
31
32
33
34
35
36
37
#include <QDBusArgument>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusMetaType>
#include <QDBusServiceWatcher>

#include <QTimer>

#include "SensorPlugin.h"
#include "SensorObject.h"
#include "SensorContainer.h"
#include "SensorProperty.h"

38
#include <KDBusService>
39
40
41
42
43
44
45
#include <KPluginLoader>
#include <KPluginMetaData>
#include <KPluginFactory>

#include "ksysguard_ifaceadaptor.h"
#include "client.h"

46
47
constexpr auto UpdateRate = std::chrono::milliseconds{500};

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
KSysGuardDaemon::KSysGuardDaemon()
    : m_serviceWatcher(new QDBusServiceWatcher(this))
{
    qDBusRegisterMetaType<SensorData>();
    qDBusRegisterMetaType<SensorInfo>();
    qRegisterMetaType<SensorDataList>("SDL");
    qDBusRegisterMetaType<SensorDataList>();
    qDBusRegisterMetaType<SensorInfoMap>();
    qDBusRegisterMetaType<QStringList>();

    new KSysGuardDaemonAdaptor(this);

    m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
    connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &KSysGuardDaemon::onServiceDisconnected);

    auto timer = new QTimer(this);
64
    timer->setInterval(UpdateRate);
65
66
67
68
    connect(timer, &QTimer::timeout, this, &KSysGuardDaemon::sendFrame);
    timer->start();
}

69
70
71
72
73
74
75
KSysGuardDaemon::~KSysGuardDaemon()
{
    for (Client* c : m_clients) {
        delete c;
    }
}

76
void KSysGuardDaemon::init(ReplaceIfRunning replaceIfRunning)
77
78
{
    loadProviders();
79
80
81
    KDBusService::StartupOptions options = KDBusService::Unique;
    if (replaceIfRunning == ReplaceIfRunning::Replace) {
        options |= KDBusService::Replace;
82
    }
83
    QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportAdaptors);
84
85
    auto service = new KDBusService(options , this);
    service->setExitValue(1);
86
87
88
89
90
}

void KSysGuardDaemon::loadProviders()
{
    //instantiate all plugins
91
92
93
94
95
    QSet<QString> knownPlugins;
    std::for_each(m_providers.cbegin(), m_providers.cend(), [&knownPlugins] (const SensorPlugin *plugin) {
        knownPlugins.insert(plugin->providerName());
    });
    const auto plugins = KPluginLoader::instantiatePlugins(QStringLiteral("ksysguard"), [this, &knownPlugins](const KPluginMetaData &metaData) {
96
        auto providerName = metaData.rawData().value("providerName").toString();
97
        if (knownPlugins.contains(providerName)) {
98
99
            return false;
        }
100
        knownPlugins.insert(providerName);
101
102
        return true;
    }, this);
103

104
105
    for (auto object : plugins) {
        auto factory = qobject_cast<KPluginFactory*>(object);
106
        if (!factory) {
107
108
            qWarning() << "Plugin object" << object << "did not provide a proper KPluginFactory";
            continue;
109
        }
110
        auto provider = factory->create<SensorPlugin>(this);
111
        if (!provider) {
112
113
            qWarning() << "Plugin object" << object << "did not provide a proper SensorPlugin";
            continue;
114
115
        }
        registerProvider(provider);
116
    }
117
118
119
120
121
122
123

    if (m_providers.isEmpty()) {
        qWarning() << "No plugins found";
    }
}

void KSysGuardDaemon::registerProvider(SensorPlugin *provider) {
Arjen Hiemstra's avatar
Arjen Hiemstra committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    m_providers.append(provider);
    const auto containers = provider->containers();
    for (auto container : containers) {
        m_containers[container->id()] = container;
        connect(container, &SensorContainer::objectAdded, this, [this](SensorObject *obj) {
            for (auto sensor: obj->sensors()) {
                emit sensorAdded(sensor->path());
            }
        });
        connect(container, &SensorContainer::objectRemoved, this, [this](SensorObject *obj) {
            for (auto sensor: obj->sensors()) {
                emit sensorRemoved(sensor->path());
            }
        });
    }
139
140
141
142
143
144
}

SensorInfoMap KSysGuardDaemon::allSensors() const
{
    SensorInfoMap infoMap;
    for (auto c : qAsConst(m_containers)) {
145
146
147
148
        auto containerInfo = SensorInfo{};
        containerInfo.name = c->name();
        infoMap.insert(c->id(), containerInfo);

149
150
        const auto objects = c->objects();
        for(auto object : objects) {
151
152
153
154
            auto objectInfo = SensorInfo{};
            objectInfo.name = object->name();
            infoMap.insert(object->path(), objectInfo);

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
            const auto sensors = object->sensors();
            for (auto sensor : sensors) {
                infoMap[sensor->path()] = sensor->info();
            }
        }
    }
    return infoMap;
}

SensorInfoMap KSysGuardDaemon::sensors(const QStringList &sensorPaths) const
{
    SensorInfoMap si;
    for (const QString &path : sensorPaths) {
        if (auto sensor = findSensor(path)) {
            si[path] = sensor->info();
        }
    }
    return si;
}

void KSysGuardDaemon::subscribe(const QStringList &sensorIds)
{
    const QString sender = QDBusContext::message().service();
    m_serviceWatcher->addWatchedService(sender);

    Client *client = m_clients.value(sender);
    if (!client) {
        client = new Client(this, sender);
        m_clients[sender] = client;
    }
    client->subscribeSensors(sensorIds);
}

void KSysGuardDaemon::unsubscribe(const QStringList &sensorIds)
{
    const QString sender = QDBusContext::message().service();
    Client *client = m_clients.value(sender);
    if (!client) {
        return;
    }
    client->unsubscribeSensors(sensorIds);
}

SensorDataList KSysGuardDaemon::sensorData(const QStringList &sensorIds)
{
    SensorDataList sensorData;
    for (const QString &sensorId: sensorIds) {
        if (SensorProperty *sensorProperty = findSensor(sensorId)) {
            const QVariant value = sensorProperty->value();
            if (value.isValid()) {
                sensorData << SensorData(sensorId, value);
            }
        }
    }
    return sensorData;
}

SensorProperty *KSysGuardDaemon::findSensor(const QString &path) const
{
    int subsystemIndex = path.indexOf('/');
    int propertyIndex = path.lastIndexOf('/');

    const QString subsystem = path.left(subsystemIndex);
    const QString object = path.mid(subsystemIndex + 1, propertyIndex - (subsystemIndex + 1));
    const QString property = path.mid(propertyIndex + 1);

    auto c = m_containers.value(subsystem);
    if (!c) {
        return nullptr;
    }
    auto o = c->object(object);
    if (!o) {
        return nullptr;
    }
    return o->sensor(property);
}

void KSysGuardDaemon::onServiceDisconnected(const QString &service)
{
    delete m_clients.take(service);
235
236
237
    if (m_clients.isEmpty()) {
        QCoreApplication::quit();
    };
238
239
240
241
242
243
244
245
246
247
248
249
}

void KSysGuardDaemon::sendFrame()
{
    for (auto provider : qAsConst(m_providers)) {
        provider->update();
    }

    for (auto client: qAsConst(m_clients)) {
        client->sendFrame();
    }
}