From b6799e59bb9cc2ea511b0f19aab88a83c244dda8 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Fri, 19 Apr 2019 21:42:40 +0200 Subject: [PATCH] Remove avatars with missmatch between supposed and actual sha1 hash on load, make loading async --- libdino/src/service/avatar_manager.vala | 49 +++++++++++----- libdino/src/service/avatar_storage.vala | 19 ++++++- main/src/ui/avatar_generator.vala | 60 ++++++++++---------- main/src/ui/avatar_image.vala | 26 ++++++--- main/src/ui/notifications.vala | 12 ++-- xmpp-vala/src/module/xep/pixbuf_storage.vala | 2 +- 6 files changed, 108 insertions(+), 60 deletions(-) diff --git a/libdino/src/service/avatar_manager.vala b/libdino/src/service/avatar_manager.vala index 9e75a9dd..9510389f 100644 --- a/libdino/src/service/avatar_manager.vala +++ b/libdino/src/service/avatar_manager.vala @@ -46,29 +46,48 @@ public class AvatarManager : StreamInteractionModule, Object { modules.add(new Xep.VCard.Module(avatar_storage)); } - private Pixbuf? get_avatar_by_hash(string hash) { + private async Pixbuf? get_avatar_by_hash(string hash) { if (cached_pixbuf.has_key(hash)) { return cached_pixbuf[hash]; } - Pixbuf? image = avatar_storage.get_image(hash); + Pixbuf? image = yield avatar_storage.get_image(hash); if (image != null) { cached_pixbuf[hash] = image; } return image; } - public Pixbuf? get_avatar(Account account, Jid jid) { + public bool has_avatar(Account account, Jid jid) { + string? hash = get_avatar_hash(account, jid); + if (hash != null) { + if (cached_pixbuf.has_key(hash)) { + return true; + } + return avatar_storage.has_image(hash); + } + return false; + } + + public async Pixbuf? get_avatar(Account account, Jid jid) { + string? hash = get_avatar_hash(account, jid); + if (hash != null) { + return yield get_avatar_by_hash(hash); + } + return null; + } + + private string? get_avatar_hash(Account account, Jid jid) { Jid jid_ = jid; if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) { jid_ = jid.bare_jid; } string? user_avatars_id = user_avatars[jid_]; if (user_avatars_id != null) { - return get_avatar_by_hash(user_avatars_id); + return user_avatars_id; } string? vcard_avatars_id = vcard_avatars[jid_]; if (vcard_avatars_id != null) { - return get_avatar_by_hash(vcard_avatars_id); + return vcard_avatars_id; } return null; } @@ -118,10 +137,12 @@ public class AvatarManager : StreamInteractionModule, Object { user_avatars[jid] = id; db.set_avatar_hash(jid, id, Source.USER_AVATARS); } - Pixbuf? avatar = avatar_storage.get_image(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) { @@ -131,10 +152,12 @@ public class AvatarManager : StreamInteractionModule, Object { db.set_avatar_hash(jid, id, Source.VCARD); } } - Pixbuf? avatar = avatar_storage.get_image(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); + } + }); } } diff --git a/libdino/src/service/avatar_storage.vala b/libdino/src/service/avatar_storage.vala index b924ca27..a307fe66 100644 --- a/libdino/src/service/avatar_storage.vala +++ b/libdino/src/service/avatar_storage.vala @@ -28,9 +28,24 @@ public class AvatarStorage : Xep.PixbufStorage, Object { return file.query_exists(); } - public Pixbuf? get_image(string id) { + public async Pixbuf? get_image(string id) { try { - return new Pixbuf.from_file(Path.build_filename(folder, id)); + File file = File.new_for_path(Path.build_filename(folder, id)); + FileInputStream stream = yield file.read_async(); + + uint8 fbuf[100]; + size_t size; + + Checksum checksum = new Checksum (ChecksumType.SHA1); + while ((size = yield stream.read_async(fbuf)) > 0) { + checksum.update(fbuf, size); + } + + if (checksum.get_string() != id) { + FileUtils.remove(file.get_path()); + } + stream.seek(0, SeekType.SET); + return yield new Pixbuf.from_stream_async(stream); } catch (Error e) { return null; } diff --git a/main/src/ui/avatar_generator.vala b/main/src/ui/avatar_generator.vala index b2138577..012dabe4 100644 --- a/main/src/ui/avatar_generator.vala +++ b/main/src/ui/avatar_generator.vala @@ -26,31 +26,31 @@ public class AvatarGenerator { this.scale_factor = scale_factor; } - public ImageSurface draw_jid(StreamInteractor stream_interactor, Jid jid_, Account account) { + public async ImageSurface draw_jid(StreamInteractor stream_interactor, Jid jid_, Account account) { Jid? jid = jid_; this.stream_interactor = stream_interactor; Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account); - if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, real_jid) != null) { + if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(account, real_jid)) { jid = real_jid; } - ImageSurface surface = crop_corners(draw_tile(jid, account, width * scale_factor, height * scale_factor), 3 * scale_factor); + ImageSurface surface = crop_corners(yield draw_tile(jid, account, width * scale_factor, height * scale_factor), 3 * scale_factor); surface.set_device_scale(scale_factor, scale_factor); return surface; } - public ImageSurface draw_message(StreamInteractor stream_interactor, Message message) { - if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(message.account, message.real_jid) != null) { - return draw_jid(stream_interactor, message.real_jid, message.account); + public async ImageSurface draw_message(StreamInteractor stream_interactor, Message message) { + if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(message.account, message.real_jid)) { + return yield draw_jid(stream_interactor, message.real_jid, message.account); } - return draw_jid(stream_interactor, message.from, message.account); + return yield draw_jid(stream_interactor, message.from, message.account); } - public ImageSurface draw_conversation(StreamInteractor stream_interactor, Conversation conversation) { - return draw_jid(stream_interactor, conversation.counterpart, conversation.account); + public async ImageSurface draw_conversation(StreamInteractor stream_interactor, Conversation conversation) { + return yield draw_jid(stream_interactor, conversation.counterpart, conversation.account); } - public ImageSurface draw_account(StreamInteractor stream_interactor, Account account) { - return draw_jid(stream_interactor, account.bare_jid, account); + public async ImageSurface draw_account(StreamInteractor stream_interactor, Account account) { + return yield draw_jid(stream_interactor, account.bare_jid, account); } public ImageSurface draw_text(string text) { @@ -76,23 +76,23 @@ public class AvatarGenerator { return (int)Math.ceil(scale_factor/2.0); } - private void add_tile_to_pixbuf(Pixbuf pixbuf, Jid jid, Account account, int width, int height, int x, int y) { - Pixbuf tile = pixbuf_get_from_surface(draw_chat_tile(jid, account, width, height), 0, 0, width, height); + private async void add_tile_to_pixbuf(Pixbuf pixbuf, Jid jid, Account account, int width, int height, int x, int y) { + Pixbuf tile = pixbuf_get_from_surface(yield draw_chat_tile(jid, account, width, height), 0, 0, width, height); tile.copy_area(0, 0, width, height, pixbuf, x, y); } - private ImageSurface draw_tile(Jid jid, Account account, int width, int height) { + private async ImageSurface draw_tile(Jid jid, Account account, int width, int height) { ImageSurface surface; if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) { - surface = draw_groupchat_tile(jid, account, width, height); + surface = yield draw_groupchat_tile(jid, account, width, height); } else { - surface = draw_chat_tile(jid, account, width, height); + surface = yield draw_chat_tile(jid, account, width, height); } return surface; } - private ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) { - Pixbuf? pixbuf = stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid); + private async ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) { + Pixbuf? pixbuf = yield stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid); if (pixbuf != null) { double desired_ratio = (double) width / height; double avatar_ratio = (double) pixbuf.width / pixbuf.height; @@ -117,35 +117,35 @@ public class AvatarGenerator { } } - private ImageSurface draw_groupchat_tile(Jid jid, Account account, int width, int height) { + private async ImageSurface draw_groupchat_tile(Jid jid, Account account, int width, int height) { Gee.List? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account); if (stateless || occupants == null || occupants.size == 0) { - return draw_chat_tile(jid, account, width, height); + return yield draw_chat_tile(jid, account, width, height); } for (int i = 0; i < occupants.size && i < 4; i++) { Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(occupants[i], account); - if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, real_jid) != null) { + if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(account, real_jid)) { occupants[i] = real_jid; } } Pixbuf pixbuf = initialize_pixbuf(width, height); if (occupants.size == 1 || occupants.size == 2 || occupants.size == 3) { - add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height, 0, 0); + yield add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height, 0, 0); if (occupants.size == 1) { - add_tile_to_pixbuf(pixbuf, account.bare_jid, account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0); + yield add_tile_to_pixbuf(pixbuf, account.bare_jid, account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0); } else if (occupants.size == 2) { - add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0); + yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height, width / 2 + get_left_border(), 0); } else if (occupants.size == 3) { - add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0); - add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border()); + yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0); + yield add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border()); } } else if (occupants.size >= 4) { - add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height / 2 - get_right_border(), 0, 0); - add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0); - add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_right_border(), height / 2 - get_left_border(), 0, height / 2 + get_left_border()); + yield add_tile_to_pixbuf(pixbuf, occupants[0], account, width / 2 - get_right_border(), height / 2 - get_right_border(), 0, 0); + yield add_tile_to_pixbuf(pixbuf, occupants[1], account, width / 2 - get_left_border(), height / 2 - get_right_border(), width / 2 + get_left_border(), 0); + yield add_tile_to_pixbuf(pixbuf, occupants[2], account, width / 2 - get_right_border(), height / 2 - get_left_border(), 0, height / 2 + get_left_border()); if (occupants.size == 4) { - add_tile_to_pixbuf(pixbuf, occupants[3], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border()); + yield add_tile_to_pixbuf(pixbuf, occupants[3], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border()); } else if (occupants.size > 4) { ImageSurface plus_surface = draw_colored_rectangle_text("555753", "+", width / 2 - get_left_border(), height / 2 - get_left_border()); if (greyscale) plus_surface = convert_to_greyscale(plus_surface); diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala index f6140c26..c052270a 100644 --- a/main/src/ui/avatar_image.vala +++ b/main/src/ui/avatar_image.vala @@ -208,7 +208,7 @@ public class AvatarImage : Misc { stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated); stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect(on_occupant_updated); } - if (muc_manager.is_groupchat(jid_, account) && avatar_manager.get_avatar(account, jid_) == null) { + if (muc_manager.is_groupchat(jid_, account) && !avatar_manager.has_avatar(account, jid_)) { // Groupchat without avatar Gee.List? occupants; if (muc_manager.is_private_room(account, jid_)) { @@ -321,19 +321,27 @@ public class AvatarImage : Misc { this.text_only = null; this.gray = gray && allow_gray; this.with_plus = with_plus; - this.current_jids = jids; - this.current_avatars = new Gdk.Pixbuf[jids.length]; - for (int i = 0; i < current_jids.length; ++i) { - Jid? real_jid = muc_manager.get_real_jid(current_jids[i], account); + + set_jids_async.begin(jids); + } + + public async void set_jids_async(Jid[] jids) { + Jid[] jids_ = jids; + Gdk.Pixbuf[] avatars = new Gdk.Pixbuf[jids.length]; + for (int i = 0; i < jids_.length; ++i) { + Jid? real_jid = muc_manager.get_real_jid(jids_[i], account); if (real_jid != null) { - current_avatars[i] = avatar_manager.get_avatar(account, real_jid); - if (current_avatars[i] != null) { - current_jids[i] = real_jid; + avatars[i] = yield avatar_manager.get_avatar(account, real_jid); + if (avatars[i] != null) { + jids_[i] = real_jid; continue; } } - current_avatars[i] = avatar_manager.get_avatar(account, current_jids[i]); + avatars[i] = yield avatar_manager.get_avatar(account, jids_[i]); } + this.current_avatars = avatars; + this.current_jids = jids_; + queue_draw(); } diff --git a/main/src/ui/notifications.vala b/main/src/ui/notifications.vala index 277a7a09..fe545154 100644 --- a/main/src/ui/notifications.vala +++ b/main/src/ui/notifications.vala @@ -41,12 +41,12 @@ public class Notifications : Object { } public void start() { - stream_interactor.get_module(NotificationEvents.IDENTITY).notify_content_item.connect(notify_content_item); + stream_interactor.get_module(NotificationEvents.IDENTITY).notify_content_item.connect((content_item, conversation) => notify_content_item.begin(content_item, conversation)); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_subscription_request.connect(notify_subscription_request); stream_interactor.get_module(NotificationEvents.IDENTITY).notify_connection_error.connect(notify_connection_error); } - private void notify_content_item(ContentItem content_item, Conversation conversation) { + private async void notify_content_item(ContentItem content_item, Conversation conversation) { if (!notifications.has_key(conversation)) { notifications[conversation] = new Notification(""); notifications[conversation].set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); @@ -77,18 +77,20 @@ public class Notifications : Object { notifications[conversation].set_title(display_name); notifications[conversation].set_body(text); try { - notifications[conversation].set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_conversation(stream_interactor, conversation))); + Cairo.ImageSurface conversation_avatar = yield (new AvatarGenerator(40, 40)).draw_conversation(stream_interactor, conversation); + notifications[conversation].set_icon(get_pixbuf_icon(conversation_avatar)); } catch (Error e) { } window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]); active_conversation_ids.add(conversation.id.to_string()); window.urgency_hint = true; } - private void notify_subscription_request(Conversation conversation) { + private async void notify_subscription_request(Conversation conversation) { Notification notification = new Notification(_("Subscription request")); notification.set_body(conversation.counterpart.to_string()); try { - notification.set_icon(get_pixbuf_icon((new AvatarGenerator(40, 40)).draw_jid(stream_interactor, conversation.counterpart, conversation.account))); + Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, conversation.counterpart, conversation.account); + notification.set_icon(get_pixbuf_icon(jid_avatar)); } catch (Error e) { } notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); notification.add_button_with_target_value(_("Accept"), "app.accept-subscription", conversation.id); diff --git a/xmpp-vala/src/module/xep/pixbuf_storage.vala b/xmpp-vala/src/module/xep/pixbuf_storage.vala index cdc227ea..550290cf 100644 --- a/xmpp-vala/src/module/xep/pixbuf_storage.vala +++ b/xmpp-vala/src/module/xep/pixbuf_storage.vala @@ -4,6 +4,6 @@ namespace Xmpp.Xep { public interface PixbufStorage : Object { public abstract void store(string id, Bytes data); public abstract bool has_image(string id); - public abstract Pixbuf? get_image(string id); + public abstract async Pixbuf? get_image(string id); } }