Remove avatars with missmatch between supposed and actual sha1 hash on load, make loading async

This commit is contained in:
fiaxh 2019-04-19 21:42:40 +02:00
parent cbe0ff2c1d
commit b6799e59bb
6 changed files with 108 additions and 60 deletions

View file

@ -46,29 +46,48 @@ public class AvatarManager : StreamInteractionModule, Object {
modules.add(new Xep.VCard.Module(avatar_storage)); 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)) { if (cached_pixbuf.has_key(hash)) {
return cached_pixbuf[hash]; return cached_pixbuf[hash];
} }
Pixbuf? image = avatar_storage.get_image(hash); Pixbuf? image = yield avatar_storage.get_image(hash);
if (image != null) { if (image != null) {
cached_pixbuf[hash] = image; cached_pixbuf[hash] = image;
} }
return 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; Jid jid_ = jid;
if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) { if (!stream_interactor.get_module(MucManager.IDENTITY).is_groupchat_occupant(jid, account)) {
jid_ = jid.bare_jid; jid_ = jid.bare_jid;
} }
string? user_avatars_id = user_avatars[jid_]; string? user_avatars_id = user_avatars[jid_];
if (user_avatars_id != null) { if (user_avatars_id != null) {
return get_avatar_by_hash(user_avatars_id); return user_avatars_id;
} }
string? vcard_avatars_id = vcard_avatars[jid_]; string? vcard_avatars_id = vcard_avatars[jid_];
if (vcard_avatars_id != null) { if (vcard_avatars_id != null) {
return get_avatar_by_hash(vcard_avatars_id); return vcard_avatars_id;
} }
return null; return null;
} }
@ -118,10 +137,12 @@ public class AvatarManager : StreamInteractionModule, Object {
user_avatars[jid] = id; user_avatars[jid] = id;
db.set_avatar_hash(jid, id, Source.USER_AVATARS); db.set_avatar_hash(jid, id, Source.USER_AVATARS);
} }
Pixbuf? avatar = avatar_storage.get_image(id); avatar_storage.get_image.begin(id, (obj, res) => {
if (avatar != null) { Pixbuf? avatar = avatar_storage.get_image.end(res);
received_avatar(avatar, jid, account); if (avatar != null) {
} received_avatar(avatar, jid, account);
}
});
} }
private void on_vcard_avatar_received(Account account, Jid jid, string id) { 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); db.set_avatar_hash(jid, id, Source.VCARD);
} }
} }
Pixbuf? avatar = avatar_storage.get_image(id); avatar_storage.get_image.begin(id, (obj, res) => {
if (avatar != null) { Pixbuf? avatar = avatar_storage.get_image.end(res);
received_avatar(avatar, jid, account); if (avatar != null) {
} received_avatar(avatar, jid, account);
}
});
} }
} }

View file

@ -28,9 +28,24 @@ public class AvatarStorage : Xep.PixbufStorage, Object {
return file.query_exists(); return file.query_exists();
} }
public Pixbuf? get_image(string id) { public async Pixbuf? get_image(string id) {
try { 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) { } catch (Error e) {
return null; return null;
} }

View file

@ -26,31 +26,31 @@ public class AvatarGenerator {
this.scale_factor = scale_factor; 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_; Jid? jid = jid_;
this.stream_interactor = stream_interactor; this.stream_interactor = stream_interactor;
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account); 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; 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); surface.set_device_scale(scale_factor, scale_factor);
return surface; return surface;
} }
public ImageSurface draw_message(StreamInteractor stream_interactor, Message message) { public async 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) { if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).has_avatar(message.account, message.real_jid)) {
return draw_jid(stream_interactor, message.real_jid, message.account); 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) { public async ImageSurface draw_conversation(StreamInteractor stream_interactor, Conversation conversation) {
return draw_jid(stream_interactor, conversation.counterpart, conversation.account); return yield draw_jid(stream_interactor, conversation.counterpart, conversation.account);
} }
public ImageSurface draw_account(StreamInteractor stream_interactor, Account account) { public async ImageSurface draw_account(StreamInteractor stream_interactor, Account account) {
return draw_jid(stream_interactor, account.bare_jid, account); return yield draw_jid(stream_interactor, account.bare_jid, account);
} }
public ImageSurface draw_text(string text) { public ImageSurface draw_text(string text) {
@ -76,23 +76,23 @@ public class AvatarGenerator {
return (int)Math.ceil(scale_factor/2.0); 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) { 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(draw_chat_tile(jid, account, width, height), 0, 0, width, height); 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); 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; ImageSurface surface;
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) { 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 { } else {
surface = draw_chat_tile(jid, account, width, height); surface = yield draw_chat_tile(jid, account, width, height);
} }
return surface; return surface;
} }
private ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) { private async ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) {
Pixbuf? pixbuf = stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid); Pixbuf? pixbuf = yield stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid);
if (pixbuf != null) { if (pixbuf != null) {
double desired_ratio = (double) width / height; double desired_ratio = (double) width / height;
double avatar_ratio = (double) pixbuf.width / pixbuf.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<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account); Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account);
if (stateless || occupants == null || occupants.size == 0) { 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++) { 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); 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; occupants[i] = real_jid;
} }
} }
Pixbuf pixbuf = initialize_pixbuf(width, height); Pixbuf pixbuf = initialize_pixbuf(width, height);
if (occupants.size == 1 || occupants.size == 2 || occupants.size == 3) { 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) { 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) { } 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) { } 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); 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);
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[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) { } 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); yield 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); 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);
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[2], account, width / 2 - get_right_border(), height / 2 - get_left_border(), 0, height / 2 + get_left_border());
if (occupants.size == 4) { 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) { } else if (occupants.size > 4) {
ImageSurface plus_surface = draw_colored_rectangle_text("555753", "+", width / 2 - get_left_border(), height / 2 - get_left_border()); 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); if (greyscale) plus_surface = convert_to_greyscale(plus_surface);

View file

@ -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(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated);
stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect(on_occupant_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 // Groupchat without avatar
Gee.List<Jid>? occupants; Gee.List<Jid>? occupants;
if (muc_manager.is_private_room(account, jid_)) { if (muc_manager.is_private_room(account, jid_)) {
@ -321,19 +321,27 @@ public class AvatarImage : Misc {
this.text_only = null; this.text_only = null;
this.gray = gray && allow_gray; this.gray = gray && allow_gray;
this.with_plus = with_plus; this.with_plus = with_plus;
this.current_jids = jids;
this.current_avatars = new Gdk.Pixbuf[jids.length]; set_jids_async.begin(jids);
for (int i = 0; i < current_jids.length; ++i) { }
Jid? real_jid = muc_manager.get_real_jid(current_jids[i], account);
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) { if (real_jid != null) {
current_avatars[i] = avatar_manager.get_avatar(account, real_jid); avatars[i] = yield avatar_manager.get_avatar(account, real_jid);
if (current_avatars[i] != null) { if (avatars[i] != null) {
current_jids[i] = real_jid; jids_[i] = real_jid;
continue; 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(); queue_draw();
} }

View file

@ -41,12 +41,12 @@ public class Notifications : Object {
} }
public void start() { 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_subscription_request.connect(notify_subscription_request);
stream_interactor.get_module(NotificationEvents.IDENTITY).notify_connection_error.connect(notify_connection_error); 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)) { if (!notifications.has_key(conversation)) {
notifications[conversation] = new Notification(""); notifications[conversation] = new Notification("");
notifications[conversation].set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); 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_title(display_name);
notifications[conversation].set_body(text); notifications[conversation].set_body(text);
try { 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) { } } catch (Error e) { }
window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]); window.get_application().send_notification(conversation.id.to_string(), notifications[conversation]);
active_conversation_ids.add(conversation.id.to_string()); active_conversation_ids.add(conversation.id.to_string());
window.urgency_hint = true; 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 notification = new Notification(_("Subscription request"));
notification.set_body(conversation.counterpart.to_string()); notification.set_body(conversation.counterpart.to_string());
try { 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) { } } catch (Error e) { }
notification.set_default_action_and_target_value("app.open-conversation", new Variant.int32(conversation.id)); 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); notification.add_button_with_target_value(_("Accept"), "app.accept-subscription", conversation.id);

View file

@ -4,6 +4,6 @@ namespace Xmpp.Xep {
public interface PixbufStorage : Object { public interface PixbufStorage : Object {
public abstract void store(string id, Bytes data); public abstract void store(string id, Bytes data);
public abstract bool has_image(string id); public abstract bool has_image(string id);
public abstract Pixbuf? get_image(string id); public abstract async Pixbuf? get_image(string id);
} }
} }