# -*- coding: utf-8 -*- # SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-License-Identifier: GPL-2.0-or-later """Main daemon of revpi-middleware.""" from logging import getLogger from threading import Event from time import perf_counter from . import proginit as pi from .dbus_middleware1.bus_provider import BusProvider log = getLogger(__name__) class MiddlewareDaemon: """Main program of MiddlewareDaemon class.""" def __init__(self): """Init MiddlewareDaemon class.""" log.debug("enter MiddlewareDaemon.__init__") self._cycle_time = 1.0 self.do_cycle = Event() self._reconfigure = False self._running = True self.bus_provider = None self._configure() log.debug("leave MiddlewareDaemon.__init__") def _configure(self) -> None: """Load the configuration file and set values.""" log.debug("enter MiddlewareDaemon._configure") pi.reload_conf() log.debug("leave MiddlewareDaemon._configure") def dbus_start(self): log.debug("enter MiddlewareDaemon.dbus_start") if self.bus_provider and self.bus_provider.is_alive(): return self.bus_provider = BusProvider() self.bus_provider.start() log.debug("leave MiddlewareDaemon.dbus_start") def dbus_stop(self): log.debug("enter MiddlewareDaemon.dbus_stop") if self.bus_provider: self.bus_provider.stop() self.bus_provider.join(timeout=10.0) if self.bus_provider.is_alive(): log.warning("dbus provider thread is still alive") log.debug("leave MiddlewareDaemon.dbus_stop") def reload_config(self) -> None: """Reload configuration file.""" log.debug("enter MiddlewareDaemon.reload_config") self._reconfigure = True self.do_cycle.set() log.debug("leave MiddlewareDaemon.reload_config") @staticmethod def rotate_logfile() -> None: """Start a new logfile.""" log.debug("enter MiddlewareDaemon.rotate_logfile") pi.reconfigure_logger() log.warning("start new logfile") log.debug("leave MiddlewareDaemon.rotate_logfile") def start(self) -> int: """Blocking mainloop of program.""" log.debug("enter MiddlewareDaemon.start") error_code = 0 # Startup tasks self.dbus_start() pi.startup_complete() # Go into mainloop of daemon while self._running: ot = perf_counter() self.do_cycle.clear() # Early tasks of the cycle loop if self._reconfigure: self._configure() self._reconfigure = False pi.startup_complete() # Cycle time calculation dm = divmod(ot - perf_counter(), self._cycle_time) # For float the result is (q, a % b), where q is usually math.floor(a / b) but may be 1 less than that. if dm[0] == -1.0: # Cycle time isn't exceeded self.do_cycle.wait(dm[1]) else: log.debug("Cycle time exceeded about {0:.0f} times".format(abs(dm[0]))) # Cleanup tasks self.dbus_stop() log.debug("leave MiddlewareDaemon.start") return error_code def stop(self) -> None: """Set stop request for mainloop.""" log.debug("enter MiddlewareDaemon.stop") self._running = False self.do_cycle.set() log.debug("leave MiddlewareDaemon.stop")