Mercurial > libervia-web
view libervia/web/pages/_browser/cache.py @ 1622:c2065de5f6d0
browser (cache): better handling of roster and identities:
roster and identities are now handled and updated separately.
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 15 May 2025 17:52:59 +0200 |
parents | a2cd4222c702 |
children |
line wrap: on
line source
from browser import window, console as log from browser.local_storage import storage from dialog import notification from bridge import Bridge, AsyncBridge import javascript import json log.warning = log.warn session_uuid = window.session_uuid bridge = Bridge() async_bridge = AsyncBridge() profile = window.profile or "" STORAGE_KEY = f"libervia_cache_{profile}" # XXX: we don't use browser.object_storage because it is affected by # https://github.com/brython-dev/brython/issues/1467 and mixing local_storage.storage # and object_storage was resulting in weird behaviour (keys found in one not in the # other) class Cache: def __init__(self): self._cache = { 'metadata': { "session_uuid": session_uuid, }, 'roster': {}, 'identities': {}, } try: cache = storage[STORAGE_KEY] except KeyError: self.request_data_from_backend() else: cache = json.loads(cache) if cache['metadata']['session_uuid'] != session_uuid: log.debug("Data in cache are not valid for this session, resetting.") del storage[STORAGE_KEY] self.request_data_from_backend() elif not cache.get("roster") or not cache.get("identities"): log.debug("Incomplete data in cache, requesting backend.") self.request_data_from_backend() else: self._cache = cache log.debug("Storage cache is used.") @property def roster(self): return self._cache['roster'] @property def identities(self): return self._cache['identities'] def update(self): log.debug(f"updating: {self._cache}") # FIXME: workaround in Brython 3.13.0 # storage[STORAGE_KEY] = json.dumps(self._cache) storage[STORAGE_KEY] = javascript.JSON.stringify(self._cache) log.debug("cache stored") def get_contacts_cb(self, contacts): log.debug("roster received") roster = self._cache['roster'] = {} for contact_jid, attributes, groups in contacts: roster[contact_jid] = { 'attributes': attributes, 'groups': groups, } self.update() def identities_base_get_cb(self, identities_raw): log.debug("base identities received") identities = json.loads(identities_raw) self._cache['identities'] = identities self.update() def request_failed(self, exc, message): notification.show(message.format(exc=exc), "error") def request_data_from_backend(self): log.debug("requesting roster to backend") bridge.contacts_get( callback=self.get_contacts_cb, errback=lambda e: self.request_failed(e, "Can't get contacts: {exc}") ) log.debug("requesting base identities to backend") bridge.identities_base_get( callback=self.identities_base_get_cb, errback=lambda e: self.request_failed(e, "Can't get base identities: {exc}") ) async def fill_identities(self, entities) -> None: """Check that identities for entities exist, request them otherwise""" to_get = {e for e in entities if e not in self._cache['identities']} if to_get: log.debug(f"we don't have all identities in cache, getting {to_get}") try: new_identities_raw = await async_bridge.identities_get( list(to_get), ['avatar', 'nicknames'], ) except Exception as e: notification.show( f"Can't get identities: {e}", "error" ) else: new_identities = json.loads(new_identities_raw) log.debug(f"new identities: {new_identities.keys()}") self._cache['identities'].update(new_identities) self.update() else: # we already have all identities log.debug("no missing identity") def match_identity(self, entity_jid, text, identity=None): """Returns True if a text match an entity identity identity will be matching if its jid or any of its name contain text @param entity_jid: jid of the entity to check @param text: text to use for filtering. Must be in lowercase and stripped @param identity: identity data if None, it will be retrieved if jid is not matching @return: True if entity is matching """ if text in entity_jid: return True if identity is None: try: identity = self.identities[entity_jid] except KeyError: log.debug(f"missing identity: {entity_jid}") return False return any(text in n.lower() for n in identity['nicknames']) def matching_identities(self, text): """Return identities corresponding to a text """ text = text.lower().strip() for entity_jid, identity in self._cache['identities'].items(): if ((text in entity_jid or any(text in n.lower() for n in identity['nicknames']) )): yield entity_jid cache = Cache() roster = cache.roster identities = cache.identities