feat: portar panel Sistema del widget previo + servicio de captura
Pestaña Sistema: - Reproduce las 9 gráficas del widget anterior dibujadas con Cairo sobre históricos en memoria: CPU, RAM, CPU temp, GPU, GPU temp, VRAM, red (down/up superpuestos) y disk I/O, más las barras de uso de los discos /, /mnt/1tb, /mnt/2tb y /mnt/16tb. - metric.sh portado (nvidia-smi + coretemp hwmon) para temperaturas y métricas de GPU. - Paleta Nord, igual que el panel original. Widget redimensionado a 290x545 para acomodar el panel Sistema. Servicio de captura (service/): - packet-capture.service: dumpcap en ring buffer (~10 min, 10 archivos de hasta 60s/50MB, tope ~500MB) escribiendo en /var/log/pktcap. - install-capture.sh: crea el directorio, instala y activa el unit. El botón Wireshark abre ahora el .pcapng más reciente del buffer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -14,9 +14,9 @@ conky.config = {
|
|||||||
xinerama_head = 1, -- 1 = DP-1 (pantalla izquierda). 0 = HDMI-0 derecha.
|
xinerama_head = 1, -- 1 = DP-1 (pantalla izquierda). 0 = HDMI-0 derecha.
|
||||||
gap_x = 30, -- separacion desde el borde derecho
|
gap_x = 30, -- separacion desde el borde derecho
|
||||||
gap_y = 50, -- separa del panel superior de XFCE
|
gap_y = 50, -- separa del panel superior de XFCE
|
||||||
minimum_width = 300,
|
minimum_width = 290,
|
||||||
maximum_width = 300,
|
maximum_width = 290,
|
||||||
minimum_height = 360,
|
minimum_height = 545,
|
||||||
|
|
||||||
-- Ventana (tipo 'normal' = recibe clicks; 'desktop' los ignora) ----------
|
-- Ventana (tipo 'normal' = recibe clicks; 'desktop' los ignora) ----------
|
||||||
own_window = true,
|
own_window = true,
|
||||||
|
|||||||
+182
-115
@@ -3,40 +3,48 @@ conky_widget — render Cairo + pestañas clickeables.
|
|||||||
|
|
||||||
Estructura:
|
Estructura:
|
||||||
- Estado: current_tab (1=Red, 2=Sistema, 3=Docker).
|
- Estado: current_tab (1=Red, 2=Sistema, 3=Docker).
|
||||||
- conky_draw (lua_draw_hook_post): dibuja la barra de pestañas y el panel activo.
|
- conky_draw (lua_draw_hook_post): mantiene los historicos y dibuja la barra
|
||||||
|
de pestañas y el panel activo.
|
||||||
- conky_mouse (lua_mouse_hook): cambia de pestaña y lanza apps al clicar botones.
|
- conky_mouse (lua_mouse_hook): cambia de pestaña y lanza apps al clicar botones.
|
||||||
|
|
||||||
Los datos del sistema se obtienen llamando a conky_parse("${...}") desde Lua,
|
Los datos del sistema se obtienen llamando a conky_parse("${...}") desde Lua,
|
||||||
de modo que se pueden colocar con libertad mediante Cairo.
|
de modo que se pueden colocar con libertad mediante Cairo.
|
||||||
|
|
||||||
Geometria fija (la ventana mide 300x360 segun conky.conf):
|
La pestaña Sistema reproduce el panel del widget previo: nueve graficas de
|
||||||
- Barra de pestañas: y 4..28, tres pestañas de ancho W/3.
|
linea (CPU, RAM, CPU temp, GPU, GPU temp, VRAM, red, disk I/O) mas las barras
|
||||||
- Botones de la pestaña Red: fila inferior en BTN_Y.
|
de uso de los cuatro discos. Los valores de temperatura/GPU se obtienen de
|
||||||
|
metric.sh (nvidia-smi + coretemp hwmon).
|
||||||
|
|
||||||
|
Geometria fija (la ventana mide W x H segun conky.conf).
|
||||||
]]
|
]]
|
||||||
|
|
||||||
require 'cairo'
|
require 'cairo'
|
||||||
pcall(require, 'cairo_xlib') -- conky >= 1.12 separa el modulo cairo_xlib
|
pcall(require, 'cairo_xlib') -- conky >= 1.12 separa el modulo cairo_xlib
|
||||||
|
|
||||||
-- Geometria compartida entre dibujo y eventos de raton -----------------------
|
-- Geometria compartida entre dibujo y eventos de raton -----------------------
|
||||||
local W = 300
|
local W = 290
|
||||||
local H = 360
|
local H = 545
|
||||||
local TAB_TOP = 4
|
local TAB_TOP = 4
|
||||||
local TAB_H = 24
|
local TAB_H = 24
|
||||||
local BTN_H = 28
|
local BTN_H = 26
|
||||||
local BTN_Y = H - 40 -- 320
|
local BTN_Y = 242 -- fila de botones de la pestaña Red
|
||||||
|
|
||||||
-- Interfaz de red a monitorizar (detectada: enp5s0 es la fisica activa) ------
|
-- Interfaz de red a monitorizar (enp5s0 es la fisica activa) ------------------
|
||||||
local NIF = "enp5s0"
|
local NIF = "enp5s0"
|
||||||
|
|
||||||
|
-- Helper de metricas (temps + GPU), portado del widget previo -----------------
|
||||||
|
local MET = os.getenv("HOME") .. "/.config/conky/conky_widget/metric.sh"
|
||||||
|
|
||||||
-- Pestañas -------------------------------------------------------------------
|
-- Pestañas -------------------------------------------------------------------
|
||||||
local TABS = { "Red", "Sistema", "Docker" }
|
local TABS = { "Red", "Sistema", "Docker" }
|
||||||
local current_tab = 1
|
local current_tab = 1
|
||||||
|
|
||||||
-- Botones de la pestaña Red. cmd es un comando shell; bin se comprueba antes
|
-- Botones de la pestaña Red. bin se comprueba antes de lanzar; si falta,
|
||||||
-- de lanzar y, si falta, launch.sh avisa con notify-send.
|
-- launch.sh avisa con notify-send.
|
||||||
local BTNS = {
|
local BTNS = {
|
||||||
{ label = "Wireshark", bin = "wireshark", pkg = "wireshark",
|
{ label = "Wireshark", bin = "wireshark", pkg = "wireshark",
|
||||||
cmd = "wireshark /var/log/pktcap/cap.pcapng 2>/dev/null || wireshark" },
|
cmd = "f=$(ls -t /var/log/pktcap/*.pcapng 2>/dev/null | head -1); " ..
|
||||||
|
"if [ -n \"$f\" ]; then wireshark -r \"$f\"; else wireshark; fi" },
|
||||||
{ label = "ntopng", bin = "ntopng", pkg = "ntopng",
|
{ label = "ntopng", bin = "ntopng", pkg = "ntopng",
|
||||||
cmd = "xdg-open http://localhost:3000" },
|
cmd = "xdg-open http://localhost:3000" },
|
||||||
{ label = "nethogs", bin = "nethogs", pkg = "nethogs",
|
{ label = "nethogs", bin = "nethogs", pkg = "nethogs",
|
||||||
@@ -45,30 +53,49 @@ local BTNS = {
|
|||||||
|
|
||||||
local LAUNCH = os.getenv("HOME") .. "/.config/conky/conky_widget/lua/launch.sh"
|
local LAUNCH = os.getenv("HOME") .. "/.config/conky/conky_widget/lua/launch.sh"
|
||||||
|
|
||||||
-- Historico de velocidad de red para el grafico en vivo ----------------------
|
-- Historicos para los graficos en vivo ---------------------------------------
|
||||||
local HIST = 60
|
local GH = 58
|
||||||
local down_hist, up_hist = {}, {}
|
local KEYS = { "cpu", "ram", "cputemp", "gputil", "gputemp", "vram", "diskio", "down", "up" }
|
||||||
for i = 1, HIST do down_hist[i] = 0; up_hist[i] = 0 end
|
local hist = {}
|
||||||
|
for _, k in ipairs(KEYS) do
|
||||||
|
hist[k] = {}
|
||||||
|
for i = 1, GH do hist[k][i] = 0 end
|
||||||
|
end
|
||||||
|
|
||||||
local function push(t, v)
|
local function push(t, v)
|
||||||
table.remove(t, 1)
|
table.remove(t, 1)
|
||||||
t[#t + 1] = v
|
t[#t + 1] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Paleta ---------------------------------------------------------------------
|
-- Paleta (Nord, como el widget previo) ---------------------------------------
|
||||||
|
local function hex(s)
|
||||||
|
return {
|
||||||
|
tonumber(s:sub(1, 2), 16) / 255,
|
||||||
|
tonumber(s:sub(3, 4), 16) / 255,
|
||||||
|
tonumber(s:sub(5, 6), 16) / 255,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local COL = {
|
local COL = {
|
||||||
bg = { 0.08, 0.09, 0.11 },
|
bg = hex("0e0f12"),
|
||||||
panel = { 0.14, 0.15, 0.18 },
|
panel = hex("1b1d23"),
|
||||||
tab_active = { 0.18, 0.55, 0.85 },
|
tab_active = hex("5e81ac"),
|
||||||
tab_inactive = { 0.18, 0.19, 0.23 },
|
tab_inactive = hex("2e3440"),
|
||||||
text = { 0.86, 0.87, 0.90 },
|
text = hex("d8dee9"),
|
||||||
white = { 1.00, 1.00, 1.00 },
|
snow = hex("eceff4"),
|
||||||
dim = { 0.55, 0.57, 0.62 },
|
white = { 1, 1, 1 },
|
||||||
green = { 0.30, 0.80, 0.45 },
|
dim = hex("7b8394"),
|
||||||
orange = { 0.95, 0.60, 0.20 },
|
teal = hex("8fbcbb"),
|
||||||
red = { 0.90, 0.30, 0.35 },
|
green = hex("a3be8c"),
|
||||||
down = { 0.30, 0.70, 0.95 },
|
cyan = hex("88c0d0"),
|
||||||
up = { 0.95, 0.55, 0.30 },
|
blue = hex("81a1c1"),
|
||||||
|
frost = hex("5e81ac"),
|
||||||
|
yellow = hex("ebcb8b"),
|
||||||
|
orange = hex("d08770"),
|
||||||
|
purple = hex("b48ead"),
|
||||||
|
red = hex("bf616a"),
|
||||||
|
down = hex("88c0d0"),
|
||||||
|
up = hex("d08770"),
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Helpers de lectura de datos ------------------------------------------------
|
-- Helpers de lectura de datos ------------------------------------------------
|
||||||
@@ -82,6 +109,17 @@ local function num(expr)
|
|||||||
return tonumber(str(expr)) or 0
|
return tonumber(str(expr)) or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Convierte un texto de tasa de conky ("1.2MiB", "300KiB", "5B") a KiB/s ------
|
||||||
|
local function rate_kib(s)
|
||||||
|
local n, unit = s:match("([%d%.]+)%s*([KMGTPi]*)B?")
|
||||||
|
n = tonumber(n) or 0
|
||||||
|
unit = unit or ""
|
||||||
|
if unit:find("M") then return n * 1024
|
||||||
|
elseif unit:find("G") then return n * 1024 * 1024
|
||||||
|
elseif unit:find("K") then return n
|
||||||
|
else return n / 1024 end
|
||||||
|
end
|
||||||
|
|
||||||
-- Helpers de dibujo ----------------------------------------------------------
|
-- Helpers de dibujo ----------------------------------------------------------
|
||||||
local function setcol(cr, c, a)
|
local function setcol(cr, c, a)
|
||||||
cairo_set_source_rgba(cr, c[1], c[2], c[3], a or 1.0)
|
cairo_set_source_rgba(cr, c[1], c[2], c[3], a or 1.0)
|
||||||
@@ -105,10 +143,9 @@ local function text(cr, x, y, s, c, size, bold)
|
|||||||
cairo_show_text(cr, s)
|
cairo_show_text(cr, s)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Centrado aproximado para fuente monoespaciada (avance ~0.6*tamaño) ----------
|
-- Texto alineado a la derecha (avance mono ~0.6*tamaño) ----------------------
|
||||||
local function ctext(cr, cx, y, s, c, size, bold)
|
local function rtext(cr, xr, y, s, c, size, bold)
|
||||||
local tw = #s * (size or 12) * 0.6
|
text(cr, xr - #s * (size or 12) * 0.6, y, s, c, size, bold)
|
||||||
text(cr, cx - tw / 2, y, s, c, size, bold)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bar(cr, x, y, w, h, frac, c)
|
local function bar(cr, x, y, w, h, frac, c)
|
||||||
@@ -117,6 +154,30 @@ local function bar(cr, x, y, w, h, frac, c)
|
|||||||
setcol(cr, c); rrect(cr, x, y, math.max(2, w * frac), h, 3); cairo_fill(cr)
|
setcol(cr, c); rrect(cr, x, y, math.max(2, w * frac), h, 3); cairo_fill(cr)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Grafico de linea sobre un panel redondeado ---------------------------------
|
||||||
|
local function graph(cr, x, y, w, h, series)
|
||||||
|
setcol(cr, COL.panel); rrect(cr, x, y, w, h, 4); cairo_fill(cr)
|
||||||
|
-- Maximo comun a todas las series (fijo si se indica)
|
||||||
|
local maxv = 1
|
||||||
|
for _, s in ipairs(series) do
|
||||||
|
if s.max then
|
||||||
|
if s.max > maxv then maxv = s.max end
|
||||||
|
else
|
||||||
|
for i = 1, #s.data do if s.data[i] > maxv then maxv = s.data[i] end end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, s in ipairs(series) do
|
||||||
|
cairo_set_line_width(cr, 1.3); setcol(cr, s.c)
|
||||||
|
local n = #s.data
|
||||||
|
for i = 1, n do
|
||||||
|
local px = x + (i - 1) / (n - 1) * w
|
||||||
|
local py = y + h - (s.data[i] / maxv) * (h - 4) - 2
|
||||||
|
if i == 1 then cairo_move_to(cr, px, py) else cairo_line_to(cr, px, py) end
|
||||||
|
end
|
||||||
|
cairo_stroke(cr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Barra de pestañas ----------------------------------------------------------
|
-- Barra de pestañas ----------------------------------------------------------
|
||||||
local function draw_tabs(cr)
|
local function draw_tabs(cr)
|
||||||
local tw = W / 3
|
local tw = W / 3
|
||||||
@@ -125,33 +186,12 @@ local function draw_tabs(cr)
|
|||||||
local active = (i == current_tab)
|
local active = (i == current_tab)
|
||||||
setcol(cr, active and COL.tab_active or COL.tab_inactive)
|
setcol(cr, active and COL.tab_active or COL.tab_inactive)
|
||||||
rrect(cr, x + 3, TAB_TOP, tw - 6, TAB_H, 5); cairo_fill(cr)
|
rrect(cr, x + 3, TAB_TOP, tw - 6, TAB_H, 5); cairo_fill(cr)
|
||||||
ctext(cr, x + tw / 2, TAB_TOP + 17, TABS[i],
|
local lbl = TABS[i]
|
||||||
|
text(cr, x + tw / 2 - #lbl * 12 * 0.6 / 2, TAB_TOP + 17, lbl,
|
||||||
active and COL.white or COL.dim, 12, active)
|
active and COL.white or COL.dim, 12, active)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Grafico de red en vivo -----------------------------------------------------
|
|
||||||
local function draw_netgraph(cr, x, y, w, h)
|
|
||||||
setcol(cr, COL.panel); rrect(cr, x, y, w, h, 6); cairo_fill(cr)
|
|
||||||
local maxv = 1
|
|
||||||
for i = 1, HIST do
|
|
||||||
if down_hist[i] > maxv then maxv = down_hist[i] end
|
|
||||||
if up_hist[i] > maxv then maxv = up_hist[i] end
|
|
||||||
end
|
|
||||||
local function plot(hist, c)
|
|
||||||
cairo_set_line_width(cr, 1.5); setcol(cr, c)
|
|
||||||
for i = 1, HIST do
|
|
||||||
local px = x + (i - 1) / (HIST - 1) * w
|
|
||||||
local py = y + h - (hist[i] / maxv) * (h - 6) - 3
|
|
||||||
if i == 1 then cairo_move_to(cr, px, py) else cairo_line_to(cr, px, py) end
|
|
||||||
end
|
|
||||||
cairo_stroke(cr)
|
|
||||||
end
|
|
||||||
plot(down_hist, COL.down)
|
|
||||||
plot(up_hist, COL.up)
|
|
||||||
text(cr, x + 5, y + 12, string.format("max %.0f KiB/s", maxv), COL.dim, 8)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Botones de la pestaña Red --------------------------------------------------
|
-- Botones de la pestaña Red --------------------------------------------------
|
||||||
local function draw_buttons(cr)
|
local function draw_buttons(cr)
|
||||||
local bw = (W - 24) / 3
|
local bw = (W - 24) / 3
|
||||||
@@ -160,77 +200,98 @@ local function draw_buttons(cr)
|
|||||||
setcol(cr, COL.tab_inactive); rrect(cr, bx, BTN_Y, bw, BTN_H, 6); cairo_fill(cr)
|
setcol(cr, COL.tab_inactive); rrect(cr, bx, BTN_Y, bw, BTN_H, 6); cairo_fill(cr)
|
||||||
setcol(cr, COL.tab_active, 0.9); cairo_set_line_width(cr, 1)
|
setcol(cr, COL.tab_active, 0.9); cairo_set_line_width(cr, 1)
|
||||||
rrect(cr, bx, BTN_Y, bw, BTN_H, 6); cairo_stroke(cr)
|
rrect(cr, bx, BTN_Y, bw, BTN_H, 6); cairo_stroke(cr)
|
||||||
ctext(cr, bx + bw / 2, BTN_Y + 18, BTNS[i].label, COL.text, 10)
|
local lbl = BTNS[i].label
|
||||||
|
text(cr, bx + bw / 2 - #lbl * 10 * 0.6 / 2, BTN_Y + 17, lbl, COL.text, 10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Panel: Red -----------------------------------------------------------------
|
-- Panel: Red -----------------------------------------------------------------
|
||||||
local function draw_red(cr)
|
local function draw_red(cr)
|
||||||
local y = 50
|
local y = 50
|
||||||
text(cr, 14, y, "Interfaz " .. NIF, COL.dim, 11); y = y + 22
|
text(cr, 12, y, "Interfaz " .. NIF, COL.dim, 11); y = y + 22
|
||||||
|
|
||||||
text(cr, 14, y, "Down", COL.down, 12)
|
text(cr, 12, y, "Down", COL.down, 12)
|
||||||
text(cr, 90, y, str("${downspeed " .. NIF .. "}"), COL.text, 13, true); y = y + 20
|
text(cr, 90, y, str("${downspeed " .. NIF .. "}"), COL.text, 13, true); y = y + 20
|
||||||
text(cr, 14, y, "Up", COL.up, 12)
|
text(cr, 12, y, "Up", COL.up, 12)
|
||||||
text(cr, 90, y, str("${upspeed " .. NIF .. "}"), COL.text, 13, true); y = y + 24
|
text(cr, 90, y, str("${upspeed " .. NIF .. "}"), COL.text, 13, true); y = y + 24
|
||||||
|
|
||||||
draw_netgraph(cr, 14, y, W - 28, 78); y = y + 90
|
graph(cr, 12, y, W - 24, 70, {
|
||||||
|
{ data = hist.down, c = COL.down },
|
||||||
|
{ data = hist.up, c = COL.up },
|
||||||
|
})
|
||||||
|
y = y + 78
|
||||||
|
|
||||||
local conns = str("${execi 2 ss -tun state established 2>/dev/null | tail -n +2 | wc -l}")
|
local conns = str("${execi 2 ss -tun state established 2>/dev/null | tail -n +2 | wc -l}")
|
||||||
text(cr, 14, y, "Conexiones activas: " .. conns, COL.text, 11); y = y + 18
|
text(cr, 12, y, "Conexiones activas: " .. conns, COL.text, 11); y = y + 16
|
||||||
text(cr, 14, y, "Total ↓ " .. str("${totaldown " .. NIF .. "}") ..
|
text(cr, 12, y, "Total ↓ " .. str("${totaldown " .. NIF .. "}") ..
|
||||||
" ↑ " .. str("${totalup " .. NIF .. "}"), COL.dim, 10)
|
" ↑ " .. str("${totalup " .. NIF .. "}"), COL.dim, 10)
|
||||||
|
|
||||||
draw_buttons(cr)
|
draw_buttons(cr)
|
||||||
|
|
||||||
|
text(cr, 12, BTN_Y + BTN_H + 18,
|
||||||
|
"Wireshark abre el buffer de captura mas reciente.", COL.dim, 9)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Panel: Sistema -------------------------------------------------------------
|
-- Panel: Sistema (portado del widget previo) ---------------------------------
|
||||||
local function draw_sys(cr)
|
local function draw_sys(cr)
|
||||||
local y = 50
|
local x = 10
|
||||||
|
local gw = W - 20
|
||||||
|
local y = 38
|
||||||
|
|
||||||
local cpu = num("${cpu cpu0}")
|
local function row(label, value, lc, gh)
|
||||||
text(cr, 14, y, "CPU", COL.text, 12, true)
|
text(cr, x, y + 11, label, lc, 11, true)
|
||||||
text(cr, W - 52, y, string.format("%d%%", cpu), COL.text, 12)
|
if value and value ~= "" then rtext(cr, W - 10, y + 11, value, COL.snow, 10) end
|
||||||
y = y + 6
|
y = y + 15
|
||||||
bar(cr, 14, y, W - 28, 8, cpu / 100, cpu > 80 and COL.red or COL.green)
|
return gh
|
||||||
y = y + 18
|
|
||||||
|
|
||||||
local nproc = math.floor(num("${exec nproc}"))
|
|
||||||
if nproc < 1 then nproc = 1 elseif nproc > 16 then nproc = 16 end
|
|
||||||
local cw = (W - 28) / nproc
|
|
||||||
for i = 1, nproc do
|
|
||||||
local cu = num("${cpu cpu" .. i .. "}")
|
|
||||||
bar(cr, 14 + (i - 1) * cw, y, cw - 2, 6, cu / 100,
|
|
||||||
cu > 80 and COL.red or COL.green)
|
|
||||||
end
|
end
|
||||||
y = y + 20
|
|
||||||
|
|
||||||
local memp = num("${memperc}")
|
local cputemp = str("${execi 3 " .. MET .. " cpu_temp}")
|
||||||
text(cr, 14, y, "RAM", COL.text, 12, true)
|
local gputemp = str("${execi 2 " .. MET .. " gpu_temp}")
|
||||||
text(cr, W - 150, y, str("${mem}") .. " / " .. str("${memmax}"), COL.dim, 9)
|
|
||||||
y = y + 6
|
|
||||||
bar(cr, 14, y, W - 28, 8, memp / 100, memp > 85 and COL.red or COL.orange)
|
|
||||||
y = y + 18
|
|
||||||
|
|
||||||
local swapp = num("${swapperc}")
|
-- CPU
|
||||||
text(cr, 14, y, "Swap", COL.text, 12, true)
|
local gh = row("CPU " .. math.floor(num("${cpu cpu0}")) .. "%",
|
||||||
text(cr, W - 150, y, str("${swap}") .. " / " .. str("${swapmax}"), COL.dim, 9)
|
str("${freq_g}") .. "GHz " .. cputemp .. "°C", COL.teal, 26)
|
||||||
y = y + 6
|
graph(cr, x, y, gw, gh, { { data = hist.cpu, c = COL.green, max = 100 } }); y = y + gh + 4
|
||||||
bar(cr, 14, y, W - 28, 8, swapp / 100, COL.orange)
|
|
||||||
y = y + 18
|
|
||||||
|
|
||||||
local diskp = num("${fs_used_perc /}")
|
-- RAM
|
||||||
text(cr, 14, y, "Disco /", COL.text, 12, true)
|
gh = row("RAM " .. math.floor(num("${memperc}")) .. "%",
|
||||||
text(cr, W - 150, y, str("${fs_used /}") .. " / " .. str("${fs_size /}"), COL.dim, 9)
|
str("${mem}") .. " / " .. str("${memmax}"), COL.green, 26)
|
||||||
y = y + 6
|
graph(cr, x, y, gw, gh, { { data = hist.ram, c = COL.green, max = 100 } }); y = y + gh + 4
|
||||||
bar(cr, 14, y, W - 28, 8, diskp / 100, diskp > 90 and COL.red or COL.green)
|
|
||||||
y = y + 24
|
|
||||||
|
|
||||||
local traw = tonumber(str("${execi 5 cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null}"))
|
-- CPU TEMP
|
||||||
local tstr = traw and string.format("%.0f°C", traw / 1000) or "n/a"
|
gh = row("CPU TEMP " .. cputemp .. "°C", "", COL.yellow, 20)
|
||||||
text(cr, 14, y, "Temp " .. tstr, COL.dim, 10)
|
graph(cr, x, y, gw, gh, { { data = hist.cputemp, c = COL.yellow, max = 100 } }); y = y + gh + 4
|
||||||
text(cr, W - 150, y, "Load " .. str("${loadavg 1}"), COL.dim, 10); y = y + 16
|
|
||||||
text(cr, 14, y, "Uptime " .. str("${uptime_short}"), COL.dim, 10)
|
-- GPU
|
||||||
|
gh = row("GPU " .. str("${execi 2 " .. MET .. " gpu_util}") .. "%",
|
||||||
|
gputemp .. "°C", COL.cyan, 26)
|
||||||
|
graph(cr, x, y, gw, gh, { { data = hist.gputil, c = COL.cyan, max = 100 } }); y = y + gh + 4
|
||||||
|
|
||||||
|
-- GPU TEMP
|
||||||
|
gh = row("GPU TEMP " .. gputemp .. "°C", "", COL.yellow, 20)
|
||||||
|
graph(cr, x, y, gw, gh, { { data = hist.gputemp, c = COL.yellow, max = 100 } }); y = y + gh + 4
|
||||||
|
|
||||||
|
-- VRAM
|
||||||
|
gh = row("VRAM " .. str("${execi 2 " .. MET .. " gpu_memp}") .. "%",
|
||||||
|
str("${execi 2 " .. MET .. " gpu_memi}"), COL.purple, 26)
|
||||||
|
graph(cr, x, y, gw, gh, { { data = hist.vram, c = COL.purple, max = 100 } }); y = y + gh + 4
|
||||||
|
|
||||||
|
-- DISK I/O
|
||||||
|
gh = row("DISK I/O", str("${diskio}"), COL.orange, 26)
|
||||||
|
graph(cr, x, y, gw, gh, { { data = hist.diskio, c = COL.purple } }); y = y + gh + 6
|
||||||
|
|
||||||
|
-- Uso de discos
|
||||||
|
text(cr, x, y + 10, "USO DE DISCOS", COL.snow, 10, true); y = y + 16
|
||||||
|
local disks = { "/", "/mnt/1tb", "/mnt/2tb", "/mnt/16tb" }
|
||||||
|
for _, m in ipairs(disks) do
|
||||||
|
local p = num("${fs_used_perc " .. m .. "}")
|
||||||
|
text(cr, x, y + 9, m, COL.green, 10)
|
||||||
|
rtext(cr, W - 10, y + 9,
|
||||||
|
str("${fs_used " .. m .. "}") .. "/" .. str("${fs_size " .. m .. "}") ..
|
||||||
|
" " .. math.floor(p) .. "%", COL.dim, 9)
|
||||||
|
y = y + 12
|
||||||
|
bar(cr, x, y, gw, 6, p / 100, p > 90 and COL.red or COL.green); y = y + 11
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Panel: Docker --------------------------------------------------------------
|
-- Panel: Docker --------------------------------------------------------------
|
||||||
@@ -238,19 +299,19 @@ local function draw_docker(cr)
|
|||||||
local y = 50
|
local y = 50
|
||||||
local running = str("${execi 3 docker ps -q 2>/dev/null | wc -l}")
|
local running = str("${execi 3 docker ps -q 2>/dev/null | wc -l}")
|
||||||
local total = str("${execi 10 docker ps -aq 2>/dev/null | wc -l}")
|
local total = str("${execi 10 docker ps -aq 2>/dev/null | wc -l}")
|
||||||
text(cr, 14, y, "Contenedores", COL.text, 12, true)
|
text(cr, 12, y, "Contenedores", COL.text, 12, true)
|
||||||
text(cr, W - 110, y, running .. " up / " .. total .. " total", COL.dim, 10)
|
rtext(cr, W - 10, y, running .. " up / " .. total .. " total", COL.dim, 10)
|
||||||
y = y + 22
|
y = y + 22
|
||||||
|
|
||||||
local names = str("${execi 3 docker ps --format '{{.Names}}' 2>/dev/null | head -16}")
|
local names = str("${execi 3 docker ps --format '{{.Names}}' 2>/dev/null | head -28}")
|
||||||
if names == "" then
|
if names == "" then
|
||||||
text(cr, 18, y, "ninguno en marcha", COL.dim, 10)
|
text(cr, 16, y, "ninguno en marcha", COL.dim, 10)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for line in names:gmatch("[^\n]+") do
|
for line in names:gmatch("[^\n]+") do
|
||||||
text(cr, 18, y, "● " .. line, COL.green, 10)
|
text(cr, 16, y, "● " .. line, COL.green, 10)
|
||||||
y = y + 15
|
y = y + 15
|
||||||
if y > H - 16 then break end
|
if y > H - 14 then break end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -262,9 +323,16 @@ function conky_draw()
|
|||||||
conky_window.width, conky_window.height)
|
conky_window.width, conky_window.height)
|
||||||
local cr = cairo_create(cs)
|
local cr = cairo_create(cs)
|
||||||
|
|
||||||
-- Mantener el historico de red vivo en todas las pestañas.
|
-- Mantener todos los historicos vivos en cualquier pestaña.
|
||||||
push(down_hist, num("${downspeedf " .. NIF .. "}"))
|
push(hist.cpu, num("${cpu cpu0}"))
|
||||||
push(up_hist, num("${upspeedf " .. NIF .. "}"))
|
push(hist.ram, num("${memperc}"))
|
||||||
|
push(hist.cputemp, num("${execi 3 " .. MET .. " cpu_temp}"))
|
||||||
|
push(hist.gputil, num("${execi 2 " .. MET .. " gpu_util}"))
|
||||||
|
push(hist.gputemp, num("${execi 2 " .. MET .. " gpu_temp}"))
|
||||||
|
push(hist.vram, num("${execi 2 " .. MET .. " gpu_memp}"))
|
||||||
|
push(hist.diskio, rate_kib(str("${diskio}")))
|
||||||
|
push(hist.down, num("${downspeedf " .. NIF .. "}"))
|
||||||
|
push(hist.up, num("${upspeedf " .. NIF .. "}"))
|
||||||
|
|
||||||
setcol(cr, COL.bg, 0.86); rrect(cr, 0, 0, W, H, 10); cairo_fill(cr)
|
setcol(cr, COL.bg, 0.86); rrect(cr, 0, 0, W, H, 10); cairo_fill(cr)
|
||||||
|
|
||||||
@@ -287,9 +355,8 @@ local function shell_quote(s)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function launch(b)
|
local function launch(b)
|
||||||
local cmd = string.format("%s %s %s %s &",
|
os.execute(string.format("%s %s %s %s &",
|
||||||
shell_quote(LAUNCH), shell_quote(b.bin), shell_quote(b.pkg), shell_quote(b.cmd))
|
shell_quote(LAUNCH), shell_quote(b.bin), shell_quote(b.pkg), shell_quote(b.cmd)))
|
||||||
os.execute(cmd)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Hook de raton: cambia de pestaña y lanza apps ------------------------------
|
-- Hook de raton: cambia de pestaña y lanza apps ------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Helper de metricas para conky_widget — imprime UN valor "pelado" (sin etiquetas).
|
||||||
|
# Portado del widget previo. Toda la logica con comillas/awk vive aqui para no
|
||||||
|
# romper el parser de conky ni el de widget.lua.
|
||||||
|
case "$1" in
|
||||||
|
gpu_util) nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits ;;
|
||||||
|
gpu_temp) nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits ;;
|
||||||
|
gpu_memp) nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits \
|
||||||
|
| awk -F', ' '{printf "%d", $1/$2*100}' ;;
|
||||||
|
gpu_memi) nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits \
|
||||||
|
| awk -F', ' '{printf "%d/%d MB", $1, $2}' ;;
|
||||||
|
cpu_temp) for h in /sys/class/hwmon/hwmon*; do
|
||||||
|
[ "$(cat "$h/name" 2>/dev/null)" = coretemp ] && { cat "$h/temp1_input"; break; }
|
||||||
|
done | awk '{printf "%d", $1/1000}' ;;
|
||||||
|
*) echo 0 ;;
|
||||||
|
esac
|
||||||
Executable
+48
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Instala el servicio systemd packet-capture (dumpcap ring buffer ~10 min).
|
||||||
|
# Crea el directorio de captura propiedad del usuario, copia el unit, lo activa
|
||||||
|
# y muestra su estado. Requiere privilegios sudo (los pedirá si no están en caché).
|
||||||
|
#
|
||||||
|
# Uso: install-capture.sh [interfaz] (por defecto enp5s0)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
UNIT_SRC="$SCRIPT_DIR/packet-capture.service"
|
||||||
|
UNIT_DST="/etc/systemd/system/packet-capture.service"
|
||||||
|
CAP_DIR="/var/log/pktcap"
|
||||||
|
USER_NAME="${SUDO_USER:-$USER}"
|
||||||
|
IFACE="${1:-enp5s0}"
|
||||||
|
|
||||||
|
echo "==> packet-capture install (interfaz: $IFACE, usuario: $USER_NAME)"
|
||||||
|
|
||||||
|
if ! command -v dumpcap >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: dumpcap no instalado. Instalar: sudo apt install wireshark" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. Directorio de captura, propiedad del usuario que ejecuta dumpcap
|
||||||
|
sudo mkdir -p "$CAP_DIR"
|
||||||
|
sudo chown "$USER_NAME:$USER_NAME" "$CAP_DIR"
|
||||||
|
sudo chmod 750 "$CAP_DIR"
|
||||||
|
echo " dir: $CAP_DIR (owner $USER_NAME)"
|
||||||
|
|
||||||
|
# 2. Instalar el unit, ajustando interfaz y usuario
|
||||||
|
sudo cp "$UNIT_SRC" "$UNIT_DST"
|
||||||
|
sudo sed -i \
|
||||||
|
-e "s|-i enp5s0|-i $IFACE|" \
|
||||||
|
-e "s|^User=.*|User=$USER_NAME|" \
|
||||||
|
-e "s|^Group=.*|Group=$USER_NAME|" \
|
||||||
|
"$UNIT_DST"
|
||||||
|
echo " unit: $UNIT_DST"
|
||||||
|
|
||||||
|
# 3. Activar y arrancar
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now packet-capture.service
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo "==> Estado:"
|
||||||
|
sudo systemctl --no-pager --full status packet-capture.service | head -12 || true
|
||||||
|
echo "==> Capturas en $CAP_DIR:"
|
||||||
|
ls -lh "$CAP_DIR" 2>/dev/null | tail -3 || true
|
||||||
|
echo "==> Parar: sudo systemctl stop packet-capture.service"
|
||||||
|
echo "==> Logs: journalctl -u packet-capture.service -f"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Packet capture ring buffer (~10 min, dumpcap) for conky_widget
|
||||||
|
Documentation=https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/conky_widget
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# dumpcap escribe un ring buffer rotativo: 10 archivos de hasta 60s o 50MB cada
|
||||||
|
# uno, lo que ocurra antes. Resultado: siempre los ultimos ~10 minutos de
|
||||||
|
# trafico en disco (tope ~500MB para no llenar el disco con descargas grandes).
|
||||||
|
#
|
||||||
|
# Variantes utiles (editar la linea ExecStart):
|
||||||
|
# - Solo cabeceras (mucho mas ligero): añadir -s 96
|
||||||
|
# - Ver dominios (SNI/DNS) sin payload: añadir -s 320
|
||||||
|
# - Filtrar una IP/puerto: añadir -f "host 1.2.3.4"
|
||||||
|
Type=exec
|
||||||
|
User=enmanuel
|
||||||
|
Group=enmanuel
|
||||||
|
SupplementaryGroups=wireshark
|
||||||
|
ExecStart=/usr/bin/dumpcap -i enp5s0 -b duration:60 -b files:10 -b filesize:51200 -w /var/log/pktcap/cap.pcapng
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
Nice=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Reference in New Issue
Block a user