From 053ffc2ea6cf22f2b4d1ab37805f57c48d114871 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 18 Nov 2020 04:46:54 +0100 Subject: Matrix: attempt fix double messages for sent messages with construct, missing displayname/avatars and invite to join modifying the wrong user --- plugins/Matrix.hpp | 2 +- src/QuickMedia.cpp | 59 ++++++++++++++++++++++++++++---------------------- src/plugins/Matrix.cpp | 54 ++++++++++++++++++++++++++++++++------------- 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 4514b4c..e60889f 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -512,7 +512,7 @@ namespace QuickMedia { std::vector> rooms; std::unordered_map room_data_by_id; // value is an index into |rooms| std::recursive_mutex room_data_mutex; - std::string user_id; + std::string my_user_id; std::string access_token; std::string homeserver; std::optional upload_limit; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 71ba8d2..f66d419 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3364,7 +3364,8 @@ namespace QuickMedia { std::string event_id; }; - std::vector unresolved_provisional_messages; // |event_id| is always empty in this. Use |message->event_id| instead + // This is needed to keep the message shared ptr alive. TODO: Remove this shit, maybe even use raw pointers. + std::unordered_map sent_messages; // |event_id| is always empty in this. Use |message->event_id| instead std::optional provisional_message; MessageQueue provisional_message_queue; MessageQueue> post_task_queue; @@ -3378,22 +3379,21 @@ namespace QuickMedia { }; std::thread post_thread(post_thread_handler); - auto resolve_provisional_messages = [&unresolved_provisional_messages](Messages &messages) { - if(messages.empty() || unresolved_provisional_messages.empty()) - return; + auto filter_my_messages = [&me](Messages &messages) { + for(auto it = messages.begin(); it != messages.end();) { + if((*it)->user == me) + it = messages.erase(it); + else + ++it; + } + }; - for(auto it = unresolved_provisional_messages.begin(); it != unresolved_provisional_messages.end();) { - auto find_it = std::find_if(messages.cbegin(), messages.cend(), [&it](const std::shared_ptr &message) { - return message->event_id == it->message->event_id; - }); - if(find_it != messages.end()) { - it->body_item->set_description_color(sf::Color::White); - it->body_item->userdata = find_it->get(); // This is ok because the message is added to |all_messages| - it = unresolved_provisional_messages.erase(it); - messages.erase(find_it); - } else { + auto filter_sent_messages = [&sent_messages](Messages &messages) { + for(auto it = messages.begin(); it != messages.end();) { + if(sent_messages.find((*it)->event_id) != sent_messages.end()) + it = messages.erase(it); + else ++it; - } } }; @@ -3414,7 +3414,7 @@ namespace QuickMedia { tabs[MESSAGES_TAB_INDEX].body->select_last_item(); } }; - + chat_input.on_submit_callback = [this, &tabs, &me, &chat_input, &selected_tab, ¤t_room, &new_page, &chat_state, ¤tly_operating_on_item, &post_task_queue, &unreferenced_events, &find_body_item_by_event_id](std::string text) mutable { if(!current_room) return false; @@ -3509,14 +3509,17 @@ namespace QuickMedia { void *related_to_message = currently_operating_on_item->userdata; message->related_event_type = RelatedEventType::EDIT; message->related_event_id = static_cast(related_to_message)->event_id; - auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id); + size_t body_item_index = 0; + auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id, &body_item_index); if(body_item) { - body_item->set_description(text); - body_item->set_description_color(provisional_message_color); - unreferenced_events.push_back(message); - post_task_queue.push([this, ¤t_room, text, related_to_message, message]() { + auto body_item_shared_ptr = tabs[MESSAGES_TAB_INDEX].body->items[body_item_index]; + body_item_shared_ptr->set_description(text); + body_item_shared_ptr->set_description_color(provisional_message_color); + //unreferenced_events.push_back(message); + post_task_queue.push([this, ¤t_room, text, related_to_message, message, body_item_shared_ptr]() { ProvisionalMessage provisional_message; provisional_message.message = message; + provisional_message.body_item = body_item_shared_ptr; if(matrix->post_edit(current_room, text, related_to_message, provisional_message.event_id) != PluginResult::OK) fprintf(stderr, "Failed to post matrix edit\n"); return provisional_message; @@ -3900,7 +3903,7 @@ namespace QuickMedia { } }; - auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &provisional_message_queue, &post_thread, &tabs]() { + auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &provisional_message_queue, &fetched_messages_set, &sent_messages, &post_thread, &tabs]() { set_read_marker_future.cancel(); fetch_message_future.cancel(); typing_state_queue.close(); @@ -3914,6 +3917,8 @@ namespace QuickMedia { post_thread.join(); } provisional_message_queue.clear(); + fetched_messages_set.clear(); + sent_messages.clear(); //unreferenced_event_by_room.clear(); @@ -4327,7 +4332,8 @@ namespace QuickMedia { if(!provisional_message->event_id.empty()) { provisional_message->message->event_id = std::move(provisional_message->event_id); - unresolved_provisional_messages.push_back(provisional_message.value()); + provisional_message->body_item->set_description_color(sf::Color::White); + sent_messages[provisional_message->message->event_id] = std::move(provisional_message.value()); } else if(provisional_message->body_item) { provisional_message->body_item->set_description("Failed to send: " + provisional_message->body_item->get_description()); provisional_message->body_item->set_description_color(sf::Color::Red); @@ -4340,7 +4346,7 @@ namespace QuickMedia { matrix->get_room_sync_data(current_room, sync_data); if(!sync_data.messages.empty()) { all_messages.insert(all_messages.end(), sync_data.messages.begin(), sync_data.messages.end()); - resolve_provisional_messages(sync_data.messages); + filter_my_messages(sync_data.messages); filter_existing_messages(sync_data.messages); } add_new_messages_to_current_room(sync_data.messages); @@ -4358,6 +4364,7 @@ namespace QuickMedia { all_messages.insert(all_messages.end(), new_messages.begin(), new_messages.end()); if(new_messages.empty()) fetched_enough_messages = true; + filter_sent_messages(new_messages); filter_existing_messages(new_messages); fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_messages.size()); bool move_to_bottom = false; @@ -4603,8 +4610,8 @@ namespace QuickMedia { fetched_messages_set.insert(message->event_id); } all_messages.insert(all_messages.end(), all_messages_new.begin(), all_messages_new.end()); - auto me = matrix->get_me(current_room); - resolve_provisional_messages(all_messages_new); + me = matrix->get_me(current_room); + filter_sent_messages(all_messages_new); add_new_messages_to_current_room(all_messages_new); modify_related_messages_in_current_room(all_messages_new); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index ee61c23..9998b48 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -101,7 +101,7 @@ namespace QuickMedia { UserInfo::UserInfo(RoomData *room, std::string user_id) : room(room), display_name_color(user_id_to_color(user_id)), user_id(user_id), resolve_state(UserResolveState::NOT_RESOLVED) { - display_name = std::move(user_id); + display_name = user_id; } UserInfo::UserInfo(RoomData *room, std::string user_id, std::string display_name, std::string avatar_url) : @@ -1368,7 +1368,6 @@ namespace QuickMedia { room->set_prev_batch(prev_batch_json.GetString()); } - // TODO: Use /_matrix/client/r0/notifications ? or remove this and always look for displayname/user_id in messages bool has_unread_notifications = false; const rapidjson::Value &unread_notification_json = GetMember(it.value, "unread_notifications"); if(unread_notification_json.IsObject() && !is_additional_messages_sync) { @@ -1382,7 +1381,7 @@ namespace QuickMedia { const rapidjson::Value &events_json = GetMember(timeline_json, "events"); events_add_user_info(events_json, room); events_set_room_name(events_json, room); - set_room_name_to_users_if_empty(room, user_id); + set_room_name_to_users_if_empty(room, my_user_id); if(account_data_json.IsObject()) { const rapidjson::Value &events_json = GetMember(account_data_json, "events"); @@ -1397,7 +1396,7 @@ namespace QuickMedia { if(!is_additional_messages_sync) events_add_pinned_events(events_json, room); } else { - set_room_name_to_users_if_empty(room, user_id); + set_room_name_to_users_if_empty(room, my_user_id); if(account_data_json.IsObject()) { const rapidjson::Value &events_json = GetMember(account_data_json, "events"); auto me = get_me(room); @@ -1784,8 +1783,9 @@ namespace QuickMedia { if(strcmp(membership_json.GetString(), "join") == 0) { const rapidjson::Value &unsigned_json = GetMember(event_item_json, "unsigned"); if(unsigned_json.IsObject()) { + const rapidjson::Value &prev_sender = GetMember(unsigned_json, "prev_sender"); const rapidjson::Value &prev_content_json = GetMember(unsigned_json, "prev_content"); - if(prev_content_json.IsObject()) { + if(prev_content_json.IsObject() && (!prev_sender.IsString() || strcmp(prev_sender.GetString(), user->user_id.c_str()) == 0)) { const rapidjson::Value &prev_displayname_json = GetMember(prev_content_json, "displayname"); const rapidjson::Value &prev_avatar_url_json = GetMember(prev_content_json, "avatar_url"); const rapidjson::Value &new_displayname_json = GetMember(*content_json, "displayname"); @@ -2003,7 +2003,7 @@ namespace QuickMedia { std::vector> users_excluding_me; if(!has_room_name || !has_room_avatar_url || room->name_is_fallback || room->avatar_is_fallback) - users_excluding_me = room->get_users_excluding_me(user_id); + 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)); @@ -2255,7 +2255,7 @@ namespace QuickMedia { std::string desc; LeaveType leave_type; if(strcmp(membership_json.GetString(), "leave") == 0) { - if(strcmp(sender_json.GetString(), user_id.c_str()) == 0) { + if(strcmp(sender_json.GetString(), my_user_id.c_str()) == 0) { leave_type = LeaveType::LEAVE; } else { leave_type = LeaveType::KICKED; @@ -2929,7 +2929,7 @@ namespace QuickMedia { // such as pantalaimon json_root.AddMember("homeserver", rapidjson::StringRef(homeserver.c_str()), request_data.GetAllocator()); - this->user_id = user_id_json.GetString(); + this->my_user_id = user_id_json.GetString(); this->access_token = access_token_json.GetString(); this->homeserver = homeserver; @@ -2964,7 +2964,7 @@ namespace QuickMedia { // Make sure all fields are reset here! rooms.clear(); room_data_by_id.clear(); - user_id.clear(); + my_user_id.clear(); access_token.clear(); homeserver.clear(); upload_limit.reset(); @@ -3063,7 +3063,7 @@ namespace QuickMedia { std::string access_token = access_token_json.GetString(); std::string homeserver = homeserver_json.GetString(); - this->user_id = std::move(user_id); + this->my_user_id = std::move(user_id); this->access_token = std::move(access_token); this->homeserver = std::move(homeserver); return PluginResult::OK; @@ -3086,7 +3086,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(user_id) , server_response, std::move(additional_args), use_tor, true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(my_user_id) , server_response, std::move(additional_args), use_tor, true); return download_result_to_plugin_result(download_result); } @@ -3106,7 +3106,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(user_id), server_response, std::move(additional_args), use_tor, true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(my_user_id), server_response, std::move(additional_args), use_tor, true); return download_result_to_plugin_result(download_result); } @@ -3199,7 +3199,7 @@ namespace QuickMedia { bool Matrix::was_message_posted_by_me(void *message) { Message *message_typed = (Message*)message; - return user_id == message_typed->user->user_id; + return my_user_id == message_typed->user->user_id; } std::string Matrix::message_get_author_displayname(Message *message) const { @@ -3239,7 +3239,7 @@ namespace QuickMedia { } std::shared_ptr Matrix::get_me(RoomData *room) { - return get_user_by_id(room, user_id); + return get_user_by_id(room, my_user_id); } RoomData* Matrix::get_room_by_id(const std::string &id) { @@ -3336,6 +3336,7 @@ namespace QuickMedia { } void Matrix::update_room_users(RoomData *room) { +#if 1 std::vector additional_args = { { "-H", "Authorization: Bearer " + access_token } }; @@ -3360,7 +3361,8 @@ namespace QuickMedia { const rapidjson::Value &avatar_url_json = GetMember(joined_obj.value, "avatar_url"); const rapidjson::Value &display_name_json = GetMember(joined_obj.value, "display_name"); - auto user = get_user_by_id(room, std::string(joined_obj.name.GetString(), joined_obj.name.GetStringLength())); + std::string user_id(joined_obj.name.GetString(), joined_obj.name.GetStringLength()); + auto user = get_user_by_id(room, user_id); assert(user); std::string display_name = display_name_json.IsString() ? display_name_json.GetString() : user_id; @@ -3372,6 +3374,28 @@ namespace QuickMedia { room->set_user_avatar_url(user, std::move(avatar_url)); room->set_user_display_name(user, std::move(display_name)); } +#else + std::vector additional_args = { + { "-H", "Authorization: Bearer " + access_token } + }; + + // TODO: Use at param? which is room->get_prev_batch(); + char url[512]; + snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/members?membership=join", homeserver.c_str(), room->id.c_str()); + + rapidjson::Document json_root; + DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true); + if(download_result != DownloadResult::OK || !json_root.IsObject()) { + fprintf(stderr, "Fetching users for room %s failed!\n", room->id.c_str()); + return; + } + + const rapidjson::Value &chunk_json = GetMember(json_root, "chunk"); + if(!chunk_json.IsArray()) + return; + + events_add_user_info(chunk_json, room); +#endif } // TODO: GET the filter to check if its valid? -- cgit v1.2.3