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));
}
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);
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);
avatar_storage.get_image.begin(id, (obj, res) => {
Pixbuf? avatar = avatar_storage.get_image.end(res);
if (avatar != null) {
received_avatar(avatar, jid, account);
}
});
}
}

View file

@ -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;
}

View file

@ -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<Jid>? 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);

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(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<Jid>? 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();
}

View file

@ -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);

View file

@ -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);
}
}