File indexing completed on 2024-06-16 05:07:33

0001 /*
0002     SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "network.h"
0008 
0009 #include <QDateTime>
0010 #include <QDebug>
0011 #include <QFile>
0012 #include <QHash>
0013 #include <QProcess>
0014 #include <QStandardPaths>
0015 
0016 #include <KLocalizedString>
0017 #include <KPluginFactory>
0018 
0019 #include "networkconstants.h"
0020 #include "networklogging.h"
0021 
0022 using namespace KSysGuard;
0023 
0024 NetworkPlugin::NetworkPlugin(QObject *parent, const QVariantList &args)
0025     : ProcessDataProvider(parent, args)
0026 {
0027     const auto executable = NetworkConstants::HelperLocation;
0028     if (!QFile::exists(executable)) {
0029         qCWarning(KSYSGUARD_PLUGIN_NETWORK) << "Could not find ksgrd_network_helper";
0030         return;
0031     }
0032 
0033     qCDebug(KSYSGUARD_PLUGIN_NETWORK) << "Network plugin loading";
0034     qCDebug(KSYSGUARD_PLUGIN_NETWORK) << "Found helper at" << qPrintable(executable);
0035 
0036     m_inboundSensor = new ProcessAttribute(QStringLiteral("netInbound"), i18nc("@title", "Download Speed"), this);
0037     m_inboundSensor->setShortName(i18nc("@title", "Download"));
0038     m_inboundSensor->setUnit(KSysGuard::UnitByteRate);
0039     m_inboundSensor->setVisibleByDefault(true);
0040     m_outboundSensor = new ProcessAttribute(QStringLiteral("netOutbound"), i18nc("@title", "Upload Speed"), this);
0041     m_outboundSensor->setShortName(i18nc("@title", "Upload"));
0042     m_outboundSensor->setUnit(KSysGuard::UnitByteRate);
0043     m_outboundSensor->setVisibleByDefault(true);
0044 
0045     addProcessAttribute(m_inboundSensor);
0046     addProcessAttribute(m_outboundSensor);
0047 
0048     m_process = new QProcess(this);
0049     m_process->setProgram(executable);
0050 
0051     connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](int exitCode, QProcess::ExitStatus status) {
0052         if (exitCode != 0 || status != QProcess::NormalExit) {
0053             qCWarning(KSYSGUARD_PLUGIN_NETWORK) << "Helper process terminated abnormally:" << m_process->readAllStandardError().trimmed();
0054         }
0055     });
0056 
0057     connect(m_process, &QProcess::readyReadStandardOutput, this, [this]() {
0058         while (m_process->canReadLine()) {
0059             const QString line = QString::fromUtf8(m_process->readLine());
0060 
0061             // Each line consists of: timestamp|PID|pid|IN|in_bytes|OUT|out_bytes
0062             const auto parts = QStringView(line).split(QLatin1Char('|'), Qt::SkipEmptyParts);
0063             if (parts.size() < 7) {
0064                 continue;
0065             }
0066 
0067             long pid = parts.at(2).toLong();
0068 
0069             auto timeStamp = QDateTime::currentDateTimeUtc();
0070             timeStamp.setTime(QTime::fromString(parts.at(0).toString(), QStringLiteral("HH:mm:ss")));
0071 
0072             auto bytesIn = parts.at(4).toUInt();
0073             auto bytesOut = parts.at(6).toUInt();
0074 
0075             auto process = getProcess(pid);
0076             if (!process) {
0077                 return;
0078             }
0079 
0080             m_inboundSensor->setData(process, bytesIn);
0081             m_outboundSensor->setData(process, bytesOut);
0082         }
0083     });
0084 }
0085 
0086 void NetworkPlugin::handleEnabledChanged(bool enabled)
0087 {
0088     if (enabled) {
0089         qCDebug(KSYSGUARD_PLUGIN_NETWORK) << "Network plugin enabled, starting helper";
0090         m_process->start();
0091     } else {
0092         qCDebug(KSYSGUARD_PLUGIN_NETWORK) << "Network plugin disabled, stopping helper";
0093         m_process->terminate();
0094     }
0095 }
0096 
0097 K_PLUGIN_FACTORY_WITH_JSON(PluginFactory, "networkplugin.json", registerPlugin<NetworkPlugin>();)
0098 
0099 #include "network.moc"