function cmd::activity::on_load() { load_module net flag::register --peer flag::register --service flag::register --ip flag::register --hours flag::register --type flag::register --dropped } # ============================================ # Help # ============================================ function cmd::activity::help() { function cmd::activity::run() { local filter_peer="" filter_service="" filter_ip="" filter_type="" local hours=24 dropped_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 ;; --help) cmd::activity::help; return ;; *) log::error "Unknown flag: $1" cmd::activity::help return 1 ;; esac done # 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 aggregated data local data 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) if [[ -z "$data" ]]; then log::wg_warning "No activity data found" return 0 fi # Measure w_peer and w_drops from data 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} function cmd::group::show() { local name="" while [[ $# -gt 0 ]]; do case "$1" in --name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;; --help) cmd::group::help; return ;; *) log::error "Unknown flag: $1"; return 1 ;; esac done [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1 group::require_exists "$name" || return 1 local group_file group_file="$(group::path "$name")" log::section "Group: ${name}" printf "\n" local desc desc=$(json::get "$group_file" "desc") ui::row "Description" "${desc:-—}" local peers_list=() mapfile -t peers_list < <(json::get "$group_file" "peers") || true local filtered=() for p in "${peers_list[@]:-}"; do [[ -n "$p" ]] && filtered+=("$p") done peers_list=("${filtered[@]:-}") local peer_count=${#peers_list[@]} [[ -z "${peers_list[0]:-}" ]] && peer_count=0 local peer_word="peers" [[ "$peer_count" -eq 1 ]] && peer_word="peer" local valid_count=0 for p in "${peers_list[@]}"; do [[ -z "$p" ]] && continue peers::require_exists "$p" > /dev/null 2>&1 && (( valid_count++ )) || true done local peer_word="peers" [[ "$valid_count" -eq 1 ]] && peer_word="peer" ui::row "Peers" "${valid_count} ${peer_word}" printf "\n" if [[ "$peer_count" -gt 0 ]]; then # Measure name and IP widths local w_name=16 w_ip=13 for peer_name in "${peers_list[@]}"; do [[ -z "$peer_name" ]] && continue (( ${#peer_name} > w_name )) && w_name=${#peer_name} done (( w_name += 2 )) for peer_name in "${peers_list[@]}"; do [[ -z "$peer_name" ]] && continue if ! peers::require_exists "$peer_name" > /dev/null 2>&1; then printf " \033[2m%-${w_name}s (no longer exists)\033[0m\n" "$peer_name" continue fi local ip rule is_blocked ip=$(peers::get_ip "$peer_name") rule=$(peers::get_meta "$peer_name" "rule") peers::is_blocked "$peer_name" 2>/dev/null && is_blocked="true" || is_blocked="false" ui::group::show_member_row "$peer_name" "$ip" "${rule:--}" \ "$is_blocked" "$w_name" "$w_ip" done else printf " \033[2m—\033[0m\n" fi printf "\n" }