frobarng: NetworkProvider done
This commit is contained in:
parent
36df032ecd
commit
1ae7d6b447
|
@ -3,9 +3,11 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
import datetime
|
||||||
import enum
|
import enum
|
||||||
|
import ipaddress
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import coloredlogs
|
import coloredlogs
|
||||||
|
@ -22,6 +24,21 @@ C = typing.TypeVar("C", bound="ComposableText")
|
||||||
Sortable = str | int
|
Sortable = str | int
|
||||||
|
|
||||||
|
|
||||||
|
def humanSize(numi: int) -> str:
|
||||||
|
"""
|
||||||
|
Returns a string of width 3+3
|
||||||
|
"""
|
||||||
|
num = float(numi)
|
||||||
|
for unit in ("B ", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"):
|
||||||
|
if abs(num) < 1000:
|
||||||
|
if num >= 10:
|
||||||
|
return "{:3d}{}".format(int(num), unit)
|
||||||
|
else:
|
||||||
|
return "{:.1f}{}".format(num, unit)
|
||||||
|
num /= 1024
|
||||||
|
return "{:d}YiB".format(numi)
|
||||||
|
|
||||||
|
|
||||||
class ComposableText(typing.Generic[P, C]):
|
class ComposableText(typing.Generic[P, C]):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -267,6 +284,7 @@ class Bar(ComposableText):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.parent: None
|
self.parent: None
|
||||||
self.children: typing.MutableSequence[Screen]
|
self.children: typing.MutableSequence[Screen]
|
||||||
|
self.longRunningTasks: list[asyncio.Task] = list()
|
||||||
|
|
||||||
self.refresh = asyncio.Event()
|
self.refresh = asyncio.Event()
|
||||||
self.taskGroup = asyncio.TaskGroup()
|
self.taskGroup = asyncio.TaskGroup()
|
||||||
|
@ -280,6 +298,10 @@ class Bar(ComposableText):
|
||||||
continue
|
continue
|
||||||
Screen(parent=self, output=output.name)
|
Screen(parent=self, output=output.name)
|
||||||
|
|
||||||
|
def addLongRunningTask(self, coro: typing.Coroutine) -> None:
|
||||||
|
task = self.taskGroup.create_task(coro)
|
||||||
|
self.longRunningTasks.append(task)
|
||||||
|
|
||||||
async def run(self) -> None:
|
async def run(self) -> None:
|
||||||
cmd = [
|
cmd = [
|
||||||
"lemonbar",
|
"lemonbar",
|
||||||
|
@ -299,7 +321,6 @@ class Bar(ComposableText):
|
||||||
await self.refresh.wait()
|
await self.refresh.wait()
|
||||||
self.refresh.clear()
|
self.refresh.clear()
|
||||||
markup = self.getMarkup()
|
markup = self.getMarkup()
|
||||||
# log.debug(markup)
|
|
||||||
proc.stdin.write(markup.encode())
|
proc.stdin.write(markup.encode())
|
||||||
|
|
||||||
async def actionHandler() -> None:
|
async def actionHandler() -> None:
|
||||||
|
@ -310,21 +331,15 @@ class Bar(ComposableText):
|
||||||
callback = self.actions[command]
|
callback = self.actions[command]
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
longRunningTasks = list()
|
|
||||||
|
|
||||||
def addLongRunningTask(coro: typing.Coroutine) -> None:
|
|
||||||
task = self.taskGroup.create_task(coro)
|
|
||||||
longRunningTasks.append(task)
|
|
||||||
|
|
||||||
async with self.taskGroup:
|
async with self.taskGroup:
|
||||||
addLongRunningTask(refresher())
|
self.addLongRunningTask(refresher())
|
||||||
addLongRunningTask(actionHandler())
|
self.addLongRunningTask(actionHandler())
|
||||||
for provider in self.providers:
|
for provider in self.providers:
|
||||||
addLongRunningTask(provider.run())
|
self.addLongRunningTask(provider.run())
|
||||||
|
|
||||||
def exit() -> None:
|
def exit() -> None:
|
||||||
log.info("Terminating")
|
log.info("Terminating")
|
||||||
for task in longRunningTasks:
|
for task in self.longRunningTasks:
|
||||||
task.cancel()
|
task.cancel()
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
@ -563,11 +578,50 @@ class NetworkProviderSection(StatefulSection):
|
||||||
self.numberStates = 5 if self.wifi else 4
|
self.numberStates = 5 if self.wifi else 4
|
||||||
self.state = 1 if self.wifi else 0
|
self.state = 1 if self.wifi else 0
|
||||||
|
|
||||||
|
async def updateOnStateChange(self) -> None:
|
||||||
|
while True:
|
||||||
|
await self.stateChanged.wait()
|
||||||
|
await self.provider.updateIface(self.iface)
|
||||||
|
|
||||||
async def getText(self) -> str | None:
|
async def getText(self) -> str | None:
|
||||||
if self.ignore or not self.provider.if_stats[self.iface].isup:
|
if self.ignore or not self.provider.if_stats[self.iface].isup:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
text = self.icon
|
text = self.icon
|
||||||
|
|
||||||
|
state = self.state + (0 if self.wifi else 1) # SSID
|
||||||
|
if self.wifi and state >= 1:
|
||||||
|
cmd = ["iwgetid", self.iface, "--raw"]
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd, stdout=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, stderr = await proc.communicate()
|
||||||
|
text += f" {stdout.decode().strip()}"
|
||||||
|
|
||||||
|
if state >= 2: # Address
|
||||||
|
for address in self.provider.if_addrs[self.iface]:
|
||||||
|
if address.family == socket.AF_INET:
|
||||||
|
net = ipaddress.IPv4Network(
|
||||||
|
(address.address, address.netmask), strict=False
|
||||||
|
)
|
||||||
|
text += f" {net.with_prefixlen}"
|
||||||
|
break
|
||||||
|
|
||||||
|
if state >= 3: # Speed
|
||||||
|
prevRecv = self.provider.prev_io_counters[self.iface].bytes_recv
|
||||||
|
recv = self.provider.io_counters[self.iface].bytes_recv
|
||||||
|
prevSent = self.provider.prev_io_counters[self.iface].bytes_sent
|
||||||
|
sent = self.provider.io_counters[self.iface].bytes_sent
|
||||||
|
recvDiff = recv - prevRecv
|
||||||
|
sentDiff = sent - prevSent
|
||||||
|
dt = self.provider.time - self.provider.prev_time
|
||||||
|
recvDiff /= dt
|
||||||
|
sentDiff /= dt
|
||||||
|
|
||||||
|
text += f" ↓{humanSize(recvDiff)}↑{humanSize(sentDiff)}"
|
||||||
|
|
||||||
|
if state >= 4: # Counter
|
||||||
|
text += f" ⇓{humanSize(recv)}⇑{humanSize(sent)}"
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@ -582,12 +636,25 @@ class NetworkProvider(MirrorProvider):
|
||||||
async def run(self) -> None:
|
async def run(self) -> None:
|
||||||
await super().run()
|
await super().run()
|
||||||
|
|
||||||
while True:
|
loop = asyncio.get_running_loop()
|
||||||
# if_addrs: dict[str, list[psutil._common.snicaddr]] = psutil.net_if_addrs()
|
self.time = loop.time()
|
||||||
# io_counters: dict[str, psutil._common.snetio] = psutil.net_io_counters(pernic=True)
|
self.io_counters = psutil.net_io_counters(pernic=True)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Separate TaskGroup in case it takes longer than one second,
|
||||||
|
# it doesn't fill the main TaskGroup
|
||||||
async with asyncio.TaskGroup() as tg:
|
async with asyncio.TaskGroup() as tg:
|
||||||
|
self.prev_io_counters = self.io_counters
|
||||||
|
self.prev_time = self.time
|
||||||
|
# On-demand would only benefit if_addrs:
|
||||||
|
# stats are used to determine display,
|
||||||
|
# and we want to keep previous io_counters
|
||||||
|
# so displaying stats is ~instant.
|
||||||
|
self.time = loop.time()
|
||||||
self.if_stats = psutil.net_if_stats()
|
self.if_stats = psutil.net_if_stats()
|
||||||
|
self.if_addrs = psutil.net_if_addrs()
|
||||||
|
self.io_counters = psutil.net_io_counters(pernic=True)
|
||||||
|
|
||||||
for iface in self.if_stats:
|
for iface in self.if_stats:
|
||||||
if iface not in self.sections:
|
if iface not in self.sections:
|
||||||
section = NetworkProviderSection(
|
section = NetworkProviderSection(
|
||||||
|
@ -595,6 +662,7 @@ class NetworkProvider(MirrorProvider):
|
||||||
)
|
)
|
||||||
self.sections[iface] = section
|
self.sections[iface] = section
|
||||||
|
|
||||||
|
self.module.bar.addLongRunningTask(section.updateOnStateChange())
|
||||||
tg.create_task(self.updateIface(iface))
|
tg.create_task(self.updateIface(iface))
|
||||||
for iface, section in self.sections.items():
|
for iface, section in self.sections.items():
|
||||||
if iface not in self.if_stats:
|
if iface not in self.if_stats:
|
||||||
|
|
Loading…
Reference in a new issue