Client tun/tap online fix
This commit is contained in:
@@ -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.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.gap = std::stoi(ini.get("style", "hostblock.networks.gap", "2"));
|
||||
cfg.style.hostblock.networks.width = std::stoi(ini.get("style", "hostblock.networks.width", "8"));
|
||||
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.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"));
|
||||
|
||||
@@ -63,7 +63,24 @@ namespace config::server
|
||||
int size = 5;
|
||||
int padding = 8;
|
||||
} 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;
|
||||
};
|
||||
} // namespace config::server
|
||||
|
||||
+55
-13
@@ -1,4 +1,5 @@
|
||||
#include "display/ui/bar/Bar.h"
|
||||
#include "display/ui/theme/Theme.h"
|
||||
#include <algorithm>
|
||||
|
||||
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);
|
||||
overlay_value = std::clamp(overlay_value, 0.0f, 1.0f);
|
||||
|
||||
// 1. Рисуем фон
|
||||
// 1. Фон
|
||||
framebuffer.fillRect(x, y, width, height, style.background);
|
||||
|
||||
// 2. Рисуем заполнение
|
||||
display::graphics::Color fillColor = active ? valueToColor(value) : display::graphics::Color{0x66, 0x66, 0x66};
|
||||
// 2. Цвет заполнения
|
||||
display::graphics::Color fillColor =
|
||||
active ? valueToColor(value) : display::ui::theme::bar::OFFLINE;
|
||||
|
||||
// 3. Основное заполнение
|
||||
if (orientation == Orientation::Horizontal)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
// можно добавить метод drawRect в Framebuffer
|
||||
framebuffer.drawRect(x, y, width, height, style.border);
|
||||
}
|
||||
|
||||
if (overlay_value)
|
||||
// 5. Overlay (диагональные линии)
|
||||
if (overlay_value > 0.0f)
|
||||
{
|
||||
if (orientation == Orientation::Horizontal)
|
||||
{
|
||||
int fillWidth = static_cast<int>(width * 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
|
||||
{
|
||||
int fillHeight = static_cast<int>(height * 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace display::ui::bar
|
||||
|
||||
void draw(display::graphics::Framebuffer &framebuffer,
|
||||
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:
|
||||
int width;
|
||||
|
||||
@@ -27,7 +27,12 @@ namespace display::ui::hostblock
|
||||
config.hostblock.width - config.hostblock.padding * 2,
|
||||
config.hostblock.memory.height,
|
||||
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,
|
||||
cursorY + config.hostblock.header.height - 1,
|
||||
hostname,
|
||||
display::ui::theme::text::TEXT,
|
||||
online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
|
||||
display::ui::theme::text::OUTLINE,
|
||||
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,
|
||||
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),
|
||||
display::ui::theme::text::TEXT,
|
||||
online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
|
||||
display::ui::theme::text::OUTLINE,
|
||||
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,
|
||||
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),
|
||||
display::ui::theme::text::TEXT,
|
||||
online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
|
||||
display::ui::theme::text::OUTLINE,
|
||||
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,
|
||||
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),
|
||||
display::ui::theme::text::TEXT,
|
||||
online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
|
||||
display::ui::theme::text::OUTLINE,
|
||||
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 =====
|
||||
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;
|
||||
float txNorm = 0.0f;
|
||||
int row = i / config.hostblock.networks.max_per_row;
|
||||
int col = i % config.hostblock.networks.max_per_row;
|
||||
|
||||
if (iface.online)
|
||||
{
|
||||
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);
|
||||
}
|
||||
int bx = x + config.hostblock.padding +
|
||||
col * (config.hostblock.networks.width * 2 + config.hostblock.networks.gap_h);
|
||||
|
||||
// background bar
|
||||
memBar.draw(
|
||||
fb,
|
||||
x + config.hostblock.padding,
|
||||
by,
|
||||
0.0f,
|
||||
0.0f,
|
||||
iface.online && online);
|
||||
int by = cursorY +
|
||||
row * (config.hostblock.networks.height + config.hostblock.networks.gap_v);
|
||||
|
||||
int barX = x + config.hostblock.padding;
|
||||
int barW = config.hostblock.width - config.hostblock.padding * 2;
|
||||
int barH = config.hostblock.networks.height;
|
||||
float value_rx = std::clamp(network.rxBps / network.rxMaxBps, 0.0f, 1.0f);
|
||||
float value_tx = std::clamp(network.txBps / network.txMaxBps, 0.0f, 1.0f);
|
||||
|
||||
// RX overlay
|
||||
fb.fillRect(
|
||||
barX,
|
||||
by,
|
||||
static_cast<int>(barW * rxNorm),
|
||||
barH,
|
||||
{0, 180, 0});
|
||||
netBar.draw(fb, bx, by, value_rx, 0, network.online && online, true);
|
||||
netBar.draw(fb, bx + config.hostblock.networks.width, by, value_tx, 0, network.online && online);
|
||||
|
||||
// TX overlay
|
||||
fb.fillRect(
|
||||
barX,
|
||||
by,
|
||||
static_cast<int>(barW * txNorm),
|
||||
barH,
|
||||
{200, 200, 0});
|
||||
|
||||
// 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;
|
||||
text.drawTextOutlined(fb,
|
||||
bx + config.hostblock.networks.font.padding,
|
||||
by + 8,
|
||||
display::ui::text::formatSpeed(network.rxBps) + " " + network.name,
|
||||
network.online && online ? display::ui::theme::text::TEXT : display::ui::theme::text::OFFLINE,
|
||||
display::ui::theme::text::OUTLINE,
|
||||
display::ui::text::Font{config.hostblock.networks.font.name, config.hostblock.networks.font.size});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,6 @@ namespace display::ui::hostblock
|
||||
display::ui::bar::Bar cpuBar;
|
||||
display::ui::bar::Bar cpuTempBar;
|
||||
display::ui::bar::Bar memBar;
|
||||
display::ui::bar::Bar netBar;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,12 +22,19 @@ namespace display::ui::text
|
||||
{
|
||||
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)
|
||||
snprintf(buf, sizeof(buf), "%.0f B/s", bps);
|
||||
snprintf(buf, sizeof(buf), "%.0f", bps);
|
||||
else if (bps < 1024 * 1024)
|
||||
snprintf(buf, sizeof(buf), "%.1f kB/s", bps / 1024.0);
|
||||
snprintf(buf, sizeof(buf), "%.1fk", bps / 1024.0);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace display::ui::theme
|
||||
{
|
||||
const display::graphics::Color TEXT{220, 220, 220};
|
||||
const display::graphics::Color OUTLINE{20, 20, 20};
|
||||
const display::graphics::Color OFFLINE{100, 100, 100};
|
||||
} // namespace text
|
||||
|
||||
namespace header
|
||||
@@ -31,5 +32,6 @@ namespace display::ui::theme
|
||||
const display::graphics::Color BACKGROUND{30, 30, 30};
|
||||
const display::graphics::Color FILL{0, 180, 0};
|
||||
const display::graphics::Color BORDER{80, 80, 80};
|
||||
const display::graphics::Color OFFLINE{60, 60, 60};
|
||||
} // namespace bar
|
||||
} // namespace display::ui::theme
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <cerrno>
|
||||
@@ -329,13 +331,21 @@ namespace metrics
|
||||
|
||||
bool Collector::isInterfaceOnline(const std::string &iface)
|
||||
{
|
||||
std::ifstream f("/sys/class/net/" + iface + "/operstate");
|
||||
if (!f)
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
std::string state;
|
||||
f >> state;
|
||||
return state == "up";
|
||||
struct ifreq ifr{};
|
||||
std::snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface.c_str());
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user