def config_load(file): """ Load wgctl.json and output KEY=value pairs for all config fields. Automatically handles nested sections — add fields to JSON, they appear here. """ import os if not os.path.exists(file): return try: with open(file) as f: d = json.load(f) def emit(key, val): if val is not None and val != '': print(f"{key}={val}") wg = d.get('wireguard', {}) dns = d.get('dns', {}) hs = d.get('handshake', {}) act = d.get('activity', {}) dis = d.get('display', {}) emit('WG_INTERFACE', wg.get('interface')) emit('WG_ENDPOINT', wg.get('endpoint')) emit('WG_PORT', wg.get('port')) emit('WG_SUBNET', wg.get('subnet')) emit('WG_LAN', wg.get('lan')) emit('WG_DNS', dns.get('primary')) # fallback: join array to comma-separated string fb = dns.get('fallback', []) if fb: emit('WG_DNS_FALLBACK', ', '.join(str(x) for x in fb)) emit('WG_HANDSHAKE_CHECK_TIME_SEC', hs.get('check_interval_sec')) emit('DATE_FORMAT', dis.get('date_format')) atot = act.get('total', {}) acur = act.get('current', {}) emit('ACTIVITY_TOTAL_LOW_BYTES', atot.get('low')) emit('ACTIVITY_TOTAL_MED_BYTES', atot.get('medium')) emit('ACTIVITY_TOTAL_HIGH_BYTES', atot.get('high')) emit('ACTIVITY_CURRENT_LOW_BYTES', acur.get('low')) emit('ACTIVITY_CURRENT_MED_BYTES', acur.get('medium')) emit('ACTIVITY_CURRENT_HIGH_BYTES', acur.get('high')) except Exception as e: print(f"Error: {e}", file=sys.stderr) sys.exit(1)