From 2eb72d5dad9be99dc110417144db2f8c4446bd53 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Tue, 10 Mar 2020 23:53:11 +0100 Subject: [PATCH] Fix+optimize contact-to-avatar storage and loading --- libdino/src/service/avatar_manager.vala | 67 ++++++++++++++----------- libdino/src/service/database.vala | 37 +++++--------- qlite/src/database.vala | 2 +- 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/libdino/src/service/avatar_manager.vala b/libdino/src/service/avatar_manager.vala index a47273ee..5bb6b8e3 100644 --- a/libdino/src/service/avatar_manager.vala +++ b/libdino/src/service/avatar_manager.vala @@ -1,5 +1,6 @@ using Gdk; using Gee; +using Qlite; using Xmpp; using Dino.Entities; @@ -120,7 +121,6 @@ public class AvatarManager : StreamInteractionModule, Object { XmppStream stream = stream_interactor.get_stream(account); if (stream != null) { stream.get_module(Xep.UserAvatars.Module.IDENTITY).publish_png(stream, buffer, pixbuf.width, pixbuf.height); - on_user_avatar_received(account, account.bare_jid, Base64.encode(buffer)); } } catch (Error e) { warning(e.message); @@ -129,52 +129,61 @@ public class AvatarManager : StreamInteractionModule, Object { private void on_account_added(Account account) { stream_interactor.module_manager.get_module(account, Xep.UserAvatars.Module.IDENTITY).received_avatar.connect((stream, jid, id) => - on_user_avatar_received(account, jid, id) + on_user_avatar_received.begin(account, jid, id) ); stream_interactor.module_manager.get_module(account, Xep.VCard.Module.IDENTITY).received_avatar.connect((stream, jid, id) => - on_vcard_avatar_received(account, jid, id) + on_vcard_avatar_received.begin(account, jid, id) ); - foreach (var entry in db.get_avatar_hashes(Source.USER_AVATARS).entries) { - on_user_avatar_received(account, entry.key, entry.value); + foreach (var entry in get_avatar_hashes(account, Source.USER_AVATARS).entries) { + user_avatars[entry.key] = entry.value; } - foreach (var entry in db.get_avatar_hashes(Source.VCARD).entries) { - // FIXME: remove. temporary to remove falsely saved avatars. - if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(entry.key, account)) { - db.avatar.delete().with(db.avatar.jid, "=", entry.key.to_string()).perform(); - continue; - } - - on_vcard_avatar_received(account, entry.key, entry.value); + foreach (var entry in get_avatar_hashes(account, Source.VCARD).entries) { + vcard_avatars[entry.key] = entry.value; } } - private void on_user_avatar_received(Account account, Jid jid, string id) { + private async void on_user_avatar_received(Account account, Jid jid, string id) { if (!user_avatars.has_key(jid) || user_avatars[jid] != id) { user_avatars[jid] = id; - db.set_avatar_hash(jid, id, Source.USER_AVATARS); + set_avatar_hash(account, jid, id, Source.USER_AVATARS); + } + Pixbuf? avatar = yield get_avatar_by_hash(id); + if (avatar != null) { + received_avatar(avatar, jid, account); } - avatar_storage.get_image.begin(id, (obj, res) => { - Pixbuf? avatar = avatar_storage.get_image.end(res); - if (avatar != null) { - received_avatar(avatar, jid, account); - } - }); } - private void on_vcard_avatar_received(Account account, Jid jid, string id) { + private async void on_vcard_avatar_received(Account account, Jid jid, string id) { if (!vcard_avatars.has_key(jid) || vcard_avatars[jid] != id) { vcard_avatars[jid] = id; if (!jid.is_full()) { // don't save MUC occupant avatars - db.set_avatar_hash(jid, id, Source.VCARD); + set_avatar_hash(account, jid, id, Source.VCARD); } } - avatar_storage.get_image.begin(id, (obj, res) => { - Pixbuf? avatar = avatar_storage.get_image.end(res); - if (avatar != null) { - received_avatar(avatar, jid, account); - } - }); + Pixbuf? avatar = yield get_avatar_by_hash(id); + if (avatar != null) { + received_avatar(avatar, jid, account); + } + } + + public void set_avatar_hash(Account account, Jid jid, string hash, int type) { + db.avatar.insert() + .value(db.avatar.jid_id, db.get_jid_id(jid)) + .value(db.avatar.account_id, account.id) + .value(db.avatar.hash, hash) + .value(db.avatar.type_, type) + .perform(); + } + + public HashMap get_avatar_hashes(Account account, int type) { + HashMap ret = new HashMap(Jid.hash_func, Jid.equals_func); + foreach (Row row in db.avatar.select({db.avatar.jid_id, db.avatar.hash}) + .with(db.avatar.type_, "=", type) + .with(db.avatar.account_id, "=", account.id)) { + ret[db.get_jid_by_id(row[db.avatar.jid_id])] = row[db.avatar.hash]; + } + return ret; } } diff --git a/libdino/src/service/database.vala b/libdino/src/service/database.vala index 238d8f46..34bbea7a 100644 --- a/libdino/src/service/database.vala +++ b/libdino/src/service/database.vala @@ -7,7 +7,7 @@ using Dino.Entities; namespace Dino { public class Database : Qlite.Database { - private const int VERSION = 11; + private const int VERSION = 12; public class AccountTable : Table { public Column id = new Column.Integer("id") { primary_key = true, auto_increment = true }; @@ -150,13 +150,15 @@ public class Database : Qlite.Database { } public class AvatarTable : Table { - public Column jid = new Column.Text("jid"); + public Column jid_id = new Column.Integer("jid_id"); + public Column account_id = new Column.Integer("account_id"); public Column hash = new Column.Text("hash"); public Column type_ = new Column.Integer("type"); internal AvatarTable(Database db) { - base(db, "avatar"); - init({jid, hash, type_}); + base(db, "contact_avatar"); + init({jid_id, account_id, hash, type_}); + unique({jid_id, account_id}, "REPLACE"); } } @@ -309,6 +311,13 @@ public class Database : Qlite.Database { error("Failed to upgrade to database version 11: %s", e.message); } } + if (oldVersion < 12) { + try { + exec("delete from avatar"); + } catch (Error e) { + error("Failed to upgrade to database version 12: %s", e.message); + } + } } public ArrayList get_accounts() { @@ -424,26 +433,6 @@ public class Database : Qlite.Database { return ret; } - public void set_avatar_hash(Jid jid, string hash, int type) { - avatar.insert().or("REPLACE") - .value(avatar.jid, jid.to_string()) - .value(avatar.hash, hash) - .value(avatar.type_, type) - .perform(); - } - - public HashMap get_avatar_hashes(int type) { - HashMap ret = new HashMap(Jid.hash_func, Jid.equals_func); - foreach (Row row in avatar.select({avatar.jid, avatar.hash}).with(avatar.type_, "=", type)) { - try { - ret[new Jid(row[avatar.jid])] = row[avatar.hash]; - } catch (InvalidJidError e) { - warning("Ignoring avatar of invalid Jid: %s", e.message); - } - } - return ret; - } - public void add_entity_features(string entity, Gee.List features) { foreach (string feature in features) { entity_feature.insert() diff --git a/qlite/src/database.vala b/qlite/src/database.vala index f58b76b6..1e39d227 100644 --- a/qlite/src/database.vala +++ b/qlite/src/database.vala @@ -29,8 +29,8 @@ public class Database { error(@"SQLite error: %d - %s", db.errcode(), db.errmsg()); } this.tables = tables; - start_migration(); if (debug) db.trace((message) => print(@"Qlite trace: $message\n")); + start_migration(); } public void ensure_init() {