浏览代码

user_cal: memoize the Calendar across UserCal constructions

UserCal() previously built a fresh Calendar + CalDAVBackend per
instantiation (three call sites construct it per action run), paying
the calendar URL resolution round-trip every time.

The Calendar is now module-memoized so the resolved URL survives; the
event cache is cleared on each UserCal() construction because the user
edits this calendar externally — read freshness is unchanged. Adds
Calendar.clear_event_cache() as the public way to do that.

require_user_cal resets the memo via monkeypatch so the radicale test
config can't leak into other tests.
ZiB 4 月之前
父节点
当前提交
871ece418a
共有 3 个文件被更改,包括 26 次插入 和 2 次删除
  1. 4 0
      room_cal/caldav.py
  2. 19 2
      room_cal/user_cal/__init__.py
  3. 3 0
      tests/conftest.py

+ 4 - 0
room_cal/caldav.py

@@ -83,6 +83,10 @@ class Calendar:
   def calendar_name(self) -> str:
     return self._calendar_name
 
+  def clear_event_cache(self) -> None:
+    """Drop cached range responses so the next fetch re-reads the server."""
+    self._event_cache.clear()
+
   def _resolved_connection(self) -> dict:
     if not self._connection.get('url'):
       raise ValueError('CALDAV_URL must be set via store.caldav.url in config.json')

+ 19 - 2
room_cal/user_cal/__init__.py

@@ -9,12 +9,29 @@ from room_cal._utils import EventSource, get_config, safe_json_loads, services a
 
 _ROOM_CLOSED_TITLE = 'Room Closed'
 
+_user_calendar: Calendar | None = None
+
+
+def _get_user_calendar() -> Calendar:
+  """Shared Calendar for the user_cal connection, created on first call.
+
+  Memoized so the resolved calendar URL survives across UserCal()
+  constructions. The event cache is cleared per construction — the user
+  edits this calendar externally, so each operation must re-read.
+  """
+  global _user_calendar
+  if _user_calendar is None:
+    cfg = get_config().user_cal
+    _user_calendar = Calendar(cfg.calendar_name, url=cfg.url, username=cfg.username, password=cfg.password)
+  return _user_calendar
+
 
 class UserCal(EventSource):
   def __init__(self, *, backend=None):
     if backend is None:
-      cfg = get_config().user_cal
-      backend = CalDAVBackend(Calendar(cfg.calendar_name, url=cfg.url, username=cfg.username, password=cfg.password))
+      cal = _get_user_calendar()
+      cal.clear_event_cache()
+      backend = CalDAVBackend(cal)
     self._backend = backend
     EventSource.__init__(self, 'user_cal')
 

+ 3 - 0
tests/conftest.py

@@ -102,3 +102,6 @@ def require_user_cal(radicale_server, monkeypatch):
   mock = lambda: test_cfg
   monkeypatch.setattr('room_cal.user_cal.get_config', mock)
   monkeypatch.setattr('room_cal.actions.fetch_user_cal.get_config', mock)
+  # reset the memoized user_cal Calendar so it's rebuilt from the patched
+  # config (and restored after the test)
+  monkeypatch.setattr('room_cal.user_cal._user_calendar', None)