From a52e97177a5898ec3cd991bb930a0f8514a5a371 Mon Sep 17 00:00:00 2001 From: AndersonTsaiTW Date: Sun, 12 Oct 2025 18:52:34 -0400 Subject: [PATCH 1/3] build new branch and add network monitoring feature --- include/network_monitor.h | 109 ++++++++++++++++++++++++++++++++++++++ src/main.cpp | 19 +++++++ 2 files changed, 128 insertions(+) create mode 100644 include/network_monitor.h diff --git a/include/network_monitor.h b/include/network_monitor.h new file mode 100644 index 0000000..19d5349 --- /dev/null +++ b/include/network_monitor.h @@ -0,0 +1,109 @@ +#ifndef NETWORK_MONITOR_H +#define NETWORK_MONITOR_H + +// Written by: Anderson Yu-Hong Cai (https://github.com/AndersonTsaiTW) +// Written on: 2025-10-11 +// License: MIT +// Version: 2.0 +// +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include +#include +#include +#include + +// Note: linking still required for iphlpapi when using g++: -liphlpapi + +static bool collect_if_counters(uint64_t &out_sent, uint64_t &out_recv) { + out_sent = 0; + out_recv = 0; + + // Fallback to GetIfTable which is widely available (MinGW). We'll + // allocate the table buffer dynamically as required. + MIB_IFTABLE *pIfTable = NULL; + DWORD dwSize = 0; + DWORD dwRetVal = GetIfTable(NULL, &dwSize, FALSE); + if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) { + return false; + } + + pIfTable = (MIB_IFTABLE*)malloc(dwSize); + if (pIfTable == NULL) return false; + + dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE); + if (dwRetVal != NO_ERROR) { + free(pIfTable); + return false; + } + + std::set seenIndexes; + for (DWORD i = 0; i < pIfTable->dwNumEntries; ++i) { + MIB_IFROW &row = pIfTable->table[i]; + + // De-duplicate by dwIndex (if available). Some stacks list + // virtual/alias rows that may duplicate counters. + if (seenIndexes.find(row.dwIndex) != seenIndexes.end()) continue; + seenIndexes.insert(row.dwIndex); + + // Heuristic: include an interface if it shows any octets OR has a + // non-zero oper status. This avoids summing unused loopback/host + // entries while still counting active interfaces. + uint64_t outOct = (uint64_t)row.dwOutOctets; + uint64_t inOct = (uint64_t)row.dwInOctets; + if (outOct == 0 && inOct == 0 && row.dwOperStatus == 0) { + continue; + } + + out_sent += outOct; + out_recv += inOct; + } + + free(pIfTable); + return true; +} + +// Helper: compute difference with 64-bit wrap-around handling +static inline uint64_t counter_diff(uint64_t end, uint64_t start) { + if (end >= start) return end - start; + // wrapped + return (UINT64_MAX - start) + end + 1ULL; +} + +// Public API: samples counters for ~1s and returns KB/s +static void get_network_stats(double &sent_rate_kbps, double &received_rate_kbps) { + uint64_t sent0 = 0, recv0 = 0; + uint64_t sent1 = 0, recv1 = 0; + + if (!collect_if_counters(sent0, recv0)) { + sent_rate_kbps = 0.0; + received_rate_kbps = 0.0; + return; + } + + ULONGLONG t0 = GetTickCount64(); + Sleep(3000); // 3-second interval + + if (!collect_if_counters(sent1, recv1)) { + sent_rate_kbps = 0.0; + received_rate_kbps = 0.0; + return; + } + + ULONGLONG t1 = GetTickCount64(); + + double elapsed_s = (double)(t1 - t0) / 1000.0; + if (elapsed_s <= 0.0) elapsed_s = 1.0; // safety + + uint64_t ds = counter_diff(sent1, sent0); + uint64_t dr = counter_diff(recv1, recv0); + + // convert to KB/s + sent_rate_kbps = ((double)ds / 1024.0) / elapsed_s; + received_rate_kbps = ((double)dr / 1024.0) / elapsed_s; +} + +#endif // NETWORK_MONITOR_H \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e86b64d..ffefa49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include #include "cpu_monitor.h" #include "memory_monitor.h" +#include "network_monitor.h" int main() { @@ -40,6 +41,9 @@ int main() int mem_available = memory.memory_available(); int mem_total = memory.memory_total(); int mem_used = memory.memory_used(); + double sent_rate_kbps, received_rate_kbps; + get_network_stats(sent_rate_kbps, received_rate_kbps); + double sum_rate_kbs = sent_rate_kbps + received_rate_kbps; std::cout << R"(________ ___ ___ ________ _____ ______ ________ ________ ________ |\ ____\ |\ \ / /|\ ____\|\ _ \ _ \|\ __ \|\ __ \|\ ___ \ @@ -66,6 +70,8 @@ int main() std::cout << "Memory Available: " << mem_available << " MB" << '\n'; std::cout << "Memory Total: " << mem_total << " MB" << '\n'; std::cout << "Memory Used: " << mem_used << " MB" << '\n'; + std::cout << "Network Sent: " << sent_rate_kbps << " KB/s" << std::endl; + std::cout << "Network Received: " << received_rate_kbps << " KB/s" << std::endl; std::cout << "=========================================================== " << '\n'; std::cout << "========================System Mood======================== " << '\n'; @@ -93,6 +99,19 @@ int main() { std::cout << "So much free memory! I could host a party in here! " << '\n'; } + + if (sum_rate_kbs <= 0.0) { + std::cout << "Hello...? Anyone out there? I think I'm alone in the digital void..." << std::endl; + } else if (sum_rate_kbs <= 10.0) { // 1–10 KB/s:low + std::cout << "I can barely feel the connection... maybe send a ping to keep me alive?" << std::endl; + } else if (sum_rate_kbs <= 100.0) { // 11–100 KB/s:moderate + std::cout << "Hmm... data's trickling in. Not bad, but I'm starting to warm up!" << std::endl; + } else if (sum_rate_kbs <= 1000.0) { // 101–1000 KB/s:good + std::cout << "Nice flow! I can stream tunes, fetch memes, and still feel chill~" << std::endl; + } else { // > 1000 KB/s:fast + std::cout << "Wooosh! Data's flying—pages load before you blink. I'm unstoppable!!! " << std::endl; + } + std::cout << "=========================================================== " << '\n'; return 0; From ce88392837a9d4dd8289c5211a7a295f18098ab0 Mon Sep 17 00:00:00 2001 From: AndersonTsaiTW Date: Sun, 12 Oct 2025 19:02:12 -0400 Subject: [PATCH 2/3] add link lib Iphlpapi in CMakeList --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 001af5b..578f976 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,10 @@ target_include_directories(SysMood PRIVATE ${CMAKE_SOURCE_DIR}/include ) +if(WIN32) + target_link_libraries(SysMood PRIVATE Iphlpapi) +endif() + # Enable testing (used later) include(CTest) enable_testing() From 2922410034b151db11abaa9b2714ff1bcd2af1bd Mon Sep 17 00:00:00 2001 From: AndersonTsaiTW Date: Mon, 13 Oct 2025 01:26:17 -0400 Subject: [PATCH 3/3] Add platform guards to preserve space for Linux/macOS implementation - Wrap Windows-specific code with #ifdef _WIN32 - Provide stub implementation for non-Windows platforms - Prevent CI compilation errors on Linux builds --- include/network_monitor.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/network_monitor.h b/include/network_monitor.h index 19d5349..2df3500 100644 --- a/include/network_monitor.h +++ b/include/network_monitor.h @@ -6,13 +6,15 @@ // License: MIT // Version: 2.0 // +#include + +#ifdef _WIN32 #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0602 #endif #include #include -#include #include #include @@ -106,4 +108,13 @@ static void get_network_stats(double &sent_rate_kbps, double &received_rate_kbps received_rate_kbps = ((double)dr / 1024.0) / elapsed_s; } +#else +// Non-Windows platform: provide stub implementation +static void get_network_stats(double &sent_rate_kbps, double &received_rate_kbps) { + // TODO: Implement network monitoring for Linux/macOS + sent_rate_kbps = 0.0; + received_rate_kbps = 0.0; +} +#endif // _WIN32 + #endif // NETWORK_MONITOR_H \ No newline at end of file