diff --git a/CMakeLists.txt b/CMakeLists.txt index 72b7a4a3..ee49dfa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,8 +59,15 @@ find_package( Svg Test Widgets) -find_package(KF6 ${KF6_MIN_VERSION} REQUIRED - COMPONENTS Config CoreAddons GuiAddons I18n Kirigami Notifications) +find_package( + KF6 ${KF6_MIN_VERSION} REQUIRED + COMPONENTS Config + CoreAddons + GuiAddons + I18n + Kirigami + Notifications + QuickCharts) find_package(nlohmann_json) if(NOT nlohmann_json_FOUND) set(JSON_BuildTests diff --git a/devenv.lock b/devenv.lock index 3e0a8908..8d2f5656 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,11 +3,11 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1720103481, + "lastModified": 1720450778, "owner": "cachix", "repo": "devenv", - "rev": "2e6c99cddaa420a75dfeeeab05039505589f97bd", - "treeHash": "a550f0f176fe7ebec232f597f386c9acd48fab05", + "rev": "c5cab22d9750a9aa88aa0946849903fb619be954", + "treeHash": "57cbb9bdfab73c1ce237805823d796d2d740dc5a", "type": "github" }, "original": { @@ -56,11 +56,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720058333, + "lastModified": 1720498663, "owner": "NixOS", "repo": "nixpkgs", - "rev": "6842b061970bf96965d66fcc86a28e1f719aae95", - "treeHash": "8242fa6deb9f449872fab664ba3c385b34f1f214", + "rev": "106e145e1d4583d1e2bb20e54947d15ad55e75e1", + "treeHash": "6bf41357602936b3ee747592c05cf7dbbb2adc69", "type": "github" }, "original": { @@ -72,16 +72,16 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1719957072, + "lastModified": 1720386169, "owner": "NixOS", "repo": "nixpkgs", - "rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", - "treeHash": "415bf0e03835797927c1b2cb46a557bcecc36673", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "treeHash": "b6085ddb8a212d9c4632f85255cc9f2034289465", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } @@ -96,11 +96,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1719259945, + "lastModified": 1720524665, "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07", - "treeHash": "1a76ff89a9d4017b48abbb1bad8837b35d604ffc", + "rev": "8d6a17d0cdf411c55f12602624df6368ad86fac1", + "treeHash": "88a5039b6281f4464d76016870def0016457bd14", "type": "github" }, "original": { diff --git a/devenv.nix b/devenv.nix index ba4fc5f1..f3cde667 100644 --- a/devenv.nix +++ b/devenv.nix @@ -23,6 +23,8 @@ kdePackages.qtbase kdePackages.qtdeclarative kdePackages.qtsvg + kdePackages.kquickcharts + kdePackages.kdeclarative nlohmann_json cmake-format cmake-lint diff --git a/flake.lock b/flake.lock index ceb9b41e..3b187f29 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1720087678, - "narHash": "sha256-uOhYJU3ldDKXYV+mFaXcPtyjq/UIMh/6SCuoVNU9rxM=", + "lastModified": 1720181791, + "narHash": "sha256-i4vJL12/AdyuQuviMMd1Hk2tsGt02hDNhA0Zj1m16N8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1afc5440469f94e7ed26e8648820971b102afdc3", + "rev": "4284c2b73c8bce4b46a6adf23e16d9e2ec8da4bb", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 15b98423..7d2ae223 100644 --- a/flake.nix +++ b/flake.nix @@ -53,6 +53,7 @@ kdePackages.qtbase kdePackages.qtdeclarative kdePackages.qtsvg + kdePackages.kquickcharts nlohmann_json cmake-format ]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca06915c..a50973a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,8 +18,6 @@ add_executable( app.cpp logging.cpp main.cpp - speed_statistics.cpp - statistics.cpp tray_icon.cpp icons/icons.qrc ui/ui.qrc diff --git a/src/main.cpp b/src/main.cpp index 647158db..7e76dfcb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,8 +18,6 @@ #include "logging.hpp" #include "peer_model.hpp" #include "preferences.hpp" -#include "speed_statistics.hpp" -#include "statistics.hpp" #include "taildrop_sender.hpp" #include "tailscale.hpp" #include "util.hpp" @@ -85,8 +83,6 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) qmlRegisterSingletonInstance("org.fkoehler.KTailctl", 1, 0, "Util", util); qmlRegisterSingletonInstance("org.fkoehler.KTailctl", 1, 0, "TaildropSender", taildropSender); - qmlRegisterType("org.fkoehler.KTailctl", 1, 0, "SpeedStatistics"); - qmlRegisterType("org.fkoehler.KTailctl", 1, 0, "Statistics"); qmlRegisterType("org.fkoehler.KTailctl", 1, 0, "KTailctlConfig"); engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); diff --git a/src/speed_statistics.cpp b/src/speed_statistics.cpp deleted file mode 100644 index 4c6ce9fd..00000000 --- a/src/speed_statistics.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: 2023 Fabian Köhler -#include "speed_statistics.hpp" - -#include - -SpeedStatistics::SpeedStatistics(QObject *parent) - : QObject(parent) - , mCapacity(4096L) -{ -} - -double SpeedStatistics::average(double window) const -{ - auto window_int = static_cast(window * 1000.); - - if (mValues.empty()) { - return 0.; - } - - auto iter_values = mValues.crbegin(); - auto iter_timestamps = mTimestamps.crbegin(); - auto average = 0.0; - auto samples = 0L; - while (iter_values != mValues.crend()) { - if (iter_timestamps->msecsTo(QDateTime::currentDateTime()) > window_int) { - break; - } - average += *iter_values; - ++samples; - ++iter_values; - ++iter_timestamps; - } - - if (samples == 0) { - return 0.; - } - - return average / static_cast(samples); -} -QVariantList SpeedStatistics::valuesVariant() const -{ - // return mValues as QVariantList - QVariantList list; - for (auto value : mValues) { - list.append(value); - } - return list; -} - -void SpeedStatistics::update(long transferred) -{ - auto now = QDateTime::currentDateTime(); - if (mLastTransferred >= 0) { - auto dy = static_cast(transferred - mLastTransferred); - auto dx = static_cast(mLastTimestamp.msecsTo(now)) / 1000.; - mValues.append(dy / dx); - mTimestamps.append(now); - - while (mValues.size() > mCapacity) { - mValues.removeFirst(); - mTimestamps.removeFirst(); - } - } - - emit refreshed(); - mLastTransferred = transferred; - mLastTimestamp = now; -} diff --git a/src/speed_statistics.hpp b/src/speed_statistics.hpp deleted file mode 100644 index 74e3e118..00000000 --- a/src/speed_statistics.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: 2023 Fabian Köhler -#ifndef KTAILCTL_SPEED_STATISTICS_HPP -#define KTAILCTL_SPEED_STATISTICS_HPP - -#include -#include -#include -#include - -class SpeedStatistics : public QObject -{ - Q_OBJECT - Q_PROPERTY(double average1Second READ average NOTIFY refreshed) - Q_PROPERTY(QVariantList values READ valuesVariant NOTIFY refreshed) - -private: - long mCapacity; - QList mTimestamps; - QList mValues; - long mLastTransferred{-1}; - QDateTime mLastTimestamp; - -public: - explicit SpeedStatistics(QObject *parent = nullptr); - virtual ~SpeedStatistics() = default; - - Q_INVOKABLE double average(double window = 1.) const; - QVariantList valuesVariant() const; - -public slots: - void update(long transferred); - -signals: - void refreshed(); -}; - -#endif /* KTAILCTL_SPEED_STATISTICS_HPP */ diff --git a/src/statistics.cpp b/src/statistics.cpp deleted file mode 100644 index 82a04cb3..00000000 --- a/src/statistics.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: 2023 Fabian Köhler -#include "statistics.hpp" -#include "libktailctl_wrapper.h" -#include "tailscale.hpp" - -#include -#include - -Q_LOGGING_CATEGORY(logcat_statistics, "org.fkoehler.KTailctl.Statistics") - -Statistics::Statistics(QObject *parent) - : QObject(parent) - , mTimerTotalSpeed(new QTimer(this)) - , mSpeedUpTotal(new SpeedStatistics(this)) - , mSpeedDownTotal(new SpeedStatistics(this)) -{ - // for (const Peer *peer : Tailscale::instance()->peers()) { - // auto iterUp = mSpeedUp.insert(peer->id(), new SpeedStatistics(this)); - // auto iterDown = mSpeedDown.insert(peer->id(), new SpeedStatistics(this)); - // iterUp.value()->update(peer->txBytes()); - // iterDown.value()->update(peer->rxBytes()); - - // QObject::connect(peer, &Peer::txBytesChanged, iterUp.value(), &SpeedStatistics::update); - // QObject::connect(peer, &Peer::rxBytesChanged, iterDown.value(), &SpeedStatistics::update); - // } - - QObject::connect(mTimerTotalSpeed, &QTimer::timeout, this, &Statistics::refreshTotalSpeed); - mTimerTotalSpeed->setInterval(200); - mTimerTotalSpeed->start(); -} - -SpeedStatistics *Statistics::speedUp(const QString &id) -{ - auto iter = mSpeedUp.find(id); - if (iter == mSpeedUp.end()) { - qCCritical(logcat_statistics) << "No up speed statistics for peer" << id; - return nullptr; - } - return iter.value(); -} -SpeedStatistics *Statistics::speedDown(const QString &id) -{ - auto iter = mSpeedDown.find(id); - if (iter == mSpeedDown.end()) { - qCCritical(logcat_statistics) << "No down speed statistics for peer" << id; - return nullptr; - } - return iter.value(); -} - -SpeedStatistics *Statistics::totalUpSpeed() const -{ - return mSpeedUpTotal; -} -SpeedStatistics *Statistics::totalDownSpeed() const -{ - return mSpeedDownTotal; -} - -void Statistics::statusRefreshed() -{ - // bool newPeers = false; - // for (const Peer *peer : Tailscale::instance()->peers()) { - // if (mSpeedUp.contains(peer->id())) { - // continue; - // } - - // newPeers = true; - - // auto iterUp = mSpeedUp.insert(peer->id(), new SpeedStatistics(this)); - // auto iterDown = mSpeedDown.insert(peer->id(), new SpeedStatistics(this)); - // iterUp.value()->update(peer->txBytes()); - // iterDown.value()->update(peer->rxBytes()); - - // QObject::connect(peer, &Peer::txBytesChanged, iterUp.value(), &SpeedStatistics::update); - // QObject::connect(peer, &Peer::rxBytesChanged, iterDown.value(), &SpeedStatistics::update); - // } - - // if (newPeers) { - // emit speedUpChanged(); - // emit speedDownChanged(); - // } -} - -void Statistics::refreshTotalSpeed() -{ - // GoString tmpName; - // tailscale_get_interface_name(&tmpName); - // const auto name = QString::fromUtf8(tmpName.p, tmpName.n); - - // QFile fileTx(QString("/sys/class/net/%1/statistics/tx_bytes").arg(name)); - // if (!fileTx.open(QIODevice::ReadOnly | QIODevice::Text)) { - // qCCritical(logcat_statistics, "Cannot read tx_bytes"); - // return; - // } - // QTextStream streamTx(&fileTx); - // long bytes = 0; - // streamTx >> bytes; - // mSpeedUpTotal->update(bytes); - - // QFile fileRx(QString("/sys/class/net/%1/statistics/rx_bytes").arg(name)); - // if (!fileRx.open(QIODevice::ReadOnly | QIODevice::Text)) { - // qCCritical(logcat_statistics, "Cannot read tx_bytes"); - // return; - // } - // QTextStream streamRx(&fileRx); - // streamRx >> bytes; - // mSpeedDownTotal->update(bytes); -} diff --git a/src/statistics.hpp b/src/statistics.hpp deleted file mode 100644 index e602ba75..00000000 --- a/src/statistics.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: 2023 Fabian Köhler -#ifndef KTAILCTL_STATISTICS_HPP -#define KTAILCTL_STATISTICS_HPP - -#include "speed_statistics.hpp" - -#include -#include -#include - -Q_DECLARE_LOGGING_CATEGORY(logcat_statistics) - -class Statistics : public QObject -{ - Q_OBJECT - Q_PROPERTY(SpeedStatistics *totalUpSpeed READ totalUpSpeed CONSTANT) - Q_PROPERTY(SpeedStatistics *totalDownSpeed READ totalDownSpeed CONSTANT) - -private: - QMap mSpeedUp; - QMap mSpeedDown; - - QTimer *mTimerTotalSpeed; - SpeedStatistics *mSpeedUpTotal; - SpeedStatistics *mSpeedDownTotal; - -public: - explicit Statistics(QObject *parent = nullptr); - virtual ~Statistics() = default; - - Q_INVOKABLE SpeedStatistics *speedUp(const QString &id); - Q_INVOKABLE SpeedStatistics *speedDown(const QString &id); - SpeedStatistics *totalUpSpeed() const; - SpeedStatistics *totalDownSpeed() const; - -private slots: - void statusRefreshed(); - void refreshTotalSpeed(); - -signals: - void speedUpChanged(); - void speedDownChanged(); - void totalUpSpeedChanged(); - void totalDownSpeedChanged(); -}; - -#endif /* KTAILCTL_STATISTICS_HPP */ diff --git a/src/statistics/CMakeLists.txt b/src/statistics/CMakeLists.txt new file mode 100644 index 00000000..ae9cd7cc --- /dev/null +++ b/src/statistics/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(ktailctl_statistics STATIC statistics_model.cpp) +target_link_libraries(ktailctl_statistics PUBLIC Qt6::Core) +add_library(KTailctl::Statistics ALIAS ktailctl_statistics) diff --git a/src/statistics/statistics_model.cpp b/src/statistics/statistics_model.cpp new file mode 100644 index 00000000..079164af --- /dev/null +++ b/src/statistics/statistics_model.cpp @@ -0,0 +1,7 @@ +#include "statistics_model.hpp" + +StatisticsModel::StatisticsModel(const QString &nodeID, QObject *parent) + : QAbstractListModel(parent) + , mNodeID(nodeID) +{ +} \ No newline at end of file diff --git a/src/statistics/statistics_model.hpp b/src/statistics/statistics_model.hpp new file mode 100644 index 00000000..d97c7db7 --- /dev/null +++ b/src/statistics/statistics_model.hpp @@ -0,0 +1,18 @@ +#ifndef KTAILCTL_STATISTICS_STATISTICS_MODEL_HPP +#define KTAILCTL_STATISTICS_STATISTICS_MODEL_HPP + +#include + +class StatisticsModel : public QAbstractListModel +{ + Q_OBJECT + +private: + QVector mRxBytes; + QVector < + + public : explicit StatisticsModel(const QString &nodeID, QObject *parent = nullptr); + virtual ~StatisticsModel() = default; +}; + +#endif /* KTAILCTL_STATISTICS_STATISTICS_MODEL_HPP */