frobar: Gracefully handle zelbar exists

Before it would just spam logs with "Unknown command: "
This commit is contained in:
Geoffrey Frogeye 2025-12-17 10:01:57 +01:00
parent 356186de7c
commit 465c2347cb
2 changed files with 48 additions and 36 deletions

View file

@ -1,7 +1,7 @@
{ {
zelbarnixpkgs ? builtins.getFlake "github:wlcx/nixpkgs/zelbar", zelbarnixpkgs ? builtins.getFlake "github:wlcx/nixpkgs/zelbar",
# nixpkgs ? <nixpkgs>, nixpkgs ? <nixpkgs>,
nixpkgs ? builtins.getFlake "nixpkgs/nixos-25.11", # nixpkgs ? builtins.getFlake "nixpkgs/nixos-25.11",
pkgs ? import nixpkgs { pkgs ? import nixpkgs {
overlays = [ overlays = [
(self: super: { (self: super: {

View file

@ -4,7 +4,6 @@ import datetime
import enum import enum
import logging import logging
import signal import signal
import sys
import typing import typing
import gi import gi
@ -361,29 +360,32 @@ class Screen(ComposableText):
self.output, self.output,
] ]
print(" ".join(cmd)) print(" ".join(cmd))
loop = asyncio.get_running_loop()
while True:
last_start_time = loop.time()
proc = await asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
*cmd, *cmd,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
stdin=asyncio.subprocess.PIPE, stdin=asyncio.subprocess.PIPE,
) )
async def refresher() -> None: async def refresher(proc: asyncio.subprocess.Process) -> None:
assert proc.stdin assert proc.stdin
while True: while proc.returncode is None:
await self.refresh.wait()
self.refresh.clear()
markup = self.get_markup() markup = self.get_markup()
# sys.stdout.write(markup) # DEBUG # sys.stdout.write(markup) # DEBUG
proc.stdin.write(markup.encode()) proc.stdin.write(markup.encode())
await self.refresh.wait()
self.refresh.clear()
async def action_handler() -> None: async def action_handler(proc: asyncio.subprocess.Process) -> None:
assert proc.stdout assert proc.stdout
while True: while proc.returncode is None:
line = await proc.stdout.readline() line = await proc.stdout.readline()
try: try:
command = line.decode().strip() command = line.decode().strip()
except UnicodeDecodeError: except UnicodeDecodeError:
# FIXME zelbar seems to have some memory issues # TODO zelbar seems to have some memory issues
log.exception("Not unicode: %s", str(line)) log.exception("Not unicode: %s", str(line))
continue continue
callback = self.actions.get(command) callback = self.actions.get(command)
@ -392,8 +394,17 @@ class Screen(ComposableText):
continue continue
callback() callback()
self.bar.add_long_running_task(refresher()) refresher_task = self.bar.add_long_running_task(refresher(proc))
self.bar.add_long_running_task(action_handler()) action_handler_task = self.bar.add_long_running_task(action_handler(proc))
await proc.wait()
log.error("zelbar exited with code %d", proc.returncode)
refresher_task.cancel()
action_handler_task.cancel()
# Delay restart if it's been less than 5 seconds to prevent infinite loops
time_since_start = loop.time() - last_start_time
await asyncio.sleep(max(0, 5 - time_since_start))
def add_action(self, callback: typing.Callable) -> str: def add_action(self, callback: typing.Callable) -> str:
command = f"com{self.actionIndex:x}" command = f"com{self.actionIndex:x}"
@ -434,14 +445,15 @@ class Bar(ComposableText):
continue continue
Screen(parent=self, output=output.name) Screen(parent=self, output=output.name)
def add_long_running_task(self, coro: typing.Coroutine) -> None: def add_long_running_task(self, coro: typing.Coroutine) -> asyncio.Task:
task = self.taskGroup.create_task(coro) task = self.taskGroup.create_task(coro)
self.longRunningTasks.append(task) self.longRunningTasks.append(task)
return task
async def run(self) -> None: async def run(self) -> None:
async with self.taskGroup: async with self.taskGroup:
for screen in self.children: for screen in self.children:
await screen.run() self.add_long_running_task(screen.run())
for provider in self.providers: for provider in self.providers:
self.add_long_running_task(provider.run()) self.add_long_running_task(provider.run())
@ -630,7 +642,7 @@ class PeriodicProvider(Provider):
while True: while True:
# TODO Block bar update during the periodic update of the loops # TODO Block bar update during the periodic update of the loops
loops = [provider.loop() for provider in providers] loops = [provider.loop() for provider in providers]
asyncio.gather(*loops) await asyncio.gather(*loops)
now = datetime.datetime.now(datetime.UTC) now = datetime.datetime.now(datetime.UTC)
# Hardcoded to 1 second... not sure if we want some more than that, # Hardcoded to 1 second... not sure if we want some more than that,