Philipp Hörist pushed to branch master at gajim / gajim
Commits: 8392372a by Philipp Hörist at 2023-05-23T00:34:23+02:00 refactor: Create contact cache per account
- - - - -
6 changed files:
- gajim/common/modules/contacts.py - gajim/common/modules/discovery.py - gajim/common/modules/user_nickname.py - gajim/common/modules/vcard_avatars.py - gajim/common/storage/cache.py - gajim/gtk/avatar.py
Changes:
===================================== gajim/common/modules/contacts.py ===================================== @@ -360,7 +360,8 @@ def __init__(self, logger: LogAdapter, jid: JID, account: str) -> None: self.settings = ContactSettings(account, jid) self._resources: dict[str, ResourceContact] = {}
- self._avatar_sha = app.storage.cache.get_contact(jid, 'avatar') + self._avatar_sha = app.storage.cache.get_contact( + account, jid, 'avatar')
@property def is_self(self): @@ -448,7 +449,8 @@ def name(self) -> str: if item is not None and item.name: return item.name
- nickname = app.storage.cache.get_contact(self._jid, 'nickname') + nickname = app.storage.cache.get_contact( + self._account, self._jid, 'nickname') if nickname: return nickname if self._jid.is_domain: @@ -466,7 +468,11 @@ def get_location(self) -> Optional[LocationData]:
@property def avatar_sha(self) -> Optional[str]: - return app.storage.cache.get_contact(self._jid, 'avatar') + return app.storage.cache.get_contact( + self._account, self._jid, 'avatar') + + def set_avatar_sha(self, sha: str) -> None: + app.storage.cache.set_contact(self._account, self._jid, 'avatar', sha)
def get_avatar(self, size: int, @@ -514,7 +520,7 @@ def update_avatar(self, sha: str) -> None:
self._avatar_sha = sha
- app.storage.cache.set_contact(self._jid, 'avatar', sha) + app.storage.cache.set_contact(self._account, self._jid, 'avatar', sha) app.app.avatar_storage.invalidate_cache(self._jid) self.notify('avatar-update')
@@ -743,7 +749,10 @@ def name(self) -> str:
@property def avatar_sha(self) -> Optional[str]: - return app.storage.cache.get_muc(self._jid, 'avatar') + return app.storage.cache.get_muc(self._account, self._jid, 'avatar') + + def set_avatar_sha(self, sha: str) -> None: + app.storage.cache.set_muc(self._account, self._jid, 'avatar', sha)
def get_avatar(self, size: int, scale: int) -> Optional[cairo.ImageSurface]: transport_icon = None
===================================== gajim/common/modules/discovery.py ===================================== @@ -235,7 +235,8 @@ def disco_muc(self, if not app.app.avatar_storage.avatar_exists(avatar_sha): app.app.avatar_storage.save_avatar(avatar)
- app.storage.cache.set_muc(result.info.jid, 'avatar', avatar_sha) + app.storage.cache.set_muc( + self._account, result.info.jid, 'avatar', avatar_sha) app.app.avatar_storage.invalidate_cache(result.info.jid)
self._con.get_module('VCardAvatars').muc_disco_info_update(result.info)
===================================== gajim/common/modules/user_nickname.py ===================================== @@ -55,7 +55,8 @@ def _nickname_received(self, app.nicks[self._account] = nick return
- app.storage.cache.set_contact(properties.jid, 'nickname', nick) + app.storage.cache.set_contact( + self._account, properties.jid, 'nickname', nick)
self._log.info('Nickname for %s: %s', properties.jid, nick)
===================================== gajim/common/modules/vcard_avatars.py ===================================== @@ -97,11 +97,8 @@ def _request_vcard(self, self._log.info('Received: %s %s', contact.jid, avatar_sha) app.app.avatar_storage.save_avatar(avatar)
- if isinstance(contact, BareContact): - app.storage.cache.set_contact(contact.jid, 'avatar', avatar_sha) - - elif isinstance(contact, GroupchatContact): - app.storage.cache.set_muc(contact.jid, 'avatar', avatar_sha) + if isinstance(contact, (BareContact, GroupchatContact)): + contact.set_avatar_sha(avatar_sha)
else: self._muc_avatar_cache[contact.jid] = avatar_sha @@ -159,11 +156,7 @@ def _process_update(self, if state == AvatarState.EMPTY: # Empty <photo/> tag, means no avatar is advertised self._log.info('%s has no avatar published', jid) - if groupchat: - app.storage.cache.set_muc(jid, 'avatar', None) - else: - app.storage.cache.set_contact(jid, 'avatar', None) - + contact.set_avatar_sha(None) contact.update_avatar(avatar_sha)
else: @@ -176,11 +169,7 @@ def _process_update(self, if app.app.avatar_storage.avatar_exists(avatar_sha): # Check if the avatar is already in storage self._log.info('Found avatar in storage') - if groupchat: - app.storage.cache.set_muc(jid, 'avatar', avatar_sha) - else: - app.storage.cache.set_contact(jid, 'avatar', avatar_sha) - + contact.set_avatar_sha(avatar_sha) contact.update_avatar(avatar_sha) return
===================================== gajim/common/storage/cache.py ===================================== @@ -35,7 +35,9 @@ from gajim.common.storage.base import SqliteStorage from gajim.common.storage.base import timeit
-CURRENT_USER_VERSION = 9 +ContactCacheDictT = dict[tuple[str, JID], dict[str, Any]] + +CURRENT_USER_VERSION = 10
CACHE_SQL_STATEMENT = ''' CREATE TABLE caps_cache ( @@ -54,15 +56,19 @@ roster TEXT ); CREATE TABLE muc( - jid TEXT PRIMARY KEY UNIQUE, - avatar TEXT + account TEXT, + jid TEXT, + avatar TEXT, + PRIMARY KEY (account, jid) ); CREATE TABLE contact( - jid TEXT PRIMARY KEY UNIQUE, + account TEXT, + jid TEXT, avatar TEXT, avatar_ts INTEGER, nickname TEXT, - nickname_ts INTEGER + nickname_ts INTEGER, + PRIMARY KEY (account, jid) ); CREATE TABLE unread( account TEXT, @@ -101,8 +107,8 @@ def __init__(self, in_memory: bool = False):
self._entity_caps_cache: dict[tuple[str, str], DiscoInfo] = {} self._disco_info_cache: dict[JID, DiscoInfo] = {} - self._muc_cache: dict[JID, dict[str, Any]] = defaultdict(dict) - self._contact_cache: dict[JID, dict[str, Any]] = defaultdict(dict) + self._muc_cache: ContactCacheDictT = defaultdict(dict) + self._contact_cache: ContactCacheDictT = defaultdict(dict)
def init(self, **kwargs: Any) -> None: SqliteStorage.init(self, @@ -136,7 +142,7 @@ def _migrate(self) -> None: self._reinit_storage() return
- if user_version < 9: + if user_version < 10: self._reinit_storage() return
@@ -287,60 +293,74 @@ def remove_roster(self, account: str) -> None: self._commit()
@timeit - def set_muc(self, jid: JID, prop: str, value: Any) -> None: - sql = f'''INSERT INTO muc (jid, {prop}) VALUES (?, ?)''' + def set_muc(self, + account: str, + jid: JID, + prop: str, + value: Any + ) -> None: + + sql = f'''INSERT INTO muc (account, jid, {prop}) VALUES (?, ?, ?)'''
try: - self._con.execute(sql, (jid, value)) + self._con.execute(sql, (account, jid, value)) except sqlite3.IntegrityError: - sql = f'UPDATE muc SET {prop} = ? WHERE jid = ?' - self._con.execute(sql, (value, jid)) + sql = f'UPDATE muc SET {prop} = ? WHERE account = ? AND jid = ?' + self._con.execute(sql, (value, account, jid))
- self._muc_cache[jid][prop] = value + self._muc_cache[(account, jid)][prop] = value
self._delayed_commit()
@timeit - def get_muc(self, jid: JID, prop: str) -> Any: + def get_muc(self, account: str, jid: JID, prop: str) -> Any: try: - return self._muc_cache[jid][prop] + return self._muc_cache[(account, jid)][prop] except KeyError: sql = f'''SELECT jid as "jid [jid]", {prop} - FROM muc WHERE jid = ?''' - row = self._con.execute(sql, (jid,)).fetchone() + FROM muc WHERE account = ? AND jid = ?''' + row = self._con.execute(sql, (account, jid)).fetchone() value = None if row is None else getattr(row, prop)
- self._muc_cache[jid][prop] = value + self._muc_cache[(account, jid)][prop] = value return value
@timeit - def set_contact(self, jid: JID, prop: str, value: Any) -> None: - sql = f'INSERT INTO contact (jid, {prop}, {prop}_ts) VALUES (?, ?, ?)' + def set_contact(self, + account: str, + jid: JID, + prop: str, + value: Any + ) -> None: + + sql = f'''INSERT INTO contact (account, jid, {prop}, {prop}_ts) + VALUES (?, ?, ?, ?)'''
prop_ts = time.time()
try: - self._con.execute(sql, (jid, value, prop_ts)) + self._con.execute(sql, (account, jid, value, prop_ts)) except sqlite3.IntegrityError: - sql = f'UPDATE contact SET {prop} = ?, {prop}_ts = ? WHERE jid = ?' - self._con.execute(sql, (value, prop_ts, jid)) + sql = f'''UPDATE contact SET {prop} = ?, {prop}_ts = ? + WHERE account = ? AND jid = ?''' + self._con.execute(sql, (value, prop_ts, account, jid))
- self._contact_cache[jid][prop] = (value, prop_ts) + self._contact_cache[(account, jid)][prop] = (value, prop_ts)
self._delayed_commit()
@timeit - def get_contact(self, jid: JID, prop: str) -> Any: + def get_contact(self, account: str, jid: JID, prop: str) -> Any: try: - value, prop_ts = self._contact_cache[jid][prop] + value, prop_ts = self._contact_cache[(account, jid)][prop] except KeyError: sql = f'''SELECT jid as "jid [jid]", {prop}, {prop}_ts - FROM contact WHERE jid = ?''' - row = self._con.execute(sql, (jid,)).fetchone() + FROM contact WHERE account = ? AND jid = ?''' + row = self._con.execute(sql, (account, jid)).fetchone() value = None if row is None else getattr(row, prop) prop_ts = 0 if row is None else getattr(row, f'{prop}_ts')
- self._contact_cache[jid][prop] = (value, prop_ts) + self._contact_cache[(account, jid)][prop] = (value, prop_ts) return value
else:
===================================== gajim/gtk/avatar.py ===================================== @@ -432,7 +432,7 @@ def get_muc_surface(self, if surface is not None: return surface
- avatar_sha = app.storage.cache.get_muc(jid, 'avatar') + avatar_sha = app.storage.cache.get_muc(account, jid, 'avatar') if avatar_sha is not None: surface = self.surface_from_filename(avatar_sha, size, scale) if surface is not None: @@ -442,7 +442,7 @@ def get_muc_surface(self,
# avatar_sha set, but image is missing # (e.g. avatar cache deleted) - app.storage.cache.set_muc(jid, 'avatar', None) + app.storage.cache.set_muc(account, jid, 'avatar', None)
client = app.get_client(account) contact = client.get_module('Contacts').get_bare_contact(jid)
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/8392372aafcd1166f799108e80ed39df8...