CachedLoadingPage.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #
  2. # Copyright (c) Daniel Sheffield 2023
  3. # All rights reserved
  4. #
  5. # THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
  6. from queue import Queue, Empty
  7. from time import time
  8. from threading import Lock
  9. from typing import Callable, Union
  10. STALE = 10*60
  11. class CachedLoadingPage():
  12. value: str
  13. def __init__(self, initial_value: Union[str, list], provider: Callable[[Queue], None], incremental: bool = True):
  14. self._created = time()
  15. self._queue = Queue()
  16. self._loaded = False
  17. self.value = initial_value
  18. self._lock = Lock()
  19. self.provider = provider
  20. self.incremental = incremental
  21. @property
  22. def age(self) -> float:
  23. return time() - self._created
  24. @property
  25. def queue(self) -> Queue:
  26. return self._queue
  27. @property
  28. def loaded(self) -> bool:
  29. return self._loaded
  30. def _set_loaded(self, value: bool) -> bool:
  31. self._loaded = value
  32. return self._loaded
  33. @property
  34. def stale(self) -> bool:
  35. return self.age > STALE
  36. def _start(self) -> None:
  37. if not self.provider:
  38. return
  39. self.provider(self.queue)
  40. self.provider = None
  41. def update(self) -> Union[str, list]:
  42. if not self._lock.acquire(blocking=True, timeout=0.5):
  43. return self.value
  44. try:
  45. self._start()
  46. item = self._queue.get(block=True, timeout=0.5)
  47. if item is None:
  48. self._queue.task_done()
  49. self._set_loaded(True)
  50. else:
  51. if self.incremental:
  52. self.value.append(item)
  53. else:
  54. self.value = item
  55. self.queue.task_done()
  56. except Empty:
  57. pass
  58. finally:
  59. self._lock.release()
  60. return self.value