gistfile1.txt
· 8.2 KiB · Text
Sin formato
function cmd::activity::run() {
local filter_peer="" filter_service="" filter_ip="" filter_type=""
local hours=24 dropped_only=false
local accept_only=false drop_only=false external_only=false
while [[ $# -gt 0 ]]; do
case "$1" in
--peer) filter_peer="$2"; shift 2 ;;
--service) filter_service="$2"; shift 2 ;;
--ip) filter_ip="$2"; shift 2 ;;
--type) filter_type="$2"; shift 2 ;;
--hours) hours="$2"; shift 2 ;;
--dropped) dropped_only=true; shift ;;
--accept) accept_only=true; shift ;;
--drop) drop_only=true; shift ;;
--external) external_only=true; shift ;;
--help) cmd::activity::help; return ;;
*)
log::error "Unknown flag: $1"
cmd::activity::help
return 1
;;
esac
done
if command::json; then
cmd::activity::_output_json "$hours"
return 0
fi
# Resolve peer name if type provided
if [[ -n "$filter_peer" && -n "$filter_type" ]]; then
filter_peer=$(peers::resolve_and_require "$filter_peer" "$filter_type") || return 1
fi
# Resolve --service to IP
local service_ip=""
if [[ -n "$filter_service" ]]; then
service_ip=$(net::resolve "$filter_service" 2>/dev/null | head -1 | cut -d: -f1) || true
if [[ -z "$service_ip" ]]; then
log::error "Service not found: ${filter_service}"
return 1
fi
fi
[[ -n "$filter_ip" ]] && service_ip="$filter_ip"
# Fetch drop/handshake data
local data=""
if ! $accept_only; then
data=$(json::activity_aggregate \
"$(ctx::fw_events_log)" \
"$(ctx::events_log)" \
"$(config::interface)" \
"$(ctx::net)" \
"$(ctx::clients)" \
"$(ctx::meta)" \
"$hours" \
"$filter_peer" \
"$service_ip" 2>/dev/null)
fi
# Fetch accept data
local accept_data=""
if ! $drop_only; then
local since_arg=""
[[ "$hours" -gt 0 ]] && since_arg="${hours}h"
local ext_flag="0"
$external_only && ext_flag="1"
[[ -f "$(ctx::accept_events_log)" ]] && \
accept_data=$(json::accept_aggregate \
"$(ctx::accept_events_log)" \
"$(ctx::net)" \
"$(ctx::clients)" \
"$since_arg" \
"$filter_peer" \
"$ext_flag" \
2>/dev/null)
fi
if [[ -z "$data" && -z "$accept_data" ]]; then
log::wg_warning "No activity data found"
return 0
fi
# Build accept lookup maps
declare -gA _ACCEPT_PEER=()
declare -gA _ACCEPT_DEST_KEYS=()
declare -gA _ACCEPT_DEST=()
while IFS='|' read -r type rest; do
[[ -z "$type" ]] && continue
case "$type" in
peer)
local a_name a_bi a_bo a_pi a_po a_conns
IFS='|' read -r a_name a_bi a_bo a_pi a_po a_conns <<< "$rest"
_ACCEPT_PEER["$a_name"]="${a_bi}|${a_bo}|${a_pi}|${a_po}|${a_conns}"
;;
dest)
local d_peer d_ip d_port d_proto d_bytes d_count
IFS='|' read -r d_peer d_ip d_port d_proto d_bytes d_count <<< "$rest"
local d_key="${d_peer}:${d_ip}:${d_port}:${d_proto}"
_ACCEPT_DEST["$d_key"]="${d_bytes}|${d_count}"
_ACCEPT_DEST_KEYS["$d_peer"]+="${d_key} "
;;
esac
done <<< "$accept_data"
# Measure column widths
local w_peer=16 w_drops=1
while IFS='|' read -r type rest; do
case "$type" in
peer)
local name drops
name=$(echo "$rest" | cut -d'|' -f1)
drops=$(echo "$rest" | cut -d'|' -f4)
(( ${#name} > w_peer )) && w_peer=${#name}
(( ${#drops} > w_drops )) && w_drops=${#drops}
;;
service)
local count
count=$(echo "$rest" | cut -d'|' -f3)
(( ${#count} > w_drops )) && w_drops=${#count}
;;
esac
done <<< "$data"
for a_name in "${!_ACCEPT_PEER[@]}"; do
(( ${#a_name} > w_peer )) && w_peer=${#a_name}
done
(( w_peer += 2 ))
local drops_col=$(( w_peer + 30 ))
local hours_display="${hours}h"
[[ "$hours" == "0" ]] && hours_display="all time"
log::section "Activity Monitor (last ${hours_display})"
echo ""
if display::is_table "activity"; then
cmd::activity::_render_table "$data"
return 0
fi
# Helper — render accept dests for a peer inline
_render_peer_accept_dests() {
local peer_name="$1"
local keys="${_ACCEPT_DEST_KEYS[$peer_name]:-}"
[[ -z "$keys" ]] && return 0
for d_key in $keys; do
local dest_stats="${_ACCEPT_DEST[$d_key]:-}"
[[ -z "$dest_stats" ]] && continue
local d_bytes d_count
IFS='|' read -r d_bytes d_count <<< "$dest_stats"
local rest_key="${d_key#${peer_name}:}"
local d_ip d_port d_proto
d_ip="${rest_key%%:*}"
local pp="${rest_key#*:}"
d_port="${pp%%:*}"
d_proto="${pp##*:}"
local dest_display
dest_display=$(resolve::dest "$d_ip" "$d_port" "$d_proto" 2>/dev/null \
|| echo "${d_ip}:${d_port}/${d_proto}")
local bytes_fmt
bytes_fmt=$(fmt::bytes "$d_bytes")
ui::activity::accept_dest_row \
"$dest_display" "$d_bytes" "$bytes_fmt" \
"$d_count" "$drops_col" "$w_drops"
done
}
local first_peer=true skip_peer=false current_name=""
local -a rendered_peers=()
while IFS='|' read -r record_type rest; do
case "$record_type" in
peer)
local name rx tx drops
IFS='|' read -r name rx tx drops <<< "$rest"
# Flush previous peer's accept dests before starting new peer
if [[ -n "$current_name" ]] && ! $drop_only; then
_render_peer_accept_dests "$current_name"
fi
skip_peer=false
current_name="$name"
local has_accept="${_ACCEPT_PEER[$name]:-}"
if $dropped_only && [[ "$drops" -eq 0 ]] && [[ -z "$has_accept" ]]; then
skip_peer=true
continue
fi
$first_peer || echo ""
first_peer=false
rendered_peers+=("$name")
local rx_fmt tx_fmt
rx_fmt=$(fmt::bytes "$rx")
tx_fmt=$(fmt::bytes "$tx")
local name_pad rx_pad tx_pad
name_pad=$(printf "%-${w_peer}s" "$name")
rx_pad=$(printf "%-10s" "$rx_fmt")
tx_pad=$(printf "%-10s" "$tx_fmt")
local drop_word="drops"
[[ "$drops" -eq 1 ]] && drop_word="drop"
if ! $accept_only; then
ui::activity::peer_row \
"$name_pad" "$rx_pad" "$tx_pad" "$drops" "$drop_word" "$w_drops"
fi
# Accept summary row
if [[ -n "$has_accept" ]] && ! $drop_only; then
local a_bi a_bo a_pi a_po a_conns
IFS='|' read -r a_bi a_bo a_pi a_po a_conns <<< "$has_accept"
local a_in_fmt a_out_fmt
a_in_fmt=$(fmt::bytes "$a_bi")
a_out_fmt=$(fmt::bytes "$a_bo")
ui::activity::accept_row \
"$name_pad" "$a_in_fmt" "$a_out_fmt" "$a_conns" "$w_drops"
fi
;;
service)
$skip_peer && continue
local peer dest_display drop_count
IFS='|' read -r peer dest_display drop_count <<< "$rest"
local svc_drop_word="drops"
[[ "$drop_count" -eq 1 ]] && svc_drop_word="drop"
if ! $accept_only; then
ui::activity::service_row \
"$dest_display" "$drop_count" "$svc_drop_word" "$drops_col" "$w_drops"
fi
;;
esac
done <<< "$data"
# Flush last peer's accept dests
if [[ -n "$current_name" ]] && ! $drop_only; then
_render_peer_accept_dests "$current_name"
fi
# Accept-only peers — not in drop data, render separately
if ! $drop_only; then
for a_name in $(echo "${!_ACCEPT_PEER[@]}" | tr ' ' '\n' | sort); do
local already=false
for rp in "${rendered_peers[@]:-}"; do
[[ "$rp" == "$a_name" ]] && already=true && break
done
$already && continue
$first_peer || echo ""
first_peer=false
local a_stats="${_ACCEPT_PEER[$a_name]}"
local a_bi a_bo a_pi a_po a_conns
IFS='|' read -r a_bi a_bo a_pi a_po a_conns <<< "$a_stats"
local a_in_fmt a_out_fmt
a_in_fmt=$(fmt::bytes "$a_bi")
a_out_fmt=$(fmt::bytes "$a_bo")
local name_pad
name_pad=$(printf "%-${w_peer}s" "$a_name")
local a_in_pad a_out_pad
a_in_pad=$(printf "%-10s" "$a_in_fmt")
a_out_pad=$(printf "%-10s" "$a_out_fmt")
ui::activity::accept_row \
"$name_pad" "$a_in_pad" "$a_out_pad" "$a_conns" "$w_drops"
done
fi
echo ""
}
| 1 | function cmd::activity::run() { |
| 2 | local filter_peer="" filter_service="" filter_ip="" filter_type="" |
| 3 | local hours=24 dropped_only=false |
| 4 | local accept_only=false drop_only=false external_only=false |
| 5 | |
| 6 | while [[ $# -gt 0 ]]; do |
| 7 | case "$1" in |
| 8 | --peer) filter_peer="$2"; shift 2 ;; |
| 9 | --service) filter_service="$2"; shift 2 ;; |
| 10 | --ip) filter_ip="$2"; shift 2 ;; |
| 11 | --type) filter_type="$2"; shift 2 ;; |
| 12 | --hours) hours="$2"; shift 2 ;; |
| 13 | --dropped) dropped_only=true; shift ;; |
| 14 | --accept) accept_only=true; shift ;; |
| 15 | --drop) drop_only=true; shift ;; |
| 16 | --external) external_only=true; shift ;; |
| 17 | --help) cmd::activity::help; return ;; |
| 18 | *) |
| 19 | log::error "Unknown flag: $1" |
| 20 | cmd::activity::help |
| 21 | return 1 |
| 22 | ;; |
| 23 | esac |
| 24 | done |
| 25 | |
| 26 | if command::json; then |
| 27 | cmd::activity::_output_json "$hours" |
| 28 | return 0 |
| 29 | fi |
| 30 | |
| 31 | # Resolve peer name if type provided |
| 32 | if [[ -n "$filter_peer" && -n "$filter_type" ]]; then |
| 33 | filter_peer=$(peers::resolve_and_require "$filter_peer" "$filter_type") || return 1 |
| 34 | fi |
| 35 | |
| 36 | # Resolve --service to IP |
| 37 | local service_ip="" |
| 38 | if [[ -n "$filter_service" ]]; then |
| 39 | service_ip=$(net::resolve "$filter_service" 2>/dev/null | head -1 | cut -d: -f1) || true |
| 40 | if [[ -z "$service_ip" ]]; then |
| 41 | log::error "Service not found: ${filter_service}" |
| 42 | return 1 |
| 43 | fi |
| 44 | fi |
| 45 | [[ -n "$filter_ip" ]] && service_ip="$filter_ip" |
| 46 | |
| 47 | # Fetch drop/handshake data |
| 48 | local data="" |
| 49 | if ! $accept_only; then |
| 50 | data=$(json::activity_aggregate \ |
| 51 | "$(ctx::fw_events_log)" \ |
| 52 | "$(ctx::events_log)" \ |
| 53 | "$(config::interface)" \ |
| 54 | "$(ctx::net)" \ |
| 55 | "$(ctx::clients)" \ |
| 56 | "$(ctx::meta)" \ |
| 57 | "$hours" \ |
| 58 | "$filter_peer" \ |
| 59 | "$service_ip" 2>/dev/null) |
| 60 | fi |
| 61 | |
| 62 | # Fetch accept data |
| 63 | local accept_data="" |
| 64 | if ! $drop_only; then |
| 65 | local since_arg="" |
| 66 | [[ "$hours" -gt 0 ]] && since_arg="${hours}h" |
| 67 | local ext_flag="0" |
| 68 | $external_only && ext_flag="1" |
| 69 | [[ -f "$(ctx::accept_events_log)" ]] && \ |
| 70 | accept_data=$(json::accept_aggregate \ |
| 71 | "$(ctx::accept_events_log)" \ |
| 72 | "$(ctx::net)" \ |
| 73 | "$(ctx::clients)" \ |
| 74 | "$since_arg" \ |
| 75 | "$filter_peer" \ |
| 76 | "$ext_flag" \ |
| 77 | 2>/dev/null) |
| 78 | fi |
| 79 | |
| 80 | if [[ -z "$data" && -z "$accept_data" ]]; then |
| 81 | log::wg_warning "No activity data found" |
| 82 | return 0 |
| 83 | fi |
| 84 | |
| 85 | # Build accept lookup maps |
| 86 | declare -gA _ACCEPT_PEER=() |
| 87 | declare -gA _ACCEPT_DEST_KEYS=() |
| 88 | declare -gA _ACCEPT_DEST=() |
| 89 | |
| 90 | while IFS='|' read -r type rest; do |
| 91 | [[ -z "$type" ]] && continue |
| 92 | case "$type" in |
| 93 | peer) |
| 94 | local a_name a_bi a_bo a_pi a_po a_conns |
| 95 | IFS='|' read -r a_name a_bi a_bo a_pi a_po a_conns <<< "$rest" |
| 96 | _ACCEPT_PEER["$a_name"]="${a_bi}|${a_bo}|${a_pi}|${a_po}|${a_conns}" |
| 97 | ;; |
| 98 | dest) |
| 99 | local d_peer d_ip d_port d_proto d_bytes d_count |
| 100 | IFS='|' read -r d_peer d_ip d_port d_proto d_bytes d_count <<< "$rest" |
| 101 | local d_key="${d_peer}:${d_ip}:${d_port}:${d_proto}" |
| 102 | _ACCEPT_DEST["$d_key"]="${d_bytes}|${d_count}" |
| 103 | _ACCEPT_DEST_KEYS["$d_peer"]+="${d_key} " |
| 104 | ;; |
| 105 | esac |
| 106 | done <<< "$accept_data" |
| 107 | |
| 108 | # Measure column widths |
| 109 | local w_peer=16 w_drops=1 |
| 110 | while IFS='|' read -r type rest; do |
| 111 | case "$type" in |
| 112 | peer) |
| 113 | local name drops |
| 114 | name=$(echo "$rest" | cut -d'|' -f1) |
| 115 | drops=$(echo "$rest" | cut -d'|' -f4) |
| 116 | (( ${#name} > w_peer )) && w_peer=${#name} |
| 117 | (( ${#drops} > w_drops )) && w_drops=${#drops} |
| 118 | ;; |
| 119 | service) |
| 120 | local count |
| 121 | count=$(echo "$rest" | cut -d'|' -f3) |
| 122 | (( ${#count} > w_drops )) && w_drops=${#count} |
| 123 | ;; |
| 124 | esac |
| 125 | done <<< "$data" |
| 126 | |
| 127 | for a_name in "${!_ACCEPT_PEER[@]}"; do |
| 128 | (( ${#a_name} > w_peer )) && w_peer=${#a_name} |
| 129 | done |
| 130 | |
| 131 | (( w_peer += 2 )) |
| 132 | local drops_col=$(( w_peer + 30 )) |
| 133 | |
| 134 | local hours_display="${hours}h" |
| 135 | [[ "$hours" == "0" ]] && hours_display="all time" |
| 136 | |
| 137 | log::section "Activity Monitor (last ${hours_display})" |
| 138 | echo "" |
| 139 | |
| 140 | if display::is_table "activity"; then |
| 141 | cmd::activity::_render_table "$data" |
| 142 | return 0 |
| 143 | fi |
| 144 | |
| 145 | # Helper — render accept dests for a peer inline |
| 146 | _render_peer_accept_dests() { |
| 147 | local peer_name="$1" |
| 148 | local keys="${_ACCEPT_DEST_KEYS[$peer_name]:-}" |
| 149 | [[ -z "$keys" ]] && return 0 |
| 150 | for d_key in $keys; do |
| 151 | local dest_stats="${_ACCEPT_DEST[$d_key]:-}" |
| 152 | [[ -z "$dest_stats" ]] && continue |
| 153 | local d_bytes d_count |
| 154 | IFS='|' read -r d_bytes d_count <<< "$dest_stats" |
| 155 | local rest_key="${d_key#${peer_name}:}" |
| 156 | local d_ip d_port d_proto |
| 157 | d_ip="${rest_key%%:*}" |
| 158 | local pp="${rest_key#*:}" |
| 159 | d_port="${pp%%:*}" |
| 160 | d_proto="${pp##*:}" |
| 161 | local dest_display |
| 162 | dest_display=$(resolve::dest "$d_ip" "$d_port" "$d_proto" 2>/dev/null \ |
| 163 | || echo "${d_ip}:${d_port}/${d_proto}") |
| 164 | local bytes_fmt |
| 165 | bytes_fmt=$(fmt::bytes "$d_bytes") |
| 166 | ui::activity::accept_dest_row \ |
| 167 | "$dest_display" "$d_bytes" "$bytes_fmt" \ |
| 168 | "$d_count" "$drops_col" "$w_drops" |
| 169 | done |
| 170 | } |
| 171 | |
| 172 | local first_peer=true skip_peer=false current_name="" |
| 173 | local -a rendered_peers=() |
| 174 | |
| 175 | while IFS='|' read -r record_type rest; do |
| 176 | case "$record_type" in |
| 177 | peer) |
| 178 | local name rx tx drops |
| 179 | IFS='|' read -r name rx tx drops <<< "$rest" |
| 180 | |
| 181 | # Flush previous peer's accept dests before starting new peer |
| 182 | if [[ -n "$current_name" ]] && ! $drop_only; then |
| 183 | _render_peer_accept_dests "$current_name" |
| 184 | fi |
| 185 | |
| 186 | skip_peer=false |
| 187 | current_name="$name" |
| 188 | local has_accept="${_ACCEPT_PEER[$name]:-}" |
| 189 | |
| 190 | if $dropped_only && [[ "$drops" -eq 0 ]] && [[ -z "$has_accept" ]]; then |
| 191 | skip_peer=true |
| 192 | continue |
| 193 | fi |
| 194 | |
| 195 | $first_peer || echo "" |
| 196 | first_peer=false |
| 197 | rendered_peers+=("$name") |
| 198 | |
| 199 | local rx_fmt tx_fmt |
| 200 | rx_fmt=$(fmt::bytes "$rx") |
| 201 | tx_fmt=$(fmt::bytes "$tx") |
| 202 | |
| 203 | local name_pad rx_pad tx_pad |
| 204 | name_pad=$(printf "%-${w_peer}s" "$name") |
| 205 | rx_pad=$(printf "%-10s" "$rx_fmt") |
| 206 | tx_pad=$(printf "%-10s" "$tx_fmt") |
| 207 | |
| 208 | local drop_word="drops" |
| 209 | [[ "$drops" -eq 1 ]] && drop_word="drop" |
| 210 | |
| 211 | if ! $accept_only; then |
| 212 | ui::activity::peer_row \ |
| 213 | "$name_pad" "$rx_pad" "$tx_pad" "$drops" "$drop_word" "$w_drops" |
| 214 | fi |
| 215 | |
| 216 | # Accept summary row |
| 217 | if [[ -n "$has_accept" ]] && ! $drop_only; then |
| 218 | local a_bi a_bo a_pi a_po a_conns |
| 219 | IFS='|' read -r a_bi a_bo a_pi a_po a_conns <<< "$has_accept" |
| 220 | local a_in_fmt a_out_fmt |
| 221 | a_in_fmt=$(fmt::bytes "$a_bi") |
| 222 | a_out_fmt=$(fmt::bytes "$a_bo") |
| 223 | ui::activity::accept_row \ |
| 224 | "$name_pad" "$a_in_fmt" "$a_out_fmt" "$a_conns" "$w_drops" |
| 225 | fi |
| 226 | ;; |
| 227 | |
| 228 | service) |
| 229 | $skip_peer && continue |
| 230 | local peer dest_display drop_count |
| 231 | IFS='|' read -r peer dest_display drop_count <<< "$rest" |
| 232 | local svc_drop_word="drops" |
| 233 | [[ "$drop_count" -eq 1 ]] && svc_drop_word="drop" |
| 234 | if ! $accept_only; then |
| 235 | ui::activity::service_row \ |
| 236 | "$dest_display" "$drop_count" "$svc_drop_word" "$drops_col" "$w_drops" |
| 237 | fi |
| 238 | ;; |
| 239 | esac |
| 240 | done <<< "$data" |
| 241 | |
| 242 | # Flush last peer's accept dests |
| 243 | if [[ -n "$current_name" ]] && ! $drop_only; then |
| 244 | _render_peer_accept_dests "$current_name" |
| 245 | fi |
| 246 | |
| 247 | # Accept-only peers — not in drop data, render separately |
| 248 | if ! $drop_only; then |
| 249 | for a_name in $(echo "${!_ACCEPT_PEER[@]}" | tr ' ' '\n' | sort); do |
| 250 | local already=false |
| 251 | for rp in "${rendered_peers[@]:-}"; do |
| 252 | [[ "$rp" == "$a_name" ]] && already=true && break |
| 253 | done |
| 254 | $already && continue |
| 255 | |
| 256 | $first_peer || echo "" |
| 257 | first_peer=false |
| 258 | |
| 259 | local a_stats="${_ACCEPT_PEER[$a_name]}" |
| 260 | local a_bi a_bo a_pi a_po a_conns |
| 261 | IFS='|' read -r a_bi a_bo a_pi a_po a_conns <<< "$a_stats" |
| 262 | local a_in_fmt a_out_fmt |
| 263 | a_in_fmt=$(fmt::bytes "$a_bi") |
| 264 | a_out_fmt=$(fmt::bytes "$a_bo") |
| 265 | local name_pad |
| 266 | name_pad=$(printf "%-${w_peer}s" "$a_name") |
| 267 | local a_in_pad a_out_pad |
| 268 | a_in_pad=$(printf "%-10s" "$a_in_fmt") |
| 269 | a_out_pad=$(printf "%-10s" "$a_out_fmt") |
| 270 | ui::activity::accept_row \ |
| 271 | "$name_pad" "$a_in_pad" "$a_out_pad" "$a_conns" "$w_drops" |
| 272 | done |
| 273 | fi |
| 274 | |
| 275 | echo "" |
| 276 | } |