dotfiles/.config/eww/scripts/network2.py
2025-06-27 16:56:03 -06:00

73 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Asynchronous network monitoring script, reports current state every 5 seconds."""
from ipaddress import (
IPv4Address as IPAddress,
IPv4Network as IPNetwork,
IPv4Interface as IPInterface,
AddressValueError,
)
from dbus_fast.aio import MessageBus
from dbus_fast import Variant, BusType
import re
import asyncio
from subprocess import PIPE
import functools
MONITOR_IPS = {"ezrinet": IPAddress("10.242.3.1"), "internet": IPAddress("1.1.1.1")}
INTERFACE_IGNORE_PATTERNS = [
re.compile(r"^vb-"),
re.compile(r"^vz-"),
re.compile(r"^virbr[0-9]+"),
re.compile(r"^lo$"),
]
def timer(interval: float, initial_delay: float = 0):
"""Decorate a function or coroutine to run it on the given interval."""
def decorator(func):
async def do_interval():
try:
await asyncio.sleep(initial_delay)
while True:
await func()
await asyncio.sleep(interval)
except asyncio.CancelledError:
return
def start():
loop = asyncio.get_running_loop()
if "_timer_task" in func.__dict__:
raise Exception("Timer is already running.")
func.__dict__["_timer_task"] = loop.create_task(do_interval())
func.__dict__["start"] = start
return func
return decorator
async def ping(address: IPAddress) -> tuple[bool, float | None]:
"""Ping a host and return a tuple of [success, ping time]."""
proc = await asyncio.create_subprocess_exec(
"ping", "-c1", "-w1", "-n", str(address), stdout=PIPE
)
stdout, stderr = await proc.communicate()
_match = re.search(
r"icmp_seq=1 ttl=[0-9]+ time=([0-9]+\.?[0-9]*) ms", stdout.decode("utf-8")
)
if _match is None:
return (False, None)
else:
return (True, float(_match.group(1)))
@timer(5)
async def ping_checks():
"""Recurring ping checks for configured IP addresses."""