From d32410cf38b74260854e4f1666aa0d95ce9de605 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Sat, 23 Dec 2023 11:46:27 -0600 Subject: [PATCH] Rework ZGS cache strategy --- soco/events_base.py | 6 ++++++ soco/zonegroupstate.py | 17 ++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/soco/events_base.py b/soco/events_base.py index f53e8e20f..033de77a7 100644 --- a/soco/events_base.py +++ b/soco/events_base.py @@ -453,6 +453,8 @@ def success(headers): # Autorenew just before expiry, say at 85% of self.timeout seconds interval = self.timeout * 85 / 100 self._auto_renew_start(interval) + if service.service_type == "ZoneGroupTopology": + service.soco.zone_group_state.extend_cache(self.timeout) # Lock out EventNotifyHandler during registration. # If events_twisted is used, this lock should always be @@ -523,6 +525,8 @@ def success(headers): self.service.base_url + self.service.event_subscription_url, self.sid, ) + if self.service.service_type == "ZoneGroupTopology": + self.service.soco.zone_group_state.extend_cache(self.timeout) return self._request( "SUBSCRIBE", @@ -653,6 +657,8 @@ def _cancel_subscription(self, msg=None): # an attempt to unsubscribe fails self._has_been_unsubscribed = True self._timestamp = None + if self.service.service_type == "ZoneGroupTopology": + self.service.soco.zone_group_state.clear_cache() # Cancel any auto renew self._auto_renew_cancel() if msg: diff --git a/soco/zonegroupstate.py b/soco/zonegroupstate.py index 1f89952f2..5f926ab87 100755 --- a/soco/zonegroupstate.py +++ b/soco/zonegroupstate.py @@ -124,6 +124,11 @@ def clear_cache(self): """Clear the cache timestamp.""" self._cache_until = NEVER_TIME + def extend_cache(self, timeout=EVENT_CACHE_TIMEOUT): + """Extend the cache timeout.""" + self._cache_until = time.monotonic() + timeout + _LOG.debug("Extending ZGS cache by %ss", timeout) + def clear_zone_groups(self): """Clear all known group sets.""" self.groups.clear() @@ -156,6 +161,7 @@ def poll(self, soco): try: zgs = soco.zoneGroupTopology.GetZoneGroupState()["ZoneGroupState"] self.process_payload(payload=zgs, source="poll", source_ip=soco.ip_address) + self.extend_cache(POLLING_CACHE_TIMEOUT) # In the event of failure, we fall back to using a ZGT event to # determine the ZGS. Fallback behaviour can be disabled by setting the @@ -244,22 +250,12 @@ async def update_zgs_by_event_asyncio(speaker): def process_payload(self, payload, source, source_ip): """Update using the provided XML payload.""" self.total_requests += 1 - - def update_cache(): - if source == "event": - timeout = EVENT_CACHE_TIMEOUT - else: - timeout = POLLING_CACHE_TIMEOUT - self._cache_until = time.monotonic() + timeout - _LOG.debug("Setting ZGS cache to %ss", timeout) - tree = normalize_zgs_xml(payload) normalized_zgs = str(tree) if normalized_zgs == self._last_zgs: _LOG.debug( "Duplicate ZGS received from %s (%s), ignoring", source_ip, source ) - update_cache() return self.processed_count += 1 @@ -272,7 +268,6 @@ def update_cache(): ) self.update_soco_instances(tree) - update_cache() self._last_zgs = normalized_zgs def parse_zone_group_member(self, member_element):