TUI is now more optimized

This commit is contained in:
Sam
2026-01-29 01:46:17 -06:00
parent 1ab375593d
commit a6db1beaab

View File

@@ -1122,17 +1122,8 @@ show_dashboard() {
local snap_file="$INSTALL_DIR/traffic_stats/tracker_snapshot" local snap_file="$INSTALL_DIR/traffic_stats/tracker_snapshot"
local data_file="$INSTALL_DIR/traffic_stats/cumulative_data" local data_file="$INSTALL_DIR/traffic_stats/cumulative_data"
if [ -s "$snap_file" ] || [ -s "$data_file" ]; then if [ -s "$snap_file" ] || [ -s "$data_file" ]; then
# Get actual total connected clients from docker logs # Reuse connected count from show_status (already cached)
local dash_clients=0 local dash_clients=${_total_connected:-0}
local dash_ps=$(docker ps --format '{{.Names}}' 2>/dev/null)
for ci in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $ci)
if echo "$dash_ps" | grep -q "^${cname}$"; then
local lg=$(docker logs --tail 50 "$cname" 2>&1 | grep "\[STATS\]" | tail -1)
local cn=$(echo "$lg" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p')
[[ "$cn" =~ ^[0-9]+$ ]] && dash_clients=$((dash_clients + cn))
fi
done
# Left column: Active Clients per country (estimated from snapshot distribution) # Left column: Active Clients per country (estimated from snapshot distribution)
local left_lines=() local left_lines=()
@@ -1164,13 +1155,14 @@ show_dashboard() {
# Right column: Top 5 Upload (cumulative outbound bytes per country) # Right column: Top 5 Upload (cumulative outbound bytes per country)
local right_lines=() local right_lines=()
if [ -s "$data_file" ]; then if [ -s "$data_file" ]; then
local top5_upload local all_upload
top5_upload=$(awk -F'|' '{if($1!="" && $3+0>0) print $3"|"$1}' "$data_file" 2>/dev/null | sort -t'|' -k1 -nr | head -5) all_upload=$(awk -F'|' '{if($1!="" && $3+0>0) print $3"|"$1}' "$data_file" 2>/dev/null | sort -t'|' -k1 -nr)
local top5_upload=$(echo "$all_upload" | head -5)
local total_upload=0 local total_upload=0
if [ -n "$top5_upload" ]; then if [ -n "$all_upload" ]; then
while IFS='|' read -r bytes co; do while IFS='|' read -r bytes co; do
total_upload=$((total_upload + bytes)) total_upload=$((total_upload + bytes))
done < <(awk -F'|' '{if($1!="" && $3+0>0) print $3"|"$1}' "$data_file" 2>/dev/null) done <<< "$all_upload"
fi fi
[ "$total_upload" -eq 0 ] && total_upload=1 [ "$total_upload" -eq 0 ] && total_upload=1
if [ -n "$top5_upload" ]; then if [ -n "$top5_upload" ]; then
@@ -1233,51 +1225,35 @@ show_dashboard() {
get_container_stats() { get_container_stats() {
# Get CPU and RAM usage across all conduit containers # Get CPU and RAM usage across all conduit containers
# Returns: "CPU_PERCENT RAM_USAGE" # Returns: "CPU_PERCENT RAM_USAGE"
if [ "$CONTAINER_COUNT" -le 1 ]; then # Single docker stats call for all containers at once
local stats=$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" conduit 2>/dev/null) local names=""
if [ -z "$stats" ]; then for i in $(seq 1 $CONTAINER_COUNT); do
echo "0% 0MiB" names+=" $(get_container_name $i)"
else done
echo "$stats" local all_stats=$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" $names 2>/dev/null)
fi if [ -z "$all_stats" ]; then
echo "0% 0MiB"
elif [ "$CONTAINER_COUNT" -le 1 ]; then
echo "$all_stats"
else else
# Aggregate stats across all containers # Single awk to aggregate all container stats at once
local total_cpu=0 echo "$all_stats" | awk '{
local total_mem=0 # CPU: strip % and sum
local mem_limit="" cpu = $1; gsub(/%/, "", cpu); total_cpu += cpu + 0
local any_found=false # Memory used: convert to MiB and sum
for i in $(seq 1 $CONTAINER_COUNT); do mem = $2; gsub(/[^0-9.]/, "", mem); mem += 0
local name=$(get_container_name $i) if ($2 ~ /GiB/) mem *= 1024
local stats=$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" "$name" 2>/dev/null) else if ($2 ~ /KiB/) mem /= 1024
if [ -n "$stats" ]; then total_mem += mem
any_found=true # Memory limit: take first one
local cpu=$(echo "$stats" | awk '{print $1}' | tr -d '%') if (mem_limit == "") mem_limit = $4
total_cpu=$(awk -v a="$total_cpu" -v b="$cpu" 'BEGIN{printf "%.2f", a+b}') found = 1
# Parse mem: "123.4MiB / 1.5GiB" } END {
local mem_used=$(echo "$stats" | awk '{print $2}') if (!found) { print "0% 0MiB"; exit }
if [ -z "$mem_limit" ]; then if (total_mem >= 1024) mem_display = sprintf("%.2fGiB", total_mem/1024)
mem_limit=$(echo "$stats" | awk '{print $4}') else mem_display = sprintf("%.1fMiB", total_mem)
fi printf "%.2f%% %s / %s\n", total_cpu, mem_display, mem_limit
# Convert to MiB for summing }'
local mem_val=$(echo "$mem_used" | sed 's/[^0-9.]//g')
if echo "$mem_used" | grep -qi "gib"; then
mem_val=$(awk -v v="$mem_val" 'BEGIN{printf "%.1f", v*1024}')
fi
total_mem=$(awk -v a="$total_mem" -v b="$mem_val" 'BEGIN{printf "%.1f", a+b}')
fi
done
if [ "$any_found" = true ]; then
# Format mem back
local mem_display
if [ "$(echo "$total_mem" | awk '{print ($1 >= 1024)}')" = "1" ]; then
mem_display=$(awk -v m="$total_mem" 'BEGIN{printf "%.2fGiB", m/1024}')
else
mem_display="${total_mem}MiB"
fi
echo "${total_cpu}% ${mem_display} / ${mem_limit}"
else
echo "0% 0MiB"
fi
fi fi
} }
@@ -1329,24 +1305,29 @@ get_system_stats() {
local sys_ram_pct="N/A" local sys_ram_pct="N/A"
if command -v free &>/dev/null; then if command -v free &>/dev/null; then
# Output: used total percentage # Single free -m call: MiB values for percentage + display
local ram_data=$(free -m 2>/dev/null | awk '/^Mem:/{printf "%s %s %.2f%%", $3, $2, ($3/$2)*100}') local free_out=$(free -m 2>/dev/null)
local ram_human=$(free -h 2>/dev/null | awk '/^Mem:/{print $3 " " $2}') if [ -n "$free_out" ]; then
read -r sys_ram_used sys_ram_total sys_ram_pct <<< $(echo "$free_out" | awk '/^Mem:/{
sys_ram_used=$(echo "$ram_human" | awk '{print $1}') used_mb=$3; total_mb=$2
sys_ram_total=$(echo "$ram_human" | awk '{print $2}') pct = (total_mb > 0) ? (used_mb/total_mb)*100 : 0
sys_ram_pct=$(echo "$ram_data" | awk '{print $3}') if (total_mb >= 1024) { total_str=sprintf("%.1fGiB", total_mb/1024) } else { total_str=sprintf("%.1fMiB", total_mb) }
if (used_mb >= 1024) { used_str=sprintf("%.1fGiB", used_mb/1024) } else { used_str=sprintf("%.1fMiB", used_mb) }
printf "%s %s %.2f%%", used_str, total_str, pct
}')
fi
fi fi
echo "$sys_cpu $sys_ram_used $sys_ram_total $sys_ram_pct" echo "$sys_cpu $sys_ram_used $sys_ram_total $sys_ram_pct"
} }
show_live_stats() { show_live_stats() {
# Check if any container is running # Check if any container is running (single docker ps call)
local ps_cache=$(docker ps --format '{{.Names}}' 2>/dev/null)
local any_running=false local any_running=false
for i in $(seq 1 $CONTAINER_COUNT); do for i in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $i) local cname=$(get_container_name $i)
if docker ps 2>/dev/null | grep -q "[[:space:]]${cname}$"; then if echo "$ps_cache" | grep -q "^${cname}$"; then
any_running=true any_running=true
break break
fi fi
@@ -1379,7 +1360,7 @@ show_live_stats() {
for i in $(seq 1 $CONTAINER_COUNT); do for i in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $i) local cname=$(get_container_name $i)
local status="${RED}Stopped${NC}" local status="${RED}Stopped${NC}"
docker ps 2>/dev/null | grep -q "[[:space:]]${cname}$" && status="${GREEN}Running${NC}" echo "$ps_cache" | grep -q "^${cname}$" && status="${GREEN}Running${NC}"
echo -e " ${i}. ${cname} [${status}]" echo -e " ${i}. ${cname} [${status}]"
done done
echo "" echo ""
@@ -1733,7 +1714,8 @@ show_advanced_stats() {
while [ "$exit_stats" -eq 0 ]; do while [ "$exit_stats" -eq 0 ]; do
local now=$(date +%s) local now=$(date +%s)
local term_height=$(tput lines 2>/dev/null || echo 24) local term_height=$(stty size </dev/tty 2>/dev/null | awk '{print $1}')
[ -z "$term_height" ] || [ "$term_height" -lt 10 ] 2>/dev/null && term_height=$(tput lines 2>/dev/null || echo "${LINES:-24}")
local cycle_elapsed=$(( (now - cycle_start) % 15 )) local cycle_elapsed=$(( (now - cycle_start) % 15 ))
local time_until_next=$((15 - cycle_elapsed)) local time_until_next=$((15 - cycle_elapsed))
@@ -1762,16 +1744,28 @@ show_advanced_stats() {
local total_mem_mib=0 first_mem_limit="" local total_mem_mib=0 first_mem_limit=""
echo -e "${CYAN}║${NC} ${GREEN}CONTAINER${NC} ${DIM}|${NC} ${YELLOW}NETWORK${NC} ${DIM}|${NC} ${MAGENTA}TRACKER${NC}\033[K" echo -e "${CYAN}║${NC} ${GREEN}CONTAINER${NC} ${DIM}|${NC} ${YELLOW}NETWORK${NC} ${DIM}|${NC} ${MAGENTA}TRACKER${NC}\033[K"
# Single docker stats call for all running containers
local adv_running_names=""
for ci in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $ci)
echo "$docker_ps_cache" | grep -q "^${cname}$" && adv_running_names+=" $cname"
done
local adv_all_stats=""
if [ -n "$adv_running_names" ]; then
adv_all_stats=$(docker stats --no-stream --format "{{.Name}}|{{.CPUPerc}}|{{.MemUsage}}" $adv_running_names 2>/dev/null)
fi
for ci in $(seq 1 $CONTAINER_COUNT); do for ci in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $ci) local cname=$(get_container_name $ci)
if echo "$docker_ps_cache" | grep -q "^${cname}$"; then if echo "$docker_ps_cache" | grep -q "^${cname}$"; then
container_count=$((container_count + 1)) container_count=$((container_count + 1))
local stats=$(docker stats --no-stream --format "{{.CPUPerc}}|{{.MemUsage}}" "$cname" 2>/dev/null) local stats=$(echo "$adv_all_stats" | grep "^${cname}|" 2>/dev/null)
local cpu=$(echo "$stats" | cut -d'|' -f1 | tr -d '%') local cpu=$(echo "$stats" | cut -d'|' -f2 | tr -d '%')
[[ "$cpu" =~ ^[0-9.]+$ ]] && total_cpu=$(awk -v a="$total_cpu" -v b="$cpu" 'BEGIN{printf "%.2f", a+b}') [[ "$cpu" =~ ^[0-9.]+$ ]] && total_cpu=$(awk -v a="$total_cpu" -v b="$cpu" 'BEGIN{printf "%.2f", a+b}')
local cmem_str=$(echo "$stats" | cut -d'|' -f2 | awk '{print $1}') local cmem_str=$(echo "$stats" | cut -d'|' -f3 | awk '{print $1}')
local cmem_val=$(echo "$cmem_str" | sed 's/[^0-9.]//g') local cmem_val=$(echo "$cmem_str" | sed 's/[^0-9.]//g')
local cmem_unit=$(echo "$cmem_str" | sed 's/[0-9.]//g') local cmem_unit=$(echo "$cmem_str" | sed 's/[0-9.]//g')
if [[ "$cmem_val" =~ ^[0-9.]+$ ]]; then if [[ "$cmem_val" =~ ^[0-9.]+$ ]]; then
@@ -1781,7 +1775,7 @@ show_advanced_stats() {
esac esac
total_mem_mib=$(awk -v a="$total_mem_mib" -v b="$cmem_val" 'BEGIN{printf "%.2f", a+b}') total_mem_mib=$(awk -v a="$total_mem_mib" -v b="$cmem_val" 'BEGIN{printf "%.2f", a+b}')
fi fi
[ -z "$first_mem_limit" ] && first_mem_limit=$(echo "$stats" | cut -d'|' -f2 | awk -F'/' '{print $2}' | xargs) [ -z "$first_mem_limit" ] && first_mem_limit=$(echo "$stats" | cut -d'|' -f3 | awk -F'/' '{print $2}' | xargs)
local logs=$(docker logs --tail 50 "$cname" 2>&1 | grep "\[STATS\]" | tail -1) local logs=$(docker logs --tail 50 "$cname" 2>&1 | grep "\[STATS\]" | tail -1)
local conn=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p') local conn=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p')
@@ -1961,7 +1955,8 @@ show_peers() {
while [ $stop_peers -eq 0 ]; do while [ $stop_peers -eq 0 ]; do
local now=$(date +%s) local now=$(date +%s)
local term_height=$(tput lines 2>/dev/null || echo 24) local term_height=$(stty size </dev/tty 2>/dev/null | awk '{print $1}')
[ -z "$term_height" ] || [ "$term_height" -lt 10 ] 2>/dev/null && term_height=$(tput lines 2>/dev/null || echo "${LINES:-24}")
local cycle_elapsed=$(( (now - cycle_start) % 15 )) local cycle_elapsed=$(( (now - cycle_start) % 15 ))
local time_left=$((15 - cycle_elapsed)) local time_left=$((15 - cycle_elapsed))
@@ -2185,24 +2180,36 @@ show_status() {
if echo "$docker_ps_cache" | grep -q "[[:space:]]${cname}$"; then if echo "$docker_ps_cache" | grep -q "[[:space:]]${cname}$"; then
_c_running[$i]=true _c_running[$i]=true
running_count=$((running_count + 1)) running_count=$((running_count + 1))
local logs=$(docker logs --tail 1000 "$cname" 2>&1 | grep "STATS" | tail -1) local logs=$(docker logs --tail 50 "$cname" 2>&1 | grep "STATS" | tail -1)
if [ -n "$logs" ]; then if [ -n "$logs" ]; then
local c_connecting=$(echo "$logs" | sed -n 's/.*Connecting:[[:space:]]*\([0-9]*\).*/\1/p') # Single awk to extract all 5 fields, pipe-delimited
local c_connected=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p') IFS='|' read -r c_connecting c_connected c_up_val c_down_val c_uptime_val <<< $(echo "$logs" | awk '{
cing=0; conn=0; up=""; down=""; ut=""
for(j=1;j<=NF;j++){
if($j=="Connecting:") cing=$(j+1)+0
else if($j=="Connected:") conn=$(j+1)+0
else if($j=="Up:"){for(k=j+1;k<=NF;k++){if($k=="|"||$k~/Down:/)break; up=up (up?" ":"") $k}}
else if($j=="Down:"){for(k=j+1;k<=NF;k++){if($k=="|"||$k~/Uptime:/)break; down=down (down?" ":"") $k}}
else if($j=="Uptime:"){for(k=j+1;k<=NF;k++){ut=ut (ut?" ":"") $k}}
}
printf "%d|%d|%s|%s|%s", cing, conn, up, down, ut
}')
_c_conn[$i]="${c_connected:-0}" _c_conn[$i]="${c_connected:-0}"
_c_cing[$i]="${c_connecting:-0}" _c_cing[$i]="${c_connecting:-0}"
_c_up[$i]=$(echo "$logs" | sed -n 's/.*Up:[[:space:]]*\([^|]*\).*/\1/p' | xargs) _c_up[$i]="${c_up_val}"
_c_down[$i]=$(echo "$logs" | sed -n 's/.*Down:[[:space:]]*\([^|]*\).*/\1/p' | xargs) _c_down[$i]="${c_down_val}"
total_connecting=$((total_connecting + ${c_connecting:-0})) total_connecting=$((total_connecting + ${c_connecting:-0}))
total_connected=$((total_connected + ${c_connected:-0})) total_connected=$((total_connected + ${c_connected:-0}))
if [ -z "$uptime" ]; then if [ -z "$uptime" ]; then
uptime=$(echo "$logs" | sed -n 's/.*Uptime:[[:space:]]*\(.*\)/\1/p' | xargs) uptime="${c_uptime_val}"
fi fi
fi fi
fi fi
done done
local connecting=$total_connecting local connecting=$total_connecting
local connected=$total_connected local connected=$total_connected
# Export for parent function to reuse (avoids duplicate docker logs calls)
_total_connected=$total_connected
# Aggregate upload/download across all containers # Aggregate upload/download across all containers
local upload="" local upload=""
@@ -2824,6 +2831,20 @@ manage_containers() {
# Per-container stats table # Per-container stats table
local docker_ps_cache=$(docker ps --format '{{.Names}}' 2>/dev/null) local docker_ps_cache=$(docker ps --format '{{.Names}}' 2>/dev/null)
# Single docker stats call for all running containers (instead of per-container)
local all_dstats=""
local running_names=""
for ci in $(seq 1 $CONTAINER_COUNT); do
local cname=$(get_container_name $ci)
if echo "$docker_ps_cache" | grep -q "^${cname}$"; then
running_names+=" $cname"
fi
done
if [ -n "$running_names" ]; then
all_dstats=$(docker stats --no-stream --format "{{.Name}} {{.CPUPerc}} {{.MemUsage}}" $running_names 2>/dev/null)
fi
printf " ${BOLD}%-2s %-11s %-8s %-7s %-8s %-8s %-6s %-7s${NC}${EL}\n" \ printf " ${BOLD}%-2s %-11s %-8s %-7s %-8s %-8s %-6s %-7s${NC}${EL}\n" \
"#" "Container" "Status" "Clients" "Up" "Down" "CPU" "RAM" "#" "Container" "Status" "Clients" "Up" "Down" "CPU" "RAM"
echo -e " ${CYAN}─────────────────────────────────────────────────────────${NC}${EL}" echo -e " ${CYAN}─────────────────────────────────────────────────────────${NC}${EL}"
@@ -2837,20 +2858,28 @@ manage_containers() {
if echo "$docker_ps_cache" | grep -q "^${cname}$"; then if echo "$docker_ps_cache" | grep -q "^${cname}$"; then
status_text="Running" status_text="Running"
status_color="${GREEN}" status_color="${GREEN}"
local logs=$(docker logs --tail 1000 "$cname" 2>&1 | grep "STATS" | tail -1) local logs=$(docker logs --tail 50 "$cname" 2>&1 | grep "STATS" | tail -1)
if [ -n "$logs" ]; then if [ -n "$logs" ]; then
local conn=$(echo "$logs" | sed -n 's/.*Connected:[[:space:]]*\([0-9]*\).*/\1/p') IFS='|' read -r conn cing mc_up mc_down <<< $(echo "$logs" | awk '{
local cing=$(echo "$logs" | sed -n 's/.*Connecting:[[:space:]]*\([0-9]*\).*/\1/p') cing=0; conn=0; up=""; down=""
for(j=1;j<=NF;j++){
if($j=="Connecting:") cing=$(j+1)+0
else if($j=="Connected:") conn=$(j+1)+0
else if($j=="Up:"){for(k=j+1;k<=NF;k++){if($k=="|"||$k~/Down:/)break; up=up (up?" ":"") $k}}
else if($j=="Down:"){for(k=j+1;k<=NF;k++){if($k=="|"||$k~/Uptime:/)break; down=down (down?" ":"") $k}}
}
printf "%d|%d|%s|%s", conn, cing, up, down
}')
c_clients="${conn:-0}/${cing:-0}" c_clients="${conn:-0}/${cing:-0}"
c_up=$(echo "$logs" | sed -n 's/.*Up:[[:space:]]*\([^|]*\).*/\1/p' | xargs) c_up="${mc_up:-"-"}"
c_down=$(echo "$logs" | sed -n 's/.*Down:[[:space:]]*\([^|]*\).*/\1/p' | xargs) c_down="${mc_down:-"-"}"
[ -z "$c_up" ] && c_up="-" [ -z "$c_up" ] && c_up="-"
[ -z "$c_down" ] && c_down="-" [ -z "$c_down" ] && c_down="-"
fi fi
local dstats=$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" "$cname" 2>/dev/null) local dstats_line=$(echo "$all_dstats" | grep "^${cname} " 2>/dev/null)
if [ -n "$dstats" ]; then if [ -n "$dstats_line" ]; then
c_cpu=$(echo "$dstats" | awk '{print $1}') c_cpu=$(echo "$dstats_line" | awk '{print $2}')
c_ram=$(echo "$dstats" | awk '{print $2}') c_ram=$(echo "$dstats_line" | awk '{print $3}')
fi fi
else else
status_text="Stopped" status_text="Stopped"
@@ -4263,3 +4292,5 @@ main() {
# REACHED END OF SCRIPT - VERSION 1.1 # REACHED END OF SCRIPT - VERSION 1.1
# ############################################################################### # ###############################################################################
main "$@" main "$@"