cache.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. # -*- coding: utf-8 -*-
  2. """
  3. TTL-basierter In-Memory-Cache fuer Wetterdaten.
  4. """
  5. from datetime import datetime, timedelta
  6. from plugins.weather.models import WeatherResult
  7. from trixy_core.utils.debug import pdebug
  8. class WeatherCache:
  9. """
  10. Einfacher TTL-basierter Cache fuer WeatherResult-Objekte.
  11. Attributes:
  12. _cache: Zuordnung location_key -> WeatherResult
  13. _ttl_hours: Gueltigkeitsdauer in Stunden
  14. """
  15. def __init__(self, ttl_hours: float = 5.0) -> None:
  16. self._cache: dict[str, WeatherResult] = {}
  17. self._ttl_hours = ttl_hours
  18. def get(self, location_key: str) -> WeatherResult | None:
  19. """
  20. Gibt gecachte Wetterdaten zurueck, falls noch gueltig.
  21. Args:
  22. location_key: Normalisierter Stadtname (lowercase)
  23. Returns:
  24. WeatherResult oder None wenn abgelaufen/nicht vorhanden
  25. """
  26. result = self._cache.get(location_key)
  27. if result is None:
  28. return None
  29. if not self._is_fresh(result):
  30. pdebug(f"WeatherCache: Cache abgelaufen fuer '{location_key}'")
  31. del self._cache[location_key]
  32. return None
  33. return result
  34. def set(self, location_key: str, result: WeatherResult) -> None:
  35. """
  36. Speichert ein WeatherResult im Cache.
  37. Args:
  38. location_key: Normalisierter Stadtname (lowercase)
  39. result: Wetterergebnis
  40. """
  41. self._cache[location_key] = result
  42. pdebug(f"WeatherCache: Cache aktualisiert fuer '{location_key}'")
  43. def is_valid(self, location_key: str) -> bool:
  44. """
  45. Prueft ob ein gueltiger Cache-Eintrag existiert.
  46. Args:
  47. location_key: Normalisierter Stadtname (lowercase)
  48. Returns:
  49. True wenn gueltig und nicht abgelaufen
  50. """
  51. result = self._cache.get(location_key)
  52. if result is None:
  53. return False
  54. return self._is_fresh(result)
  55. def clear(self) -> None:
  56. """Leert den gesamten Cache."""
  57. self._cache.clear()
  58. pdebug("WeatherCache: Cache geleert")
  59. def _is_fresh(self, result: WeatherResult) -> bool:
  60. """Prueft ob ein Ergebnis noch innerhalb der TTL liegt."""
  61. age = datetime.now() - result.fetched_at
  62. return age < timedelta(hours=self._ttl_hours)