Client tun/tap online fix

This commit is contained in:
2026-01-10 14:10:58 +00:00
parent 5b5be7c3c8
commit c8d7665b77
9 changed files with 141 additions and 89 deletions
+6 -2
View File
@@ -74,8 +74,12 @@ namespace config::server
cfg.style.hostblock.disks.font.size = std::stoi(ini.get("style", "hostblock.disks.font.size", "5")); cfg.style.hostblock.disks.font.size = std::stoi(ini.get("style", "hostblock.disks.font.size", "5"));
cfg.style.hostblock.disks.font.padding = std::stoi(ini.get("style", "hostblock.disks.font.padding", "8")); cfg.style.hostblock.disks.font.padding = std::stoi(ini.get("style", "hostblock.disks.font.padding", "8"));
cfg.style.hostblock.networks.height = std::stoi(ini.get("style", "hostblock.networks.height", "11")); cfg.style.hostblock.networks.width = std::stoi(ini.get("style", "hostblock.networks.width", "8"));
cfg.style.hostblock.networks.gap = std::stoi(ini.get("style", "hostblock.networks.gap", "2")); cfg.style.hostblock.networks.height = std::stoi(ini.get("style", "hostblock.networks.height", "16"));
cfg.style.hostblock.networks.gap_h = std::stoi(ini.get("style", "hostblock.networks.gap_h", "4"));
cfg.style.hostblock.networks.gap_v = std::stoi(ini.get("style", "hostblock.networks.gap_v", "4"));
cfg.style.hostblock.networks.max_per_row = std::stoi(ini.get("style", "hostblock.networks.max_per_row", "8"));
cfg.style.hostblock.networks.rows = std::stoi(ini.get("style", "hostblock.networks.rows", "2"));
cfg.style.hostblock.networks.font.name = ini.get("style", "hostblock.networks.font.name", "PixelFive-Regular"); cfg.style.hostblock.networks.font.name = ini.get("style", "hostblock.networks.font.name", "PixelFive-Regular");
cfg.style.hostblock.networks.font.size = std::stoi(ini.get("style", "hostblock.networks.font.size", "5")); cfg.style.hostblock.networks.font.size = std::stoi(ini.get("style", "hostblock.networks.font.size", "5"));
cfg.style.hostblock.networks.font.padding = std::stoi(ini.get("style", "hostblock.networks.font.padding", "8")); cfg.style.hostblock.networks.font.padding = std::stoi(ini.get("style", "hostblock.networks.font.padding", "8"));
+18 -1
View File
@@ -63,7 +63,24 @@ namespace config::server
int size = 5; int size = 5;
int padding = 8; int padding = 8;
} font; } font;
} memory, disks, networks; } memory, disks;
struct
{
int width = 8;
int height = 16;
int gap_h = 4;
int gap_v = 4;
int max_per_row = 4;
int rows = 2;
struct
{
std::string name = "PixelFive-Regular";
int size = 5;
int padding = 8;
} font;
} networks;
} hostblock; } hostblock;
}; };
} // namespace config::server } // namespace config::server
+55 -13
View File
@@ -1,4 +1,5 @@
#include "display/ui/bar/Bar.h" #include "display/ui/bar/Bar.h"
#include "display/ui/theme/Theme.h"
#include <algorithm> #include <algorithm>
namespace display::ui::bar namespace display::ui::bar
@@ -8,49 +9,90 @@ namespace display::ui::bar
{ {
} }
void Bar::draw(display::graphics::Framebuffer &framebuffer, int x, int y, float value, float overlay_value, bool active) void Bar::draw(display::graphics::Framebuffer &framebuffer, int x, int y, float value, float overlay_value, bool active, bool mirror)
{ {
value = std::clamp(value, 0.0f, 1.0f); value = std::clamp(value, 0.0f, 1.0f);
overlay_value = std::clamp(overlay_value, 0.0f, 1.0f);
// 1. Рисуем фон // 1. Фон
framebuffer.fillRect(x, y, width, height, style.background); framebuffer.fillRect(x, y, width, height, style.background);
// 2. Рисуем заполнение // 2. Цвет заполнения
display::graphics::Color fillColor = active ? valueToColor(value) : display::graphics::Color{0x66, 0x66, 0x66}; display::graphics::Color fillColor =
active ? valueToColor(value) : display::ui::theme::bar::OFFLINE;
// 3. Основное заполнение
if (orientation == Orientation::Horizontal) if (orientation == Orientation::Horizontal)
{ {
int fillWidth = static_cast<int>(width * value); int fillWidth = static_cast<int>(width * value);
framebuffer.fillRect(x, y, fillWidth, height, fillColor);
int fillX = mirror
? x + (width - fillWidth)
: x;
framebuffer.fillRect(fillX, y, fillWidth, height, fillColor);
} }
else // Vertical else // Vertical
{ {
int fillHeight = static_cast<int>(height * value); int fillHeight = static_cast<int>(height * value);
framebuffer.fillRect(x, y + (height - fillHeight), width, fillHeight, fillColor);
int fillY = mirror
? y
: y + (height - fillHeight);
framebuffer.fillRect(x, fillY, width, fillHeight, fillColor);
} }
// 3. Рисуем рамку // 4. Рамка
if (style.drawBorder) if (style.drawBorder)
{ {
// можно добавить метод drawRect в Framebuffer
framebuffer.drawRect(x, y, width, height, style.border); framebuffer.drawRect(x, y, width, height, style.border);
} }
if (overlay_value) // 5. Overlay (диагональные линии)
if (overlay_value > 0.0f)
{ {
if (orientation == Orientation::Horizontal) if (orientation == Orientation::Horizontal)
{ {
int fillWidth = static_cast<int>(width * value); int fillWidth = static_cast<int>(width * value);
int overlayWidth = static_cast<int>(width * overlay_value); int overlayWidth = static_cast<int>(width * overlay_value);
int overlayX = x + (fillWidth - overlayWidth);
framebuffer.drawRectDiagonalOverlay(overlayX, y + 1, overlayWidth, height - 2, style.border, 3); int baseX = mirror
? x + (width - fillWidth)
: x;
int overlayX = mirror
? baseX
: baseX + (fillWidth - overlayWidth);
framebuffer.drawRectDiagonalOverlay(
overlayX,
y + 1,
overlayWidth,
height - 2,
style.border,
3);
} }
else // Vertical else // Vertical
{ {
int fillHeight = static_cast<int>(height * value); int fillHeight = static_cast<int>(height * value);
int overlayHeight = static_cast<int>(height * overlay_value); int overlayHeight = static_cast<int>(height * overlay_value);
int overlayY = y + (fillHeight - overlayHeight);
framebuffer.drawRectDiagonalOverlay(x + 1, overlayY + (height - overlayHeight), width - 2, overlayHeight, style.border, 3); int baseY = mirror
? y
: y + (height - fillHeight);
int overlayY = mirror
? baseY + (fillHeight - overlayHeight)
: baseY;
framebuffer.drawRectDiagonalOverlay(
x + 1,
overlayY,
width - 2,
overlayHeight,
style.border,
3);
} }
} }
} }
+1 -1
View File
@@ -13,7 +13,7 @@ namespace display::ui::bar
void draw(display::graphics::Framebuffer &framebuffer, void draw(display::graphics::Framebuffer &framebuffer,
int x, int y, int x, int y,
float value, float overlay_value = 0.0, bool active = true); // 0.0 .. 1.0 float value, float overlay_value = 0.0, bool active = true, bool mirror = false); // 0.0 .. 1.0
private: private:
int width; int width;
+33 -64
View File
@@ -27,7 +27,12 @@ namespace display::ui::hostblock
config.hostblock.width - config.hostblock.padding * 2, config.hostblock.width - config.hostblock.padding * 2,
config.hostblock.memory.height, config.hostblock.memory.height,
display::ui::bar::Orientation::Horizontal, display::ui::bar::Orientation::Horizontal,
display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 120, 200}, display::graphics::Color{80, 80, 80}, true}) display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 120, 200}, display::graphics::Color{80, 80, 80}, true}),
netBar(
config.hostblock.networks.width,
config.hostblock.networks.height,
display::ui::bar::Orientation::Horizontal,
display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 180, 0}, display::graphics::Color{80, 80, 80}, true})
{ {
} }
@@ -60,7 +65,7 @@ namespace display::ui::hostblock
x + config.hostblock.padding + 2, x + config.hostblock.padding + 2,
cursorY + config.hostblock.header.height - 1, cursorY + config.hostblock.header.height - 1,
hostname, hostname,
display::ui::theme::text::TEXT, online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
display::ui::theme::text::OUTLINE, display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.header.font.name, config.hostblock.header.font.size}); display::ui::text::Font{config.hostblock.header.font.name, config.hostblock.header.font.size});
@@ -110,7 +115,7 @@ namespace display::ui::hostblock
x + config.hostblock.memory.font.padding, x + config.hostblock.memory.font.padding,
cursorY + 8, cursorY + 8,
"MEM: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.total) / 1073741824), "MEM: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.total) / 1073741824),
display::ui::theme::text::TEXT, online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
display::ui::theme::text::OUTLINE, display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size}); display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size});
@@ -130,7 +135,7 @@ namespace display::ui::hostblock
x + config.hostblock.memory.font.padding, x + config.hostblock.memory.font.padding,
cursorY + 8, cursorY + 8,
"SWP: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.total) / 1073741824), "SWP: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.total) / 1073741824),
display::ui::theme::text::TEXT, online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
display::ui::theme::text::OUTLINE, display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size}); display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size});
@@ -152,79 +157,43 @@ namespace display::ui::hostblock
x + config.hostblock.disks.font.padding, x + config.hostblock.disks.font.padding,
by + 8, by + 8,
"D/" + metrics.disks[i].name + ": " + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.total) / 1073741824), "D/" + metrics.disks[i].name + ": " + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.total) / 1073741824),
display::ui::theme::text::TEXT, online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
display::ui::theme::text::OUTLINE, display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.disks.font.name, config.hostblock.disks.font.size}); display::ui::text::Font{config.hostblock.disks.font.name, config.hostblock.disks.font.size});
} }
cursorY += diskCount * (config.hostblock.disks.height + config.hostblock.disks.gap); cursorY += diskCount * (config.hostblock.disks.height + config.hostblock.disks.gap) + config.hostblock.gap;
// ===== Network bar ===== // ===== Network bar =====
for (const auto &iface : metrics.networks) int networksCount = std::min<int>(metrics.networks.size(),
config.hostblock.networks.max_per_row * config.hostblock.networks.rows);
for (int i = 0; i < networksCount; ++i)
{ {
int by = cursorY; const metrics::Network &network = metrics.networks[i];
float rxNorm = 0.0f; int row = i / config.hostblock.networks.max_per_row;
float txNorm = 0.0f; int col = i % config.hostblock.networks.max_per_row;
if (iface.online) int bx = x + config.hostblock.padding +
{ col * (config.hostblock.networks.width * 2 + config.hostblock.networks.gap_h);
if (iface.rxMaxBps > 0)
rxNorm = std::clamp(static_cast<float>(iface.rxBps / iface.rxMaxBps), 0.0f, 1.0f);
if (iface.txMaxBps > 0)
txNorm = std::clamp(static_cast<float>(iface.txBps / iface.txMaxBps), 0.0f, 1.0f);
}
// background bar int by = cursorY +
memBar.draw( row * (config.hostblock.networks.height + config.hostblock.networks.gap_v);
fb,
x + config.hostblock.padding,
by,
0.0f,
0.0f,
iface.online && online);
int barX = x + config.hostblock.padding; float value_rx = std::clamp(network.rxBps / network.rxMaxBps, 0.0f, 1.0f);
int barW = config.hostblock.width - config.hostblock.padding * 2; float value_tx = std::clamp(network.txBps / network.txMaxBps, 0.0f, 1.0f);
int barH = config.hostblock.networks.height;
// RX overlay netBar.draw(fb, bx, by, value_rx, 0, network.online && online, true);
fb.fillRect( netBar.draw(fb, bx + config.hostblock.networks.width, by, value_tx, 0, network.online && online);
barX,
by,
static_cast<int>(barW * rxNorm),
barH,
{0, 180, 0});
// TX overlay text.drawTextOutlined(fb,
fb.fillRect( bx + config.hostblock.networks.font.padding,
barX, by + 8,
by, display::ui::text::formatSpeed(network.rxBps) + " " + network.name,
static_cast<int>(barW * txNorm), network.online && online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
barH, display::ui::theme::text::OUTLINE,
{200, 200, 0}); display::ui::text::Font{config.hostblock.networks.font.name, config.hostblock.networks.font.size});
// border
fb.drawRect(barX, by, barW, barH, display::ui::theme::hostblock::BORDER);
// interface name + speeds
std::string label =
iface.name + " " +
display::ui::text::formatSpeed(iface.rxBps) + "" +
display::ui::text::formatSpeed(iface.txBps) + "";
text.drawTextOutlined(
fb,
barX + config.hostblock.networks.font.padding,
by + barH - 1,
label,
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{
config.hostblock.networks.font.name,
config.hostblock.networks.font.size});
cursorY += config.hostblock.networks.height + config.hostblock.networks.gap;
} }
} }
} }
+1
View File
@@ -29,5 +29,6 @@ namespace display::ui::hostblock
display::ui::bar::Bar cpuBar; display::ui::bar::Bar cpuBar;
display::ui::bar::Bar cpuTempBar; display::ui::bar::Bar cpuTempBar;
display::ui::bar::Bar memBar; display::ui::bar::Bar memBar;
display::ui::bar::Bar netBar;
}; };
} }
+10 -3
View File
@@ -22,12 +22,19 @@ namespace display::ui::text
{ {
char buf[32]; char buf[32];
/* if (bps < 1024)
snprintf(buf, sizeof(buf), "%.0f B/s", bps);
else if (bps < 1024 * 1024)
snprintf(buf, sizeof(buf), "%.1f kB/s", bps / 1024.0);
else
snprintf(buf, sizeof(buf), "%.1f MB/s", bps / (1024.0 * 1024.0));
*/
if (bps < 1024) if (bps < 1024)
snprintf(buf, sizeof(buf), "%.0f B/s", bps); snprintf(buf, sizeof(buf), "%.0f", bps);
else if (bps < 1024 * 1024) else if (bps < 1024 * 1024)
snprintf(buf, sizeof(buf), "%.1f kB/s", bps / 1024.0); snprintf(buf, sizeof(buf), "%.1fk", bps / 1024.0);
else else
snprintf(buf, sizeof(buf), "%.1f MB/s", bps / (1024.0 * 1024.0)); snprintf(buf, sizeof(buf), "%.1fM", bps / (1024.0 * 1024.0));
return buf; return buf;
} }
+2
View File
@@ -8,6 +8,7 @@ namespace display::ui::theme
{ {
const display::graphics::Color TEXT{220, 220, 220}; const display::graphics::Color TEXT{220, 220, 220};
const display::graphics::Color OUTLINE{20, 20, 20}; const display::graphics::Color OUTLINE{20, 20, 20};
const display::graphics::Color OFFLINE{100, 100, 100};
} // namespace text } // namespace text
namespace header namespace header
@@ -31,5 +32,6 @@ namespace display::ui::theme
const display::graphics::Color BACKGROUND{30, 30, 30}; const display::graphics::Color BACKGROUND{30, 30, 30};
const display::graphics::Color FILL{0, 180, 0}; const display::graphics::Color FILL{0, 180, 0};
const display::graphics::Color BORDER{80, 80, 80}; const display::graphics::Color BORDER{80, 80, 80};
const display::graphics::Color OFFLINE{60, 60, 60};
} // namespace bar } // namespace bar
} // namespace display::ui::theme } // namespace display::ui::theme
+15 -5
View File
@@ -4,6 +4,8 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include <cerrno> #include <cerrno>
@@ -329,13 +331,21 @@ namespace metrics
bool Collector::isInterfaceOnline(const std::string &iface) bool Collector::isInterfaceOnline(const std::string &iface)
{ {
std::ifstream f("/sys/class/net/" + iface + "/operstate"); int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (!f) if (fd < 0)
return false; return false;
std::string state; struct ifreq ifr{};
f >> state; std::snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface.c_str());
return state == "up";
bool online = false;
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
{
online = (ifr.ifr_flags & IFF_UP) != 0;
}
close(fd);
return online;
} }
bool Collector::readInterfaceCounters(const std::string &iface, uint64_t &rx, uint64_t &tx) bool Collector::readInterfaceCounters(const std::string &iface, uint64_t &rx, uint64_t &tx)