""" peers.py — peer data, transfer stats, group lookups. """ import os import json import sys import glob from lib.util import DATETIME_FMT, build_ip_to_name, build_pubkey_to_name, fmt_ts def peer_data(clients_dir, meta_dir, events_log): """ Output: name|ip|rule|type|last_ts|last_evt|main_group """ meta = {} for f in glob.glob(f"{meta_dir}/*.meta"): name = os.path.basename(f).replace('.meta', '') try: with open(f) as mf: meta[name] = json.load(mf) except Exception: meta[name] = {} last_events = {} try: with open(events_log) as f: for line in f: try: e = json.loads(line.strip()) client = e.get('client', '') if client: last_events[client] = e except Exception: pass except Exception: pass for conf in sorted(glob.glob(f"{clients_dir}/*.conf")): name = os.path.basename(conf).replace('.conf', '') ip = '' try: with open(conf) as f: for line in f: if line.startswith('Address'): ip = line.split('=')[1].strip().split('/')[0] break except Exception: pass m = meta.get(name, {}) rule = m.get('rule', '') peer_type = m.get('type', '') main_group = m.get('main_group', '') last_event = last_events.get(name, {}) last_ts = last_event.get('timestamp', '') last_evt = last_event.get('event', '') print(f"{name}|{ip}|{rule}|{peer_type}|{last_ts}|{last_evt}|{main_group}") def peer_transfer(wg_interface): """Get total transfer bytes per peer.""" import subprocess low = int(os.environ.get('ACTIVITY_TOTAL_LOW_BYTES', '1000000')) med = int(os.environ.get('ACTIVITY_TOTAL_MED_BYTES', '10000000')) high = int(os.environ.get('ACTIVITY_TOTAL_HIGH_BYTES', '100000000')) try: result = subprocess.run( ['wg', 'show', wg_interface, 'transfer'], capture_output=True, text=True ) for line in result.stdout.strip().split('\n'): if not line: continue parts = line.split('\t') if len(parts) == 3: pubkey, rx, tx = parts total = int(rx) + int(tx) if total == 0: level = 'none' elif total < low: level = 'low' elif total < med: level = 'medium' elif total < high: level = 'high' else: level = 'very high' print(f"{pubkey}|{rx}|{tx}|{level}") except Exception: pass def peer_transfer_delta(wg_interface, cache_file): """Calculate current transfer rate using delta from previous sample.""" import subprocess import time low = int(os.environ.get('ACTIVITY_CURRENT_LOW_BYTES', '10000')) med = int(os.environ.get('ACTIVITY_CURRENT_MED_BYTES', '100000')) high = int(os.environ.get('ACTIVITY_CURRENT_HIGH_BYTES', '1000000')) current = {} now = time.time() try: result = subprocess.run( ['wg', 'show', wg_interface, 'transfer'], capture_output=True, text=True ) for line in result.stdout.strip().split('\n'): if not line: continue parts = line.split('\t') if len(parts) == 3: pubkey, rx, tx = parts current[pubkey] = {'rx': int(rx), 'tx': int(tx), 'ts': now} except Exception: pass prev = {} if os.path.exists(cache_file): try: with open(cache_file) as f: prev = json.load(f) except Exception: pass try: with open(cache_file, 'w') as f: json.dump(current, f) except Exception: pass for pubkey, data in current.items(): if pubkey in prev: dt = data['ts'] - prev[pubkey].get('ts', data['ts']) if dt > 0: rx_rate = max(0, (data['rx'] - prev[pubkey]['rx']) / dt) tx_rate = max(0, (data['tx'] - prev[pubkey]['tx']) / dt) total = rx_rate + tx_rate if total <= 0: level = 'idle' elif total < low: level = 'low' elif total < med: level = 'medium' elif total < high: level = 'high' else: level = 'very high' print(f"{pubkey}|{int(rx_rate)}|{int(tx_rate)}|{level}") else: print(f"{pubkey}|0|0|idle") else: print(f"{pubkey}|0|0|unknown") def peer_group_map(groups_dir): """Return peer:group pairs for all groups.""" try: for group_file in glob.glob(f"{groups_dir}/*.group"): try: with open(group_file) as f: g = json.load(f) name = g.get('name', '') for peer in g.get('peers', []): if peer: print(f"{peer}:{name}") except Exception: pass except Exception: pass def peer_groups(groups_dir, peer_name): """Find all groups containing a peer.""" try: for group_file in glob.glob(f"{groups_dir}/*.group"): try: with open(group_file) as f: g = json.load(f) if peer_name in g.get('peers', []): print(g.get('name', '')) except Exception: pass except Exception: pass