Mercurial > libervia-web
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 |