aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/Matrix.hpp20
-rw-r--r--plugins/utils/UniqueProcess.hpp7
-rw-r--r--src/QuickMedia.cpp80
-rw-r--r--src/plugins/Matrix.cpp224
-rw-r--r--src/plugins/utils/UniqueProcess.cpp111
5 files changed, 238 insertions, 204 deletions
diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp
index aae7411..c1ee3bd 100644
--- a/plugins/Matrix.hpp
+++ b/plugins/Matrix.hpp
@@ -326,6 +326,8 @@ namespace QuickMedia {
virtual void remove_user(MatrixEventUserInfo user_info) = 0;
virtual void set_user_info(MatrixEventUserInfo user_info) = 0;
virtual void set_room_info(MatrixEventRoomInfo room_info) = 0;
+
+ virtual void clear_data() = 0;
};
class Matrix;
@@ -360,6 +362,8 @@ namespace QuickMedia {
void set_room_as_read(RoomData *room);
+ void clear_data() override;
+
Program *program;
Matrix *matrix;
MatrixChatPage *chat_page;
@@ -397,6 +401,8 @@ namespace QuickMedia {
void clear_search();
+ void clear_data();
+
MatrixQuickMedia *matrix_delegate = nullptr;
Body *body = nullptr;
private:
@@ -422,6 +428,8 @@ namespace QuickMedia {
void set_current_rooms_page(MatrixRoomsPage *rooms_page);
+ void clear_data();
+
MatrixQuickMedia *matrix_delegate = nullptr;
private:
struct TagData {
@@ -445,6 +453,8 @@ namespace QuickMedia {
void add_body_item(std::shared_ptr<BodyItem> body_item);
void remove_body_item_by_room_id(const std::string &room_id);
+
+ void clear_data();
private:
Matrix *matrix;
Body *body;
@@ -560,6 +570,7 @@ namespace QuickMedia {
const std::string room_id;
MatrixRoomsPage *rooms_page = nullptr;
+ bool should_clear_data = false;
Body *chat_body = nullptr;
bool messages_tab_visible = false;
@@ -751,16 +762,16 @@ namespace QuickMedia {
PluginResult set_qm_last_read_message_timestamp(RoomData *room, int64_t timestamp);
void load_qm_read_markers_from_account_data();
- PluginResult parse_sync_response(const rapidjson::Document &root, bool initial_sync);
+ PluginResult parse_sync_response(const rapidjson::Document &root, bool is_additional_messages_sync, bool initial_sync);
PluginResult parse_notifications(const rapidjson::Value &notifications_json, std::function<void(const MatrixNotification&)> callback_func);
PluginResult parse_sync_account_data(const rapidjson::Value &account_data_json);
- PluginResult parse_sync_room_data(const rapidjson::Value &rooms_json, bool initial_sync);
+ PluginResult parse_sync_room_data(const rapidjson::Value &rooms_json, bool is_additional_messages_sync, bool initial_sync);
void parse_custom_emoji(const rapidjson::Value &custom_emoji_json);
void load_custom_emoji_from_cache();
PluginResult get_previous_room_messages(RoomData *room_data, bool latest_messages, size_t &num_new_messages, bool *reached_end = nullptr);
void events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data, int64_t timestamp);
std::shared_ptr<UserInfo> parse_user_info(const rapidjson::Value &json, const std::string &user_id, RoomData *room_data, int64_t timestamp);
- void events_set_user_read_marker(const rapidjson::Value &events_json, RoomData *room_data, std::shared_ptr<UserInfo> &me);
+ void events_set_user_read_marker(const rapidjson::Value &events_json, RoomData *room_data, std::shared_ptr<UserInfo> &me, bool is_additional_messages_sync);
// Returns the number of messages added
size_t events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, bool has_unread_notifications);
void events_set_room_info(const rapidjson::Value &events_json, RoomData *room_data, int64_t timestamp);
@@ -782,6 +793,7 @@ namespace QuickMedia {
std::string get_next_batch();
void set_next_notifications_token(std::string new_next_token);
std::string get_next_notifications_token();
+ void clear_sync_cache_for_new_sync();
std::shared_ptr<UserInfo> get_user_by_id(RoomData *room, const std::string &user_id, bool *is_new_user = nullptr, bool create_if_not_found = true);
std::string get_filter_cached();
void load_silenced_invites();
@@ -810,7 +822,9 @@ namespace QuickMedia {
std::mutex notifications_mutex;
std::thread sync_thread;
+ std::thread sync_additional_messages_thread;
std::thread notification_thread;
+ MessageQueue<bool> additional_messages_queue;
bool sync_running = false;
bool sync_failed = false;
bool sync_is_cache = false;
diff --git a/plugins/utils/UniqueProcess.hpp b/plugins/utils/UniqueProcess.hpp
deleted file mode 100644
index f85704f..0000000
--- a/plugins/utils/UniqueProcess.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-namespace QuickMedia {
- bool is_quickmedia_instance_already_running(const char *sock_file_dir, const char *plugin_name);
- bool set_quickmedia_instance_unique(const char *sock_file_dir, const char *plugin_name);
- void remove_quickmedia_instance_lock(const char *sock_file_dir, const char *plugin_name);
-} \ No newline at end of file
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 0e9f152..2c40580 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -39,7 +39,6 @@
#include "../include/Downloader.hpp"
#include "../include/Storage.hpp"
#include "../include/AsyncImageLoader.hpp"
-#include "../plugins/utils/UniqueProcess.hpp"
#include <mglpp/system/FloatRect.hpp>
#include "../include/gui/Button.hpp"
#include "../external/hash-library/sha256.h"
@@ -408,7 +407,7 @@ namespace QuickMedia {
video_max_height = 0;
std::vector<Tab> tabs;
const char *url = nullptr;
- std::string program_path = Path(argv[0]).parent().data;
+ std::string program_path = dirname(argv[0]);
std::string instance;
std::string download_filename;
bool no_dialog = false;
@@ -634,7 +633,7 @@ namespace QuickMedia {
chat_login_page();
}
after_matrix_login_page();
- goto done;
+ return exit_code;
}
page_loop(tabs, start_tab_index);
@@ -651,10 +650,6 @@ namespace QuickMedia {
}
}
- done:
- if(plugin_name && strcmp(plugin_name, "matrix") == 0)
- remove_quickmedia_instance_lock(get_cache_dir().join("matrix").data.c_str(), "matrix");
-
return exit_code;
}
@@ -1332,7 +1327,7 @@ namespace QuickMedia {
page_stack.push(current_page);
current_page = PageType::IMAGE_BOARD_THREAD;
image_board_thread_page(thread_page.get(), body.get());
- exit(exit_code);
+ exit(0);
} else {
auto boards_page = std::make_unique<FourchanBoardsPage>(this, resources_root);
FourchanBoardsPage *boards_page_ptr = boards_page.get();
@@ -1429,22 +1424,10 @@ namespace QuickMedia {
tabs.push_back(Tab{create_body(false, true), std::make_unique<LbrySearchPage>(this), create_search_bar("Search...", 500)});
} else if(strcmp(plugin_name, "matrix") == 0) {
assert(!matrix);
-
if(create_directory_recursive(get_cache_dir().join("matrix").join("events")) != 0) {
show_notification("QuickMedia", "Failed to create events cache directory", Urgency::CRITICAL);
abort();
}
-
- if(is_quickmedia_instance_already_running(get_cache_dir().join("matrix").data.c_str(), "matrix")) {
- show_notification("QuickMedia", "Only one instance of matrix can be run. Change $XDG_CACHE_HOME if you want to run multiple instances", Urgency::CRITICAL);
- exit(exit_code);
- }
-
- if(!set_quickmedia_instance_unique(get_cache_dir().join("matrix").data.c_str(), "matrix")) {
- show_notification("QuickMedia", "Failed to set quickmedia process as unique", Urgency::CRITICAL);
- exit(exit_code);
- }
-
matrix = new Matrix();
} else {
assert(false);
@@ -7889,6 +7872,63 @@ namespace QuickMedia {
tabs[selected_tab].body->on_bottom_reached();
}
+ if(matrix_chat_page->should_clear_data) {
+ matrix_chat_page->should_clear_data = false;
+
+ std::string err_msg;
+ while(!matrix->is_initial_sync_finished()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ if(matrix->did_initial_sync_fail(err_msg)) {
+ matrix_chat_page->set_current_room(nullptr, nullptr, nullptr);
+ fetch_messages_future.cancel();
+ cleanup_tasks();
+ tabs.clear();
+ unreferenced_events.clear();
+ unresolved_reactions.clear();
+ all_messages.clear();
+ show_notification("QuickMedia", "Initial matrix sync failed, error: " + err_msg, Urgency::CRITICAL);
+ matrix->logout();
+ delete matrix;
+ matrix = new Matrix();
+ current_page = PageType::CHAT_LOGIN;
+ chat_login_page();
+ after_matrix_login_page();
+ window.close();
+ goto chat_page_end;
+ }
+ }
+
+ //all_messages.clear();
+
+ tabs[MESSAGES_TAB_INDEX].body->clear_items();
+
+ Messages all_messages_new;
+ matrix->get_all_synced_room_messages(current_room, all_messages_new);
+ for(auto &message : all_messages_new) {
+ fetched_messages_set.insert(message->event_id);
+ }
+ all_messages.insert(all_messages.end(), all_messages_new.begin(), all_messages_new.end());
+ //me = matrix->get_me(current_room);
+ filter_provisional_messages(all_messages_new);
+ add_new_messages_to_current_room(all_messages_new);
+ modify_related_messages_in_current_room(all_messages_new);
+ unresolved_reactions.clear();
+ after_token.clear();
+ before_token.clear(),
+ fetched_enough_messages_top = false;
+ fetched_enough_messages_bottom = false;
+ fetch_messages_future.cancel();
+ process_reactions(all_messages_new);
+ if(current_room->initial_prev_messages_fetch) {
+ current_room->initial_prev_messages_fetch = false;
+ tabs[MESSAGES_TAB_INDEX].body->select_last_item();
+ }
+
+ std::vector<std::string> pinned_events;
+ matrix->get_all_pinned_events(current_room, pinned_events);
+ process_pinned_events(std::move(pinned_events));
+ }
+
if(go_to_previous_page) {
go_to_previous_page = false;
goto chat_page_end;
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index fca4332..0d93bd0 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -17,7 +17,6 @@
#include <rapidjson/filewritestream.h>
#include <fcntl.h>
#include <unistd.h>
-#include <fstream>
#include <malloc.h>
#include "../../include/QuickMedia.hpp"
#include <HtmlParser.h>
@@ -39,6 +38,7 @@ namespace QuickMedia {
// then we cant see room message preview. TODO: Fix this somehow.
// TODO: What about state events in initial sync in timeline? such as user display name change.
static const char* INITIAL_FILTER = "{\"presence\":{\"limit\":0,\"types\":[\"\"]},\"account_data\":{\"types\":[\"qm.emoji\",\"m.direct\"]},\"room\":{\"state\":{\"not_types\":[\"m.room.related_groups\",\"m.room.power_levels\",\"m.room.join_rules\",\"m.room.history_visibility\",\"m.room.canonical_alias\",\"m.space.child\"],\"lazy_load_members\":true},\"timeline\":{\"types\":[\"m.room.message\"],\"limit\":1,\"lazy_load_members\":true},\"ephemeral\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true},\"account_data\":{\"limit\":1,\"types\":[\"m.fully_read\",\"m.tag\",\"qm.last_read_message_timestamp\"],\"lazy_load_members\":true}}}";
+ static const char* ADDITIONAL_MESSAGES_FILTER = "{\"presence\":{\"types\":[\"\"]},\"account_data\":{\"limit\":0,\"types\":[\"\"]},\"room\":{\"state\":{\"not_types\":[\"m.room.related_groups\",\"m.room.power_levels\",\"m.room.join_rules\",\"m.room.history_visibility\",\"m.room.canonical_alias\",\"m.space.child\"],\"lazy_load_members\":true},\"timeline\":{\"limit\":20,\"lazy_load_members\":true},\"ephemeral\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true},\"account_data\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true}}}";
static const char* CONTINUE_FILTER = "{\"presence\":{\"limit\":0,\"types\":[\"\"]},\"account_data\":{\"types\":[\"qm.emoji\",\"m.direct\"]},\"room\":{\"state\":{\"not_types\":[\"m.room.related_groups\",\"m.room.power_levels\",\"m.room.join_rules\",\"m.room.history_visibility\",\"m.room.canonical_alias\",\"m.space.child\"],\"lazy_load_members\":true},\"timeline\":{\"lazy_load_members\":true},\"ephemeral\":{\"limit\":0,\"types\":[\"\"],\"lazy_load_members\":true},\"account_data\":{\"types\":[\"m.fully_read\",\"m.tag\",\"qm.last_read_message_timestamp\"],\"lazy_load_members\":true}}}";
static bool is_gpg_installed = false;
@@ -802,6 +802,15 @@ namespace QuickMedia {
body->set_selected_item(found_item_index, false);
}
+ void MatrixQuickMedia::clear_data() {
+ //room_body_item_by_room.clear();
+ //pending_room_messages.clear();
+ //rooms_page->clear_data();
+ //room_tags_page->clear_data();
+ invites_page->clear_data();
+ //unread_notifications.clear();
+ }
+
static std::shared_ptr<Message> get_last_message_by_timestamp(const Messages &messages) {
if(messages.empty())
return nullptr;
@@ -1029,6 +1038,12 @@ namespace QuickMedia {
body->select_first_item();
}
+ void MatrixRoomsPage::clear_data() {
+ body->clear_items();
+ if(current_chat_page)
+ current_chat_page->should_clear_data = true;
+ }
+
PluginResult MatrixRoomTagsPage::submit(const SubmitArgs &args, std::vector<Tab> &result_tabs) {
auto body = create_body(true);
Body *body_ptr = body.get();
@@ -1116,6 +1131,13 @@ namespace QuickMedia {
current_rooms_page = rooms_page;
}
+ void MatrixRoomTagsPage::clear_data() {
+ tag_body_items_by_name.clear();
+ body->clear_items();
+ if(current_rooms_page)
+ current_rooms_page->clear_data();
+ }
+
MatrixInvitesPage::MatrixInvitesPage(Program *program, Matrix *matrix, Body *body) : Page(program), matrix(matrix), body(body) {
}
@@ -1176,6 +1198,12 @@ namespace QuickMedia {
}
}
+ void MatrixInvitesPage::clear_data() {
+ body->clear_items();
+ prev_invite_count = 0;
+ title = "Invites (0)";
+ }
+
PluginResult MatrixSettingsPage::submit(const SubmitArgs &args, std::vector<Tab> &result_tabs) {
if(args.url == "join") {
result_tabs.push_back(Tab{create_body(), std::make_unique<MatrixRoomInputPage>(program, matrix), create_search_bar("Enter room id...", SEARCH_DELAY_FILTER)});
@@ -1649,6 +1677,44 @@ namespace QuickMedia {
"M_MISSING_PARAM"
};
+ static void remove_empty_fields_in_sync_rooms_response(rapidjson::Value &rooms_json) {
+ for(const char *member_name : {"join", "invite", "leave"}) {
+ auto join_it = rooms_json.FindMember(member_name);
+ if(join_it != rooms_json.MemberEnd() && join_it->value.IsObject() && join_it->value.MemberCount() == 0)
+ rooms_json.RemoveMember(join_it);
+ }
+ }
+
+ static void remove_empty_fields_in_sync_account_data_response(rapidjson::Value &account_data_json) {
+ for(const char *member_name : {"events"}) {
+ auto join_it = account_data_json.FindMember(member_name);
+ if(join_it != account_data_json.MemberEnd() && join_it->value.IsObject() && join_it->value.MemberCount() == 0)
+ account_data_json.RemoveMember(join_it);
+ }
+ }
+
+ static void remove_unused_sync_data_fields(rapidjson::Value &json_root) {
+ for(auto it = json_root.MemberBegin(); it != json_root.MemberEnd();) {
+ if(strcmp(it->name.GetString(), "account_data") == 0 && it->value.IsObject()) {
+ remove_empty_fields_in_sync_account_data_response(it->value);
+ if(it->value.MemberCount() == 0)
+ it = json_root.RemoveMember(it);
+ else
+ ++it;
+ } else if(strcmp(it->name.GetString(), "rooms") == 0 && it->value.IsObject()) {
+ // TODO: Call this, but dont remove our read marker (needed for notifications on mentions for example). Or maybe we can get it from "account_data"?
+ //remove_ephemeral_field_in_sync_rooms_response(rooms_it->value);
+ remove_empty_fields_in_sync_rooms_response(it->value);
+ if(it->value.MemberCount() == 0)
+ it = json_root.RemoveMember(it);
+ else
+ ++it;
+ } else {
+ it = json_root.EraseMember(it);
+ }
+ }
+ }
+
bool Matrix::start_sync(MatrixDelegate *delegate, bool &cached) {
cached = true;
if(sync_running)
@@ -1675,32 +1741,21 @@ namespace QuickMedia {
load_custom_emoji_from_cache();
sync_thread = std::thread([this, matrix_cache_dir]() {
- FILE *sync_cache_file;
- const rapidjson::Value *next_batch_json = nullptr;
sync_is_cache = true;
-
- std::ifstream sync_cache_file_stream;
- sync_cache_file_stream.open(matrix_cache_dir.data.c_str(), std::ifstream::in | std::ifstream::binary);
- if(sync_cache_file_stream.good() && get_file_type(get_cache_dir().join("matrix").join("updated-cache-version")) == FileType::REGULAR) {
+ FILE *sync_cache_file = fopen(matrix_cache_dir.data.c_str(), "rb");
+ if(sync_cache_file) {
rapidjson::Document doc;
- std::string line;
- while(std::getline(sync_cache_file_stream, line)) {
- rapidjson::ParseResult parse_result = doc.Parse<rapidjson::kParseStopWhenDoneFlag>(line.c_str(), line.size());
+ char read_buffer[8192];
+ rapidjson::FileReadStream is(sync_cache_file, read_buffer, sizeof(read_buffer));
+ while(true) {
+ rapidjson::ParseResult parse_result = doc.ParseStream<rapidjson::kParseStopWhenDoneFlag>(is);
if(parse_result.IsError())
- continue; // This should NEVER happen. Do initial sync if it does and remove cache? :( TODO
-
- if(parse_sync_response(doc, false) != PluginResult::OK)
+ break;
+ if(parse_sync_response(doc, false, false) != PluginResult::OK)
fprintf(stderr, "Failed to parse cached sync response\n");
-
- next_batch_json = &GetMember(doc, "next_batch");
- if(next_batch_json->IsString()) {
- set_next_batch(next_batch_json->GetString());
- //fprintf(stderr, "Matrix: next batch: %s\n", next_batch.c_str());
- }
}
- malloc_trim(0);
+ fclose(sync_cache_file);
}
- sync_cache_file_stream.close();
sync_is_cache = false;
load_qm_read_markers_from_account_data(); // TODO: Remove when https://github.com/matrix-org/synapse/issues/14444 is fixed, if ever.
@@ -1722,22 +1777,16 @@ namespace QuickMedia {
else
filter = FILTER;
#endif
+ std::string filter_encoded = url_param_encode(INITIAL_FILTER);
+
std::vector<CommandArg> additional_args = {
{ "-H", "Authorization: Bearer " + access_token },
{ "-m", "35" }
};
- next_batch_json = nullptr;
+ const rapidjson::Value *next_batch_json;
PluginResult result;
- bool initial_sync = next_batch.empty();
- bool first_sync = true;
-
- std::string filter_encoded;
- if(initial_sync)
- filter_encoded = url_param_encode(INITIAL_FILTER);
- else
- filter_encoded = url_param_encode(CONTINUE_FILTER);
-
+ bool initial_sync = true;
while(sync_running) {
char url[2048];
if(next_batch.empty())
@@ -1772,7 +1821,10 @@ namespace QuickMedia {
}
}
- result = parse_sync_response(json_root, initial_sync);
+ if(next_batch.empty())
+ clear_sync_cache_for_new_sync();
+
+ result = parse_sync_response(json_root, false, initial_sync);
if(result != PluginResult::OK) {
fprintf(stderr, "Failed to parse sync response\n");
initial_sync = false;
@@ -1790,10 +1842,7 @@ namespace QuickMedia {
goto sync_end;
}
- if(first_sync) {
- first_sync = false;
- filter_encoded = url_param_encode(CONTINUE_FILTER);
-
+ if(initial_sync) {
notification_thread = std::thread([this]() {
get_previous_notifications([this](const MatrixNotification &notification) {
if(notification.read)
@@ -1804,8 +1853,39 @@ namespace QuickMedia {
delegate->add_unread_notification(std::move(notification));
});
});
+
finished_fetching_notifications = true;
+
+ {
+ std::vector<CommandArg> additional_args = {
+ { "-H", "Authorization: Bearer " + access_token },
+ { "-m", "35" }
+ };
+
+ char url[1024];
+ std::string filter_encoded = url_param_encode(ADDITIONAL_MESSAGES_FILTER);
+ snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?filter=%s&timeout=0", homeserver.c_str(), filter_encoded.c_str());
+
+ rapidjson::Document json_root;
+ std::string err_msg;
+ DownloadResult download_result = download_json(json_root, url, additional_args, true, &err_msg);
+ if(download_result != DownloadResult::OK) {
+ fprintf(stderr, "/sync for additional messages failed\n");
+ return;
+ }
+
+ // TODO: Test?
+ //if(next_batch.empty())
+ // clear_sync_cache_for_new_sync();
+
+ additional_messages_queue.pop_wait();
+ parse_sync_response(json_root, true, false);
+ }
});
+
+ filter_encoded = url_param_encode(CONTINUE_FILTER);
+ additional_messages_queue.push(true);
+ malloc_trim(0);
}
#if 0
@@ -1815,26 +1895,16 @@ namespace QuickMedia {
}
#endif
- // TODO: Use a NoSQL database.
- // TODO: Remove very old cache.
- // TODO: Find a way to remove this? this makes sync work like other clients but we dont want that!
- // If the last sync was long ago then it has to sync ALL messages again. Maybe check if sync file
- // is XX days old and then ignore it?
+ // TODO: Circulate file
sync_cache_file = fopen(matrix_cache_dir.data.c_str(), initial_sync ? "wb" : "ab");
initial_sync = false;
if(sync_cache_file) {
if(json_root.IsObject()) {
- rapidjson::StringBuffer buffer;
- rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ char buffer[4096];
+ rapidjson::FileWriteStream file_write_stream(sync_cache_file, buffer, sizeof(buffer));
+ rapidjson::Writer<rapidjson::FileWriteStream> writer(file_write_stream);
+ remove_unused_sync_data_fields(json_root);
json_root.Accept(writer);
-
- std::string json_data(buffer.GetString(), buffer.GetSize());
- string_replace_all(json_data, '\n', ' ');
- json_data += '\n';
-
- fwrite(json_data.data(), 1, json_data.size(), sync_cache_file);
- file_overwrite(get_cache_dir().join("matrix").join("updated-cache-version"), "1"); // To make sure the cache format is up to date
- malloc_trim(0);
}
fclose(sync_cache_file);
}
@@ -1855,6 +1925,13 @@ namespace QuickMedia {
program_kill_in_thread(sync_thread.get_id());
sync_thread.join();
}
+
+ if(sync_additional_messages_thread.joinable()) {
+ program_kill_in_thread(sync_additional_messages_thread.get_id());
+ additional_messages_queue.close();
+ sync_additional_messages_thread.join();
+ additional_messages_queue.restart();
+ }
if(notification_thread.joinable()) {
program_kill_in_thread(notification_thread.get_id());
@@ -2036,12 +2113,12 @@ namespace QuickMedia {
}
}
- PluginResult Matrix::parse_sync_response(const rapidjson::Document &root, bool initial_sync) {
+ PluginResult Matrix::parse_sync_response(const rapidjson::Document &root, bool is_additional_messages_sync, bool initial_sync) {
if(!root.IsObject())
return PluginResult::ERR;
const rapidjson::Value &rooms_json = GetMember(root, "rooms");
- parse_sync_room_data(rooms_json, initial_sync);
+ parse_sync_room_data(rooms_json, is_additional_messages_sync, initial_sync);
const rapidjson::Value &account_data_json = GetMember(root, "account_data");
parse_sync_account_data(account_data_json);
@@ -2223,7 +2300,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::parse_sync_room_data(const rapidjson::Value &rooms_json, bool initial_sync) {
+ PluginResult Matrix::parse_sync_room_data(const rapidjson::Value &rooms_json, bool is_additional_messages_sync, bool initial_sync) {
if(!rooms_json.IsObject())
return PluginResult::OK;
@@ -2265,9 +2342,16 @@ namespace QuickMedia {
const rapidjson::Value &timeline_json = GetMember(it.value, "timeline");
if(timeline_json.IsObject()) {
+ if(is_additional_messages_sync) {
+ // This may be non-existent if this is the first event in the room
+ const rapidjson::Value &prev_batch_json = GetMember(timeline_json, "prev_batch");
+ if(prev_batch_json.IsString())
+ room->set_prev_batch(prev_batch_json.GetString());
+ }
+
bool has_unread_notifications = false;
const rapidjson::Value &unread_notification_json = GetMember(it.value, "unread_notifications");
- if(unread_notification_json.IsObject() && !sync_is_cache) {
+ if(unread_notification_json.IsObject() && !is_additional_messages_sync && !sync_is_cache) {
const rapidjson::Value &highlight_count_json = GetMember(unread_notification_json, "highlight_count");
if(highlight_count_json.IsInt64() && (highlight_count_json.GetInt64() > 0 || initial_sync)) {
room->unread_notification_count = highlight_count_json.GetInt64();
@@ -2284,7 +2368,7 @@ namespace QuickMedia {
if(account_data_json.IsObject()) {
const rapidjson::Value &events_json = GetMember(account_data_json, "events");
auto me = get_me(room);
- events_set_user_read_marker(events_json, room, me);
+ events_set_user_read_marker(events_json, room, me, is_additional_messages_sync);
}
if(is_new_room)
@@ -2297,7 +2381,7 @@ namespace QuickMedia {
if(account_data_json.IsObject()) {
const rapidjson::Value &events_json = GetMember(account_data_json, "events");
auto me = get_me(room);
- events_set_user_read_marker(events_json, room, me);
+ events_set_user_read_marker(events_json, room, me, is_additional_messages_sync);
}
if(is_new_room)
@@ -2326,11 +2410,13 @@ namespace QuickMedia {
}
}
- const rapidjson::Value &leave_json = GetMember(rooms_json, "leave");
- remove_rooms(leave_json);
+ if(!is_additional_messages_sync) {
+ const rapidjson::Value &leave_json = GetMember(rooms_json, "leave");
+ remove_rooms(leave_json);
- const rapidjson::Value &invite_json = GetMember(rooms_json, "invite");
- add_invites(invite_json);
+ const rapidjson::Value &invite_json = GetMember(rooms_json, "invite");
+ add_invites(invite_json);
+ }
if(initial_sync) {
std::lock_guard<std::recursive_mutex> lock(room_data_mutex);
@@ -2463,7 +2549,7 @@ namespace QuickMedia {
return user_info;
}
- void Matrix::events_set_user_read_marker(const rapidjson::Value &events_json, RoomData *room_data, std::shared_ptr<UserInfo> &me) {
+ void Matrix::events_set_user_read_marker(const rapidjson::Value &events_json, RoomData *room_data, std::shared_ptr<UserInfo> &me, bool is_additional_messages_sync) {
assert(me); // TODO: Remove read marker from user and set it for the room instead. We need that in the matrix pages also
if(!events_json.IsArray() || !me)
return;
@@ -2485,7 +2571,7 @@ namespace QuickMedia {
if(!event_id_json.IsString())
continue;
- if(!sync_is_cache)
+ if(!sync_is_cache && !is_additional_messages_sync)
room_data->set_user_read_marker(me, std::string(event_id_json.GetString(), event_id_json.GetStringLength()));
} else if(strcmp(type_json.GetString(), "qm.last_read_message_timestamp") == 0) { // TODO: Remove qm.last_read_message_timestamp in room level eventually when everybody has data in global level
const rapidjson::Value &content_json = GetMember(event_json, "content");
@@ -5801,6 +5887,18 @@ namespace QuickMedia {
return next_notifications_token;
}
+ void Matrix::clear_sync_cache_for_new_sync() {
+ std::lock_guard<std::recursive_mutex> room_data_lock(room_data_mutex);
+ std::lock_guard<std::mutex> invites_lock(invite_mutex);
+ for(auto &room : rooms) {
+ room->clear_data();
+ }
+ // We intentionally dont clear |rooms| here because we want the objects inside it to still be valid. TODO: Clear |rooms| here
+ //room_data_by_id.clear();
+ invites.clear();
+ ui_thread_tasks.push([this]{ delegate->clear_data(); });
+ }
+
std::shared_ptr<UserInfo> Matrix::get_user_by_id(RoomData *room, const std::string &user_id, bool *is_new_user, bool create_if_not_found) {
auto user = room->get_user_by_id(user_id);
if(user) {
diff --git a/src/plugins/utils/UniqueProcess.cpp b/src/plugins/utils/UniqueProcess.cpp
deleted file mode 100644
index d2025f5..0000000
--- a/src/plugins/utils/UniqueProcess.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#include "../../../plugins/utils/UniqueProcess.hpp"
-#include "../../../include/Storage.hpp"
-#include <stdio.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-
-namespace QuickMedia {
- bool is_quickmedia_instance_already_running(const char *sock_file_dir, const char *plugin_name) {
- char sock_file[PATH_MAX];
- snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);
-
- std::string resolved_path;
- if(file_get_content(sock_file, resolved_path) != 0)
- return false;
-
- resolved_path.resize(108); // sizeof(addr.sun_path) is 108
-
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fd == -1) {
- fprintf(stderr, "Error: failed to create unix domain socket, error: %s\n", strerror(errno));
- return true;
- }
-
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, resolved_path.c_str());
-
- bool running = connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0;
- int err = errno;
- if(err == EAGAIN)
- running = true;
- else if(err == ENOENT)
- running = false;
- close(fd);
- return running;
- }
-
- bool set_quickmedia_instance_unique(const char *sock_file_dir, const char *plugin_name) {
- char socket_file[] = "/tmp/quickmedia.XXXXXX";
- int tmp_file_fd = mkstemp(socket_file);
- if(tmp_file_fd == -1) {
- fprintf(stderr, "Error: failed to create temporary file for unix domain socket, error: %s\n", strerror(errno));
- return false;
- }
- unlink(socket_file);
- close(tmp_file_fd);
-
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fd == -1) {
- fprintf(stderr, "Error: failed to create unix domain socket, error: %s\n", strerror(errno));
- return false;
- }
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, socket_file);
-
- if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
- fprintf(stderr, "Error: failed to bind unix domain socket, error: %s\n", strerror(errno));
- unlink(socket_file);
- close(fd);
- return false;
- }
-
- if(listen(fd, 0) == -1) {
- fprintf(stderr, "Error: failed to listen to unix domain socket, error: %s\n", strerror(errno));
- unlink(socket_file);
- close(fd);
- return false;
- }
-
- char sock_file[PATH_MAX];
- snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);
- bool success = file_overwrite(sock_file, socket_file) == 0;
- if(!success) {
- fprintf(stderr, "Error: failed to create %s unix domain socket link file\n", sock_file);
- unlink(socket_file);
- close(fd);
- }
- return success;
- }
-
- void remove_quickmedia_instance_lock(const char *sock_file_dir, const char *plugin_name) {
- char sock_file[PATH_MAX];
- snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);
-
- std::string resolved_path;
- if(file_get_content(sock_file, resolved_path) != 0) {
- unlink(sock_file);
- return;
- }
-
- resolved_path.resize(108); // sizeof(addr.sun_path) is 108
-
- if(resolved_path.size() < 4 || memcmp(resolved_path.data(), "/tmp", 4) != 0) {
- unlink(sock_file);
- return;
- }
-
- unlink(sock_file);
- unlink(resolved_path.c_str());
- }
-} \ No newline at end of file