aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-09-25 04:15:17 +0200
committerdec05eba <dec05eba@protonmail.com>2020-09-25 04:15:17 +0200
commiteac2ace1c14c1ae0564d757b26a359c6bd4b754a (patch)
tree855b98a19b6a302663a2d26e3ed6ca69110d1ce0 /src/plugins
parent6cb237cfba67e1a15d475dccfb706bcc179afe71 (diff)
Matrix: fetch previous messages when reaching the top
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Matrix.cpp117
1 files changed, 85 insertions, 32 deletions
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 2d4fd4a..529d42a 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -159,9 +159,37 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::get_room_messages(const std::string &room_id, size_t start_index, BodyItems &result_items, size_t &num_new_messages) {
- num_new_messages = 0;
+ static void room_messages_to_body_items(RoomData *room_data, Message *messages, size_t num_messages, BodyItems &result_items) {
+ // TODO: This prev_user_id should check previous message, otherwise if after a sync there is only 1 new message then it wont
+ // merge with the previous message. But for that to work then also have to send existing body items to this function,
+ // to get the body item to merge with
+ size_t prev_user_id = -1;
+ for(size_t i = 0; i < num_messages; ++i) {
+ const UserInfo &user_info = room_data->user_info[messages[i].user_id];
+ if(messages[i].user_id == prev_user_id && messages[i].url.empty()) {
+ assert(!result_items.empty());
+ result_items.back()->append_description("\n");
+ result_items.back()->append_description(messages[i].body);
+ } else {
+ auto body_item = std::make_unique<BodyItem>("");
+ body_item->set_author(user_info.display_name);
+ body_item->set_description(messages[i].body);
+ if(!messages[i].thumbnail_url.empty())
+ body_item->thumbnail_url = messages[i].thumbnail_url;
+ else if(!messages[i].url.empty())
+ body_item->thumbnail_url = messages[i].url;
+ else
+ body_item->thumbnail_url = user_info.avatar_url;
+ // TODO: Show image thumbnail inline instead of url to image
+ body_item->url = messages[i].url;
+ result_items.push_back(std::move(body_item));
+ prev_user_id = messages[i].user_id;
+ }
+ }
+ }
+ // TODO: Merge common code with |get_new_room_messages|
+ PluginResult Matrix::get_all_synced_room_messages(const std::string &room_id, BodyItems &result_items) {
auto room_it = room_data_by_id.find(room_id);
if(room_it == room_data_by_id.end()) {
fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
@@ -169,7 +197,7 @@ namespace QuickMedia {
}
if(!room_it->second->initial_fetch_finished) {
- PluginResult result = load_initial_room_data(room_id, room_it->second.get());
+ PluginResult result = get_previous_room_messages(room_id, room_it->second.get());
if(result == PluginResult::OK) {
room_it->second->initial_fetch_finished = true;
} else {
@@ -178,36 +206,49 @@ namespace QuickMedia {
}
}
- // This will happen if there are no new messages
- if(start_index >= room_it->second->messages.size())
- return PluginResult::OK;
+ room_messages_to_body_items(room_it->second.get(), room_it->second->messages.data(), room_it->second->messages.size(), result_items);
+ room_it->second->last_read_index = room_it->second->messages.size();
+ return PluginResult::OK;
+ }
- num_new_messages = room_it->second->messages.size() - start_index;
+ PluginResult Matrix::get_new_room_messages(const std::string &room_id, BodyItems &result_items) {
+ auto room_it = room_data_by_id.find(room_id);
+ if(room_it == room_data_by_id.end()) {
+ fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
+ return PluginResult::ERR;
+ }
- size_t prev_user_id = -1;
- for(auto it = room_it->second->messages.begin() + start_index, end = room_it->second->messages.end(); it != end; ++it) {
- const UserInfo &user_info = room_it->second->user_info[it->user_id];
- if(it->user_id == prev_user_id && it->url.empty()) {
- assert(!result_items.empty());
- result_items.back()->append_description("\n");
- result_items.back()->append_description(it->body);
+ if(!room_it->second->initial_fetch_finished) {
+ PluginResult result = get_previous_room_messages(room_id, room_it->second.get());
+ if(result == PluginResult::OK) {
+ room_it->second->initial_fetch_finished = true;
} else {
- auto body_item = std::make_unique<BodyItem>("");
- body_item->set_author(user_info.display_name);
- body_item->set_description(it->body);
- if(!it->thumbnail_url.empty())
- body_item->thumbnail_url = it->thumbnail_url;
- else if(!it->url.empty())
- body_item->thumbnail_url = it->url;
- else
- body_item->thumbnail_url = user_info.avatar_url;
- // TODO: Show image thumbnail inline instead of url to image
- body_item->url = it->url;
- result_items.push_back(std::move(body_item));
- prev_user_id = it->user_id;
+ fprintf(stderr, "Initial sync failed for room: %s\n", room_id.c_str());
+ return result;
}
}
+ size_t num_new_messages = room_it->second->messages.size() - room_it->second->last_read_index;
+ room_messages_to_body_items(room_it->second.get(), room_it->second->messages.data() + room_it->second->last_read_index, num_new_messages, result_items);
+ room_it->second->last_read_index = room_it->second->messages.size();
+ return PluginResult::OK;
+ }
+
+ PluginResult Matrix::get_previous_room_messages(const std::string &room_id, BodyItems &result_items) {
+ auto room_it = room_data_by_id.find(room_id);
+ if(room_it == room_data_by_id.end()) {
+ fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
+ return PluginResult::ERR;
+ }
+
+ size_t num_messages_before = room_it->second->messages.size();
+ PluginResult result = get_previous_room_messages(room_id, room_it->second.get());
+ if(result != PluginResult::OK)
+ return result;
+
+ size_t num_messages_after = room_it->second->messages.size();
+ size_t num_new_messages = num_messages_after - num_messages_before;
+ room_messages_to_body_items(room_it->second.get(), room_it->second->messages.data(), num_new_messages, result_items);
return PluginResult::OK;
}
@@ -270,10 +311,12 @@ namespace QuickMedia {
if(!timeline_json.isObject())
continue;
- // This may be non-existent if this is the first event in the room
- const Json::Value &prev_batch_json = timeline_json["prev_batch"];
- if(prev_batch_json.isString())
- room_it->second->prev_batch = prev_batch_json.asString();
+ if(room_it->second->prev_batch.empty()) {
+ // This may be non-existent if this is the first event in the room
+ const Json::Value &prev_batch_json = timeline_json["prev_batch"];
+ if(prev_batch_json.isString())
+ room_it->second->prev_batch = prev_batch_json.asString();
+ }
const Json::Value &events_json = timeline_json["events"];
events_add_user_info(events_json, room_it->second.get());
@@ -415,8 +458,11 @@ namespace QuickMedia {
}
}
+ // TODO: Loop and std::move instead? doesn't insert create copies?
if(message_dir == MessageDirection::BEFORE) {
room_data->messages.insert(room_data->messages.begin(), new_messages.rbegin(), new_messages.rend());
+ if(room_data->last_read_index != 0)
+ room_data->last_read_index += new_messages.size();
} else if(message_dir == MessageDirection::AFTER) {
room_data->messages.insert(room_data->messages.end(), new_messages.begin(), new_messages.end());
}
@@ -500,7 +546,7 @@ namespace QuickMedia {
}
}
- PluginResult Matrix::load_initial_room_data(const std::string &room_id, RoomData *room_data) {
+ PluginResult Matrix::get_previous_room_messages(const std::string &room_id, RoomData *room_data) {
std::string from = room_data->prev_batch;
if(from.empty()) {
fprintf(stderr, "Info: missing previous batch for room: %s, using /sync next batch\n", room_id.c_str());
@@ -554,6 +600,13 @@ namespace QuickMedia {
const Json::Value &chunk_json = json_root["chunk"];
events_add_messages(chunk_json, room_data, MessageDirection::BEFORE);
+ const Json::Value &end_json = json_root["end"];
+ if(!end_json.isString()) {
+ fprintf(stderr, "Warning: matrix messages response is missing 'end', this could happen if we received the very first messages in the room\n");
+ return PluginResult::OK;
+ }
+
+ room_data->prev_batch = end_json.asString();
return PluginResult::OK;
}