"""Monitor for tracking Ollama availability and notifying on state changes.""" from __future__ import annotations from typing import Callable from gi.repository import GLib from .ollama_client import OllamaClient class OllamaAvailabilityMonitor: """Monitors Ollama availability and notifies callbacks on state changes.""" def __init__(self, client: OllamaClient, check_interval_seconds: int = 30) -> None: """ Initialize the availability monitor. Args: client: OllamaClient instance to monitor check_interval_seconds: How often to check availability (default: 30s) """ self._client = client self._check_interval_ms = check_interval_seconds * 1000 self._callbacks: list[Callable[[bool], None]] = [] self._last_state: bool | None = None self._timeout_id: int | None = None self._is_running = False def add_callback(self, callback: Callable[[bool], None]) -> None: """ Add a callback to be notified when availability changes. Args: callback: Function that takes a bool (True if available, False if not) """ if callback not in self._callbacks: self._callbacks.append(callback) def remove_callback(self, callback: Callable[[bool], None]) -> None: """Remove a previously registered callback.""" if callback in self._callbacks: self._callbacks.remove(callback) def start(self) -> None: """Start monitoring Ollama availability.""" if self._is_running: return self._is_running = True # Do an immediate check self._check_availability() # Schedule periodic checks self._timeout_id = GLib.timeout_add( self._check_interval_ms, self._check_availability ) def stop(self) -> None: """Stop monitoring Ollama availability.""" if not self._is_running: return self._is_running = False if self._timeout_id is not None: GLib.source_remove(self._timeout_id) self._timeout_id = None def _check_availability(self) -> bool: """ Check current availability and notify callbacks if state changed. Returns: True to continue periodic checks, False to stop """ # Force a connection check self._client._check_connection() current_state = self._client.is_available # Only notify if state changed if self._last_state is None or self._last_state != current_state: self._last_state = current_state self._notify_callbacks(current_state) # Return True to continue periodic checks return True def _notify_callbacks(self, is_available: bool) -> None: """Notify all registered callbacks of the availability state.""" for callback in self._callbacks: try: callback(is_available) except Exception as e: # Log error but don't let one callback failure affect others print(f"Error in availability callback: {e}") @property def is_running(self) -> bool: """Check if the monitor is currently running.""" return self._is_running @property def current_state(self) -> bool | None: """Get the last known availability state (None if never checked).""" return self._last_state