comparison libervia/pages/_browser/cache.py @ 1329:ed28ad7d484c

browser (cache): new `cache` module to handle cache of roster and identities: the cache is put in local storage and linked to a session.
author Goffi <goffi@goffi.org>
date Fri, 14 Aug 2020 09:31:32 +0200
parents
children 7472d5a88006
comparison
equal deleted inserted replaced
1328:683e50799d6d 1329:ed28ad7d484c
1 from browser import window
2 from browser.local_storage import storage
3 from javascript import JSON
4 from dialog import notification
5 from bridge import Bridge
6
7 session_uuid = window.session_uuid
8 bridge = Bridge()
9
10 # XXX: we don't use browser.object_storage because it is affected by
11 # https://github.com/brython-dev/brython/issues/1467 and mixing local_storage.storage
12 # and object_storage was resulting in weird behaviour (keys found in one not in the
13 # other)
14
15
16 class Cache:
17
18 def __init__(self):
19 try:
20 cache = storage['libervia_cache']
21 except KeyError:
22 self.request_data_from_backend()
23 else:
24 cache = JSON.parse(cache)
25 if cache['metadata']['session_uuid'] != session_uuid:
26 print("data in cache are not valid for this session, resetting")
27 del storage['libervia_cache']
28 self.request_data_from_backend()
29 else:
30 self._cache = cache
31 print("storage cache is used")
32
33 @property
34 def roster(self):
35 return self._cache['roster']
36
37 @property
38 def identities(self):
39 return self._cache['identities']
40
41 def update(self):
42 # FIXME: we use window.JSON as a workaround to
43 # https://github.com/brython-dev/brython/issues/1467
44 print(f"updating: {self._cache}")
45 storage['libervia_cache'] = window.JSON.stringify(self._cache)
46 print("cache stored")
47
48 def _store_if_complete(self):
49 self._completed_count -= 1
50 if self._completed_count == 0:
51 del self._completed_count
52 self.update()
53
54 def getContactsCb(self, contacts):
55 print("roster received")
56 roster = self._cache['roster']
57 for contact_jid, attributes, groups in contacts:
58 roster[contact_jid] = {
59 'attributes': attributes,
60 'groups': groups,
61 }
62 self._store_if_complete()
63
64 def identitiesBaseGetCb(self, identities_raw):
65 print("base identities received")
66 identities = JSON.parse(identities_raw)
67 self._cache['identities'].update(identities)
68 self._store_if_complete()
69
70 def request_failed(self, exc, message):
71 notification.show(message.format(exc=exc), "error")
72 self._store_if_complete()
73
74 def request_data_from_backend(self):
75 self._cache = {
76 'metadata': {
77 "session_uuid": session_uuid,
78 },
79 'roster': {},
80 'identities': {},
81 }
82 self._completed_count = 2
83 print("requesting roster to backend")
84 bridge.getContacts(
85 callback=self.getContactsCb,
86 errback=lambda e: self.request_failed(e, "Can't get contacts: {exc}")
87 )
88 print("requesting base identities to backend")
89 bridge.identitiesBaseGet(
90 callback=self.identitiesBaseGetCb,
91 errback=lambda e: self.request_failed(e, "Can't get base identities: {exc}")
92 )
93
94 def _fill_identities_cb(self, new_identities_raw, callback):
95 new_identities = JSON.parse(new_identities_raw)
96 print(f"new identities: {new_identities.keys()}")
97 self._cache['identities'].update(new_identities)
98 self.update()
99 if callback:
100 callback()
101
102 def fill_identities(self, entities, callback=None):
103 """Check that identities for identites exist, request them otherwise"""
104 to_get = {e for e in entities if e not in self._cache['identities']}
105 if to_get:
106 bridge.identitiesGet(
107 list(to_get),
108 ['avatar', 'nicknames'],
109 callback=lambda identities: self._fill_identities_cb(
110 identities, callback),
111 errback=lambda failure_: notification.show(
112 f"Can't get identities: {failure_}",
113 "error"
114 )
115 )
116 else:
117 # we already have all identities
118 print("no missing identity")
119 if callback:
120 callback()
121
122 def match_identity(self, entity_jid, text, identity=None):
123 """Returns True if a text match an entity identity
124
125 identity will be matching if its jid or any of its name contain text
126 @param entity_jid: jid of the entity to check
127 @param text: text to use for filtering. Must be in lowercase and stripped
128 @param identity: identity data
129 if None, it will be retrieved if jid is not matching
130 @return: True if entity is matching
131 """
132 if text in entity_jid:
133 return True
134 if identity is None:
135 try:
136 identity = self.identities[entity_jid]
137 except KeyError:
138 print(f"missing identity: {entity_jid}")
139 return False
140 return any(text in n.lower() for n in identity['nicknames'])
141
142 def matching_identities(self, text):
143 """Return identities corresponding to a text
144
145 """
146 text = text.lower().strip()
147 for entity_jid, identity in self._cache['identities'].items():
148 if ((text in entity_jid
149 or any(text in n.lower() for n in identity['nicknames'])
150 )):
151 yield entity_jid
152
153
154 cache = Cache()
155 roster = cache.roster
156 identities = cache.identities