Последняя активность 1 month ago

nuno ревизий этого фрагмента 1 month ago. К ревизии

1 file changed, 278 insertions

gistfile1.txt(файл создан)

@@ -0,0 +1,278 @@
1 + #!/usr/bin/env bash
2 + # activity.command.sh — WireGuard activity snapshot
3 +
4 + # ============================================
5 + # Lifecycle
6 + # ============================================
7 +
8 + function cmd::activity::on_load() {
9 + load_module net
10 +
11 + flag::register --peer
12 + flag::register --service
13 + flag::register --ip
14 + flag::register --hours
15 + flag::register --type
16 + flag::register --dropped
17 +
18 + command::mixin json_output
19 + }
20 +
21 + # ============================================
22 + # Help
23 + # ============================================
24 +
25 + function cmd::activity::help() {
26 + cat <<EOF
27 + Usage: wgctl activity [options]
28 +
29 + Show WireGuard activity — transfer totals and firewall drops per peer.
30 + Data sources: wg show transfer, fw_events.log
31 +
32 + Options:
33 + --peer <name> Filter by peer name
34 + --service <name> Filter by service (e.g. truenas, proxmox:web-ui)
35 + --ip <ip> Filter by destination IP
36 + --hours <n> Time window in hours (default: 24, 0 = all time)
37 + --type <type> Filter by device type (combined with --peer)
38 + --dropped Show only peers with at least one drop
39 +
40 + Examples:
41 + wgctl activity
42 + wgctl activity --dropped
43 + wgctl activity --peer phone-nuno
44 + wgctl activity --service truenas
45 + wgctl activity --hours 0
46 + wgctl activity --ip 10.0.0.101
47 + EOF
48 + }
49 +
50 + # ============================================
51 + # Run
52 + # ============================================
53 +
54 + function cmd::activity::run() {
55 + local filter_peer="" filter_service="" filter_ip="" filter_type=""
56 + local hours=24 dropped_only=false
57 +
58 + while [[ $# -gt 0 ]]; do
59 + case "$1" in
60 + --peer) filter_peer="$2"; shift 2 ;;
61 + --service) filter_service="$2"; shift 2 ;;
62 + --ip) filter_ip="$2"; shift 2 ;;
63 + --type) filter_type="$2"; shift 2 ;;
64 + --hours) hours="$2"; shift 2 ;;
65 + --dropped) dropped_only=true; shift ;;
66 + --help) cmd::activity::help; return ;;
67 + *)
68 + log::error "Unknown flag: $1"
69 + cmd::activity::help
70 + return 1
71 + ;;
72 + esac
73 + done
74 +
75 + if command::json; then
76 + cmd::activity::_output_json "$hours"
77 + return 0
78 + fi
79 +
80 + # Resolve peer name if type provided
81 + if [[ -n "$filter_peer" && -n "$filter_type" ]]; then
82 + filter_peer=$(peers::resolve_and_require "$filter_peer" "$filter_type") || return 1
83 + fi
84 +
85 + # Resolve --service to IP
86 + local service_ip=""
87 + if [[ -n "$filter_service" ]]; then
88 + service_ip=$(net::resolve "$filter_service" 2>/dev/null | head -1 | cut -d: -f1) || true
89 + if [[ -z "$service_ip" ]]; then
90 + log::error "Service not found: ${filter_service}"
91 + return 1
92 + fi
93 + fi
94 + [[ -n "$filter_ip" ]] && service_ip="$filter_ip"
95 +
96 + # Fetch aggregated data
97 + local data
98 + data=$(json::activity_aggregate \
99 + "$(ctx::fw_events_log)" \
100 + "$(ctx::events_log)" \
101 + "$(config::interface)" \
102 + "$(ctx::net)" \
103 + "$(ctx::clients)" \
104 + "$(ctx::meta)" \
105 + "$hours" \
106 + "$filter_peer" \
107 + "$service_ip" 2>/dev/null)
108 +
109 + if [[ -z "$data" ]]; then
110 + log::wg_warning "No activity data found"
111 + return 0
112 + fi
113 +
114 + # Measure column widths
115 + local w_peer=16 w_drops=1
116 + while IFS='|' read -r type rest; do
117 + case "$type" in
118 + peer)
119 + local name drops
120 + name=$(echo "$rest" | cut -d'|' -f1)
121 + drops=$(echo "$rest" | cut -d'|' -f4)
122 + (( ${#name} > w_peer )) && w_peer=${#name}
123 + (( ${#drops} > w_drops )) && w_drops=${#drops}
124 + ;;
125 + service)
126 + local count
127 + count=$(echo "$rest" | cut -d'|' -f3)
128 + (( ${#count} > w_drops )) && w_drops=${#count}
129 + ;;
130 + esac
131 + done <<< "$data"
132 +
133 + (( w_peer += 2 ))
134 +
135 + # Compute column where drop count starts on peer row:
136 + # " " (2) + name (w_peer) + " ↓" (3) + rx (10) + " ↑" (3) + tx (10) + " " (2)
137 + # ↓ and ↑ are multi-byte (3 bytes, 1 visible) — 2 extra bytes each
138 + # Visible: 2 + w_peer + 2+1 + 10 + 2+1 + 10 + 2 = w_peer + 30
139 + local drops_col=$(( w_peer + 30 ))
140 +
141 + local hours_display="${hours}h"
142 + [[ "$hours" == "0" ]] && hours_display="all time"
143 +
144 + log::section "Activity Monitor (last ${hours_display})"
145 + echo ""
146 +
147 + if display::is_table "activity"; then
148 + cmd::activity::_render_table "$data"
149 + return 0
150 + fi
151 +
152 + local first_peer=true skip_peer=false
153 +
154 + while IFS='|' read -r record_type rest; do
155 + case "$record_type" in
156 + peer)
157 + local name rx tx drops
158 + IFS='|' read -r name rx tx drops <<< "$rest"
159 +
160 + skip_peer=false
161 + if $dropped_only && [[ "$drops" -eq 0 ]]; then
162 + skip_peer=true
163 + continue
164 + fi
165 +
166 + $first_peer || echo ""
167 + first_peer=false
168 +
169 + local rx_fmt tx_fmt
170 + rx_fmt=$(fmt::bytes "$rx")
171 + tx_fmt=$(fmt::bytes "$tx")
172 +
173 + local name_pad rx_pad tx_pad
174 + name_pad=$(printf "%-${w_peer}s" "$name")
175 + rx_pad=$(printf "%-10s" "$rx_fmt")
176 + tx_pad=$(printf "%-10s" "$tx_fmt")
177 +
178 + local drop_word="drops"
179 + [[ "$drops" -eq 1 ]] && drop_word="drop"
180 +
181 + ui::activity::peer_row \
182 + "$name_pad" "$rx_pad" "$tx_pad" "$drops" "$drop_word" "$w_drops"
183 + ;;
184 +
185 + service)
186 + $skip_peer && continue
187 +
188 + local peer dest_display drop_count
189 + IFS='|' read -r peer dest_display drop_count <<< "$rest"
190 +
191 + local svc_drop_word="drops"
192 + [[ "$drop_count" -eq 1 ]] && svc_drop_word="drop"
193 +
194 + ui::activity::service_row \
195 + "$dest_display" "$drop_count" "$svc_drop_word" "$drops_col" "$w_drops"
196 + ;;
197 + esac
198 + done <<< "$data"
199 +
200 + echo ""
201 + }
202 +
203 + function cmd::activity::_render_table() {
204 + local data="${1:-}"
205 + [[ -z "$data" ]] && return 0
206 +
207 + ui::activity::header_table
208 + local skip_peer=false
209 + while IFS='|' read -r record_type rest; do
210 + case "$record_type" in
211 + peer)
212 + local name rx tx drops
213 + IFS='|' read -r name rx tx drops <<< "$rest"
214 + skip_peer=false
215 + local rx_fmt tx_fmt
216 + rx_fmt=$(fmt::bytes "$rx")
217 + tx_fmt=$(fmt::bytes "$tx")
218 + ui::activity::peer_row_table "$name" "$rx_fmt" "$tx_fmt" "$drops" ""
219 + ;;
220 + service)
221 + $skip_peer && continue
222 + local peer dest count
223 + IFS='|' read -r peer dest count <<< "$rest"
224 + ui::activity::service_row_table "$dest" "$count" "drops"
225 + ;;
226 + esac
227 + done <<< "$data"
228 + }
229 +
230 +
231 + function cmd::activity::_output_json() {
232 + local hours="${1:-24}"
233 + local data
234 + data=$(json::activity_aggregate \
235 + "$(ctx::fw_events_log)" "$(ctx::events_log)" \
236 + "$(config::interface)" "$(ctx::net)" \
237 + "$(ctx::clients)" "$(ctx::meta)" \
238 + "$hours" "" "" 2>/dev/null)
239 +
240 + local -a peers=()
241 + local current_peer="" current_services=""
242 + local -a current_svc_list=()
243 +
244 + while IFS='|' read -r record_type rest; do
245 + case "$record_type" in
246 + peer)
247 + # Flush previous peer
248 + if [[ -n "$current_peer" ]]; then
249 + local svc_array
250 + svc_array=$(printf '%s\n' "${current_svc_list[@]:-}" | paste -sd ',' -)
251 + peers+=("${current_peer},\"services\":[${svc_array:-}]}")
252 + current_svc_list=()
253 + fi
254 + local name rx tx drops
255 + IFS='|' read -r name rx tx drops <<< "$rest"
256 + current_peer=$(printf '{"name":"%s","rx":%s,"tx":%s,"drops":%s' \
257 + "$name" "$rx" "$tx" "$drops")
258 + ;;
259 + service)
260 + local peer dest count
261 + IFS='|' read -r peer dest count <<< "$rest"
262 + current_svc_list+=("$(printf '{"dest":"%s","drops":%s}' "$dest" "$count")")
263 + ;;
264 + esac
265 + done <<< "$data"
266 +
267 + # Flush last peer
268 + if [[ -n "$current_peer" ]]; then
269 + local svc_array
270 + svc_array=$(printf '%s\n' "${current_svc_list[@]:-}" | paste -sd ',' -)
271 + peers+=("${current_peer},\"services\":[${svc_array:-}]}")
272 + fi
273 +
274 + local count=${#peers[@]}
275 + local array
276 + array=$(printf '%s\n' "${peers[@]:-}" | paste -sd ',' -)
277 + printf '{"peers":[%s]}' "${array:-}" | json::envelope "activity" "$count"
278 + }
Новее Позже