From d77d315eaf5658e93cf7384cc7f1ebf7a86bd87c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 25 Oct 2022 08:12:36 +0200 Subject: Matrix: apply user display name and avatar update by timestamp --- src/plugins/Matrix.cpp | 177 ++++++++++++++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 67 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 14f49bf..7715a6b 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -116,15 +116,30 @@ namespace QuickMedia { return colors[color_hash_code(user_id) % num_colors]; } + bool TimestampedDisplayData::set_data_if_newer(std::string new_data, time_t new_timestamp) { + if(new_timestamp == 0) { + data = std::move(new_data); + return true; + } + + if(new_timestamp < timestamp) + return false; + + data = std::move(new_data); + timestamp = new_timestamp; + return true; + } + UserInfo::UserInfo(RoomData *room, std::string user_id) : room(room), display_name_color(user_id_to_color(user_id)), user_id(user_id) { - display_name = user_id; + display_name.set_data_if_newer(user_id, 0); } - UserInfo::UserInfo(RoomData *room, std::string user_id, std::string display_name, std::string avatar_url) : - room(room), display_name_color(user_id_to_color(user_id)), user_id(std::move(user_id)), display_name(std::move(display_name)), avatar_url(std::move(avatar_url)) { - + UserInfo::UserInfo(RoomData *room, std::string _user_id, std::string _display_name, std::string _avatar_url, time_t update_timestamp_ms) : + room(room), display_name_color(user_id_to_color(user_id)), user_id(std::move(_user_id)) { + display_name.set_data_if_newer(std::move(_display_name), update_timestamp_ms); + avatar_url.set_data_if_newer(std::move(_avatar_url), update_timestamp_ms); } // TODO: Remove this when images are embedded inside the text instead of using the same space as the author @@ -161,24 +176,27 @@ namespace QuickMedia { std::string RoomData::get_user_display_name(const std::shared_ptr &user) { std::lock_guard lock(user_mutex); - return user->display_name; + return user->display_name.data; } std::string RoomData::get_user_avatar_url(const std::shared_ptr &user) { std::lock_guard lock(user_mutex); - return user->avatar_url; + return user->avatar_url.data; } - void RoomData::set_user_display_name(std::shared_ptr &user, std::string display_name) { + bool RoomData::set_user_display_name(std::shared_ptr &user, std::string display_name, time_t update_timestamp_ms) { std::lock_guard lock(user_mutex); - user->display_name = std::move(display_name); - if(user->display_name.empty()) - user->display_name = user->user_id; + if(display_name.empty()) { + user->display_name.data = user->user_id; + return true; + } else { + return user->display_name.set_data_if_newer(std::move(display_name), update_timestamp_ms); + } } - void RoomData::set_user_avatar_url(std::shared_ptr &user, std::string avatar_url) { + bool RoomData::set_user_avatar_url(std::shared_ptr &user, std::string avatar_url, time_t update_timestamp_ms) { std::lock_guard lock(user_mutex); - user->avatar_url = std::move(avatar_url); + return user->avatar_url.set_data_if_newer(std::move(avatar_url), update_timestamp_ms); } size_t RoomData::prepend_messages_reverse(const Messages &new_messages) { @@ -283,42 +301,42 @@ namespace QuickMedia { bool RoomData::has_name() { std::lock_guard lock(room_mutex); - return !name.empty(); + return !name.data.empty(); } - void RoomData::set_name(const std::string &new_name) { + bool RoomData::set_name(const std::string &new_name, time_t update_timestamp_ms) { std::lock_guard lock(room_mutex); - name = new_name; + return name.set_data_if_newer(new_name, update_timestamp_ms); } std::string RoomData::get_name() { std::lock_guard lock(room_mutex); - return name; + return name.data; } - void RoomData::set_topic(const std::string &new_topic) { + bool RoomData::set_topic(const std::string &new_topic, time_t update_timestamp_ms) { std::lock_guard lock(room_mutex); - topic = new_topic; + return topic.set_data_if_newer(new_topic, update_timestamp_ms); } std::string RoomData::get_topic() { std::lock_guard lock(room_mutex); - return topic; + return topic.data; } bool RoomData::has_avatar_url() { std::lock_guard lock(room_mutex); - return !avatar_url.empty(); + return !avatar_url.data.empty(); } - void RoomData::set_avatar_url(const std::string &new_avatar_url) { + bool RoomData::set_avatar_url(const std::string &new_avatar_url, time_t update_timestamp_ms) { std::lock_guard lock(room_mutex); - avatar_url = new_avatar_url; + return avatar_url.set_data_if_newer(new_avatar_url, update_timestamp_ms); } std::string RoomData::get_avatar_url() { std::lock_guard lock(room_mutex); - return avatar_url; + return avatar_url.data; } void RoomData::set_pinned_events(std::vector new_pinned_events) { @@ -1507,8 +1525,8 @@ namespace QuickMedia { return PluginResult::ERR; const rapidjson::Value &state_json = GetMember(json_root, "state"); - events_add_user_info(state_json, room); - //events_set_room_info(state_json, room_data); + events_add_user_info(state_json, room, 0); + //events_set_room_info(state_json, room_data, 0); const rapidjson::Value &chunk_json = GetMember(json_root, "chunk"); if(chunk_json.IsArray()) { @@ -1742,8 +1760,8 @@ namespace QuickMedia { const rapidjson::Value &state_json = GetMember(it.value, "state"); if(state_json.IsObject()) { const rapidjson::Value &events_json = GetMember(state_json, "events"); - events_add_user_info(events_json, room); - events_set_room_info(events_json, room); + events_add_user_info(events_json, room, 0); + events_set_room_info(events_json, room, 0); events_add_pinned_events(events_json, room); } @@ -1770,8 +1788,8 @@ namespace QuickMedia { } const rapidjson::Value &events_json = GetMember(timeline_json, "events"); - events_add_user_info(events_json, room); - events_set_room_info(events_json, room); + events_add_user_info(events_json, room, 0); + events_set_room_info(events_json, room, 0); set_room_info_to_users_if_empty(room, my_user_id); if(account_data_json.IsObject()) { @@ -1841,7 +1859,7 @@ namespace QuickMedia { return PluginResult::OK; } - void Matrix::events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data) { + void Matrix::events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data, int64_t timestamp) { if(!events_json.IsArray()) return; @@ -1865,7 +1883,14 @@ namespace QuickMedia { if(!content_json.IsObject()) continue; - parse_user_info(content_json, sender_json->GetString(), room_data); + int64_t item_timestamp = timestamp; + if(item_timestamp == 0) { + const rapidjson::Value &origin_server_ts = GetMember(event_item_json, "origin_server_ts"); + if(origin_server_ts.IsInt64()) + item_timestamp = origin_server_ts.GetInt64(); + } + + parse_user_info(content_json, sender_json->GetString(), room_data, item_timestamp); } } @@ -1890,7 +1915,7 @@ namespace QuickMedia { return homeserver + "/_matrix/media/r0/thumbnail/" + mxc_id + "?width=" + size + "&height=" + size + "&method=crop"; } - std::shared_ptr Matrix::parse_user_info(const rapidjson::Value &json, const std::string &user_id, RoomData *room_data) { + std::shared_ptr Matrix::parse_user_info(const rapidjson::Value &json, const std::string &user_id, RoomData *room_data, int64_t timestamp) { assert(json.IsObject()); std::string avatar_url_str; const rapidjson::Value &avatar_url_json = GetMember(json, "avatar_url"); @@ -1908,18 +1933,26 @@ namespace QuickMedia { //room_data->add_user(user_info); bool is_new_user; auto user_info = get_user_by_id(room_data, user_id, &is_new_user); - room_data->set_user_display_name(user_info, display_name); - room_data->set_user_avatar_url(user_info, avatar_url); + bool update_display_name = room_data->set_user_display_name(user_info, display_name, timestamp); + bool update_avatar_url = room_data->set_user_avatar_url(user_info, avatar_url, timestamp); MatrixEventUserInfo event_user_info; event_user_info.user_id = user_id; - event_user_info.display_name = display_name; - event_user_info.avatar_url = avatar_url; + event_user_info.display_name = std::move(display_name); + event_user_info.avatar_url = std::move(avatar_url); - if(is_new_user) { - trigger_event(room_data, MatrixEventType::ADD_USER, std::move(event_user_info)); - } else { - trigger_event(room_data, MatrixEventType::USER_INFO, std::move(event_user_info)); + if(!update_display_name) + event_user_info.display_name = std::nullopt; + + if(!update_avatar_url) + event_user_info.display_name = std::nullopt; + + if(update_display_name || update_avatar_url) { + if(is_new_user) { + trigger_event(room_data, MatrixEventType::ADD_USER, std::move(event_user_info)); + } else { + trigger_event(room_data, MatrixEventType::USER_INFO, std::move(event_user_info)); + } } return user_info; @@ -2335,6 +2368,7 @@ namespace QuickMedia { std::optional new_display_name; std::optional new_avatar_url; + bool update_user_display_info = false; if(prev_membership_json.IsString() && strcmp(prev_membership_json.GetString(), "leave") == 0) { body = user_display_name + " joined the room"; @@ -2347,27 +2381,27 @@ namespace QuickMedia { prev_displayname_str = sender_json_str; body = extract_first_line_remove_newline_elipses(prev_displayname_str, AUTHOR_MAX_LENGTH) + " changed his display name to " + extract_first_line_remove_newline_elipses(new_displayname_str, AUTHOR_MAX_LENGTH); new_display_name = new_displayname_str; - room_data->set_user_display_name(user, std::move(new_displayname_str)); + update_user_display_info = room_data->set_user_display_name(user, std::move(new_displayname_str), timestamp); } else if((!new_displayname_json.IsString() || new_displayname_json.GetStringLength() == 0) && prev_displayname_json.IsString()) { body = user_display_name + " removed his display name"; new_display_name = ""; - room_data->set_user_display_name(user, ""); + update_user_display_info = room_data->set_user_display_name(user, "", timestamp); } else if(new_avatar_url_json.IsString() && new_avatar_url_json.GetStringLength() > 0 && (!prev_avatar_url_json.IsString() || strcmp(new_avatar_url_json.GetString(), prev_avatar_url_json.GetString()) != 0)) { body = user_display_name + " changed his profile picture"; std::string new_avatar_url_str = thumbnail_url_extract_media_id(new_avatar_url_json.GetString()); if(!new_avatar_url_str.empty()) new_avatar_url_str = get_thumbnail_url(homeserver, new_avatar_url_str); // TODO: Remove the constant strings around to reduce memory usage (6.3mb) new_avatar_url = new_avatar_url_str; - room_data->set_user_avatar_url(user, std::move(new_avatar_url_str)); + update_user_display_info = room_data->set_user_avatar_url(user, std::move(new_avatar_url_str), timestamp); } else if((!new_avatar_url_json.IsString() || new_avatar_url_json.GetStringLength() == 0) && prev_avatar_url_json.IsString()) { body = user_display_name + " removed his profile picture"; new_avatar_url = ""; - room_data->set_user_avatar_url(user, ""); + update_user_display_info = room_data->set_user_avatar_url(user, "", timestamp); } else { body = user_display_name + " joined the room"; } - if(new_display_name || new_avatar_url) { + if(update_user_display_info) { MatrixEventUserInfo user_info; user_info.user_id = user->user_id; user_info.display_name = std::move(new_display_name); @@ -2599,7 +2633,7 @@ namespace QuickMedia { return result; } - void Matrix::events_set_room_info(const rapidjson::Value &events_json, RoomData *room_data) { + void Matrix::events_set_room_info(const rapidjson::Value &events_json, RoomData *room_data, int64_t timestamp) { if(!events_json.IsArray()) return; @@ -2611,6 +2645,13 @@ namespace QuickMedia { if(!type_json.IsString()) continue; + int64_t item_timestamp = timestamp; + if(item_timestamp == 0) { + const rapidjson::Value &origin_server_ts = GetMember(event_item_json, "origin_server_ts"); + if(origin_server_ts.IsInt64()) + item_timestamp = origin_server_ts.GetInt64(); + } + if(strcmp(type_json.GetString(), "m.room.name") == 0) { const rapidjson::Value &content_json = GetMember(event_item_json, "content"); if(!content_json.IsObject()) @@ -2620,7 +2661,7 @@ namespace QuickMedia { if(!name_json.IsString()) continue; - room_data->set_name(name_json.GetString()); + room_data->set_name(name_json.GetString(), item_timestamp); // TODO: Update room name in gui room_data->name_is_fallback = false; } else if(strcmp(type_json.GetString(), "m.room.avatar") == 0) { const rapidjson::Value &content_json = GetMember(event_item_json, "content"); @@ -2631,7 +2672,7 @@ namespace QuickMedia { if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0) continue; - room_data->set_avatar_url(get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(url_json.GetString()))); + room_data->set_avatar_url(get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(url_json.GetString())), item_timestamp); // TODO: Update avatar url in gui room_data->avatar_is_fallback = false; } else if(strcmp(type_json.GetString(), "m.room.topic") == 0) { const rapidjson::Value &content_json = GetMember(event_item_json, "content"); @@ -2642,7 +2683,7 @@ namespace QuickMedia { if(!topic_json.IsString()) continue; - room_data->set_topic(topic_json.GetString()); + room_data->set_topic(topic_json.GetString(), item_timestamp); // TODO: Update topic in gui } } } @@ -2656,7 +2697,7 @@ namespace QuickMedia { users_excluding_me = room->get_users_excluding_me(my_user_id); if(!has_room_name) { - room->set_name(combine_user_display_names_for_room_name(users_excluding_me, room_creator_user_id)); + room->set_name(combine_user_display_names_for_room_name(users_excluding_me, room_creator_user_id), 0); // TODO: Update in gui room->name_is_fallback = true; } @@ -2664,10 +2705,10 @@ namespace QuickMedia { if(users_excluding_me.empty()) { auto user = get_user_by_id(room, room_creator_user_id); if(user) - room->set_avatar_url(room->get_user_avatar_url(user)); + room->set_avatar_url(room->get_user_avatar_url(user), 0); // TODO: Update in gui } else { // TODO: If there are multiple users, then we want to use some other type of avatar, not the first users avatar - room->set_avatar_url(room->get_user_avatar_url(users_excluding_me.front())); + room->set_avatar_url(room->get_user_avatar_url(users_excluding_me.front()), 0); // TODO: Update in gui } room->avatar_is_fallback = true; } @@ -2818,6 +2859,8 @@ namespace QuickMedia { const rapidjson::Value &membership_json = GetMember(content_json, "membership"); if(membership_json.IsString() && strcmp(membership_json.GetString(), "invite") == 0) { + const int64_t timestamp = timestamp_json.GetInt64(); + // TODO: Check this this room should be saved in the rooms list, which might be needed if the server doesn't give a non-invite events // for the same data (user display name update, etc) Invite invite; @@ -2825,8 +2868,8 @@ namespace QuickMedia { RoomData *room = invite_room.get(); invite_rooms.push_back(std::move(invite_room)); - events_add_user_info(events_json, room); - events_set_room_info(events_json, room); + events_add_user_info(events_json, room, timestamp); + events_set_room_info(events_json, room, timestamp); std::string sender_json_str(sender_json.GetString(), sender_json.GetStringLength()); auto invited_by = get_user_by_id(room, sender_json_str); @@ -2836,7 +2879,7 @@ namespace QuickMedia { invite.room_name = room->get_name(); invite.room_avatar_url = room->get_avatar_url(); invite.invited_by = invited_by; - invite.timestamp = timestamp_json.GetInt64(); + invite.timestamp = timestamp; invite.new_invite = !sync_is_cache; std::string room_id_str(room_id.GetString(), room_id.GetStringLength()); @@ -2934,7 +2977,7 @@ namespace QuickMedia { PluginResult Matrix::get_previous_room_messages(RoomData *room_data, bool latest_messages, size_t &num_new_messages, bool *reached_end) { num_new_messages = 0; std::string from = room_data->get_prev_batch(); - if(from.empty() || latest_messages) + if(from.empty() || latest_messages) // TODO: Remove. In v1.3 (/v3/) from can be empty from = "END"; rapidjson::Document request_data(rapidjson::kObjectType); @@ -2962,8 +3005,8 @@ namespace QuickMedia { const rapidjson::Value &state_json = GetMember(json_root, "state"); // TODO: Remove? - events_add_user_info(state_json, room_data); - //events_set_room_info(state_json, room_data); + events_add_user_info(state_json, room_data, 0); + //events_set_room_info(state_json, room_data, 0); const rapidjson::Value &chunk_json = GetMember(json_root, "chunk"); num_new_messages = events_add_messages(chunk_json, room_data, MessageDirection::BEFORE, false); @@ -3574,9 +3617,9 @@ namespace QuickMedia { return nullptr; } - // TODO: Do this? what about state apply order? + // TODO: Do this? //const rapidjson::Value &state_json = GetMember(json_root, "state"); - //events_add_user_info(state_json, room); + //events_add_user_info(state_json, room, 0); std::shared_ptr new_message = parse_message_event(json_root, room); room->fetched_messages_by_event_id.insert(std::make_pair(event_id, new_message)); @@ -3622,9 +3665,9 @@ namespace QuickMedia { } } - // TODO: Do this? what about state apply order? + // TODO: Do this? //const rapidjson::Value &state_json = GetMember(json_root, "state"); - //events_add_user_info(state_json, room); + //events_add_user_info(state_json, room, 0); const rapidjson::Value &start_json = GetMember(json_root, "start"); const rapidjson::Value &end_json = GetMember(json_root, "end"); @@ -4261,8 +4304,8 @@ namespace QuickMedia { if(!room) { auto new_room = std::make_unique(); new_room->id = room_id; - new_room->set_name(invite_it->second.room_name); - new_room->set_avatar_url(invite_it->second.room_avatar_url); + new_room->set_name(invite_it->second.room_name, invite_it->second.timestamp); + new_room->set_avatar_url(invite_it->second.room_avatar_url, invite_it->second.timestamp); room = new_room.get(); add_room(std::move(new_room)); @@ -4706,8 +4749,8 @@ namespace QuickMedia { avatar_url = std::string(avatar_url_json.GetString(), avatar_url_json.GetStringLength()); if(!avatar_url.empty()) avatar_url = get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(avatar_url)); // TODO: Remove the constant strings around to reduce memory usage (6.3mb) - room->set_user_avatar_url(user, avatar_url); - room->set_user_display_name(user, display_name); + room->set_user_avatar_url(user, avatar_url, 0); + room->set_user_display_name(user, display_name, 0); MatrixEventUserInfo user_info; user_info.user_id = user_id; @@ -4740,7 +4783,7 @@ namespace QuickMedia { if(!chunk_json.IsArray()) return; - events_add_user_info(chunk_json, room); + events_add_user_info(chunk_json, room, 0); #endif } -- cgit v1.2.3