From 620123fbd6c18dc48a25cc735565f6d8d85f8639 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 26 Oct 2020 09:48:25 +0100 Subject: Matrix: add room tags Fix pinned events that are added after starting QuickMedia (before this change it adds all elements again to the list). Add /me command. Other fixes... --- plugins/Matrix.hpp | 188 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 158 insertions(+), 30 deletions(-) (limited to 'plugins/Matrix.hpp') diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index f0ca4f5..281f5a8 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -5,24 +5,11 @@ #include "Page.hpp" #include #include +#include #include #include namespace QuickMedia { - // Dummy, only play one video. TODO: Play all videos in room, as related videos? - class MatrixVideoPage : public Page { - public: - MatrixVideoPage(Program *program) : Page(program) {} - const char* get_title() const override { return ""; } - PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override { - (void)title; - (void)url; - (void)result_tabs; - return PluginResult::ERR; - } - PageTypez get_type() const override { return PageTypez::VIDEO; } - }; - struct RoomData; struct UserInfo { @@ -78,8 +65,6 @@ namespace QuickMedia { // Ignores duplicates void append_messages(const std::vector> &new_messages); - void append_pinned_events(std::vector new_pinned_events); - std::shared_ptr get_message_by_id(const std::string &id); std::vector> get_users_excluding_me(const std::string &my_user_id); @@ -96,12 +81,16 @@ namespace QuickMedia { bool has_name(); void set_name(const std::string &new_name); + // TODO: Remove this std::string get_name(); bool has_avatar_url(); void set_avatar_url(const std::string &new_avatar_url); std::string get_avatar_url(); + void set_pinned_events(std::vector new_pinned_events); + std::set& get_tags_unsafe(); + std::string id; bool initial_fetch_finished = false; @@ -116,6 +105,9 @@ namespace QuickMedia { // TODO: Verify if replied to messages are also part of /sync; then this is not needed. std::unordered_map> fetched_messages_by_event_id; + size_t messages_read_index = 0; + bool pinned_events_updated = false; + size_t index; private: std::mutex user_mutex; @@ -131,6 +123,7 @@ namespace QuickMedia { std::vector> messages; std::unordered_map> message_by_event_id; std::vector pinned_events; + std::set tags; }; enum class MessageDirection { @@ -150,25 +143,158 @@ namespace QuickMedia { struct SyncData { Messages messages; - std::vector pinned_events; + std::optional> pinned_events; + std::optional> tags; }; - using RoomSyncData = std::unordered_map; using Rooms = std::vector; bool message_contains_user_mention(const std::string &msg, const std::string &username); + enum class MatrixPageType { + ROOM_LIST, + CHAT + }; + + class MatrixDelegate { + public: + virtual ~MatrixDelegate() = default; + + virtual void room_create(RoomData *room) = 0; + // Note: calling |room| methods inside this function is not allowed + virtual void room_add_tag(RoomData *room, const std::string &tag) = 0; + // Note: calling |room| methods inside this function is not allowed + virtual void room_remove_tag(RoomData *room, const std::string &tag) = 0; + virtual void room_add_new_messages(RoomData *room, const Messages &messages, bool is_initial_sync) = 0; + + virtual void update(MatrixPageType page_type) { (void)page_type; } + }; + + class Matrix; + class MatrixRoomsPage; + class MatrixRoomTagsPage; + + class MatrixQuickMedia : public MatrixDelegate { + public: + MatrixQuickMedia(Program *program, Matrix *matrix, MatrixRoomsPage *rooms_page, MatrixRoomTagsPage *room_tags_page); + + void room_create(RoomData *room) override; + void room_add_tag(RoomData *room, const std::string &tag) override; + void room_remove_tag(RoomData *room, const std::string &tag) override; + void room_add_new_messages(RoomData *room, const Messages &messages, bool is_initial_sync) override; + + void update(MatrixPageType page_type) override; + + Program *program; + Matrix *matrix; + MatrixRoomsPage *rooms_page; + MatrixRoomTagsPage *room_tags_page; + private: + struct RoomMessagesData { + Messages messages; + bool is_initial_sync; + }; + + std::vector> room_body_items; + std::map> room_body_item_by_room; + std::map pending_room_messages; + std::mutex pending_room_messages_mutex; + }; + + class MatrixRoomsPage : public Page { + public: + MatrixRoomsPage(Program *program, Body *body, std::string title, MatrixRoomTagsPage *room_tags_page = nullptr); + ~MatrixRoomsPage() override; + + const char* get_title() const override { return title.c_str(); } + PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override; + + void update() override; + void add_body_item(std::shared_ptr body_item); + + void move_room_to_top(RoomData *room); + + MatrixQuickMedia *matrix_delegate = nullptr; + private: + std::mutex mutex; + std::vector> room_body_items; + Body *body; + std::string title; + MatrixRoomTagsPage *room_tags_page; + }; + + class MatrixRoomTagsPage : public Page { + public: + MatrixRoomTagsPage(Program *program, Body *body) : Page(program), body(body) {} + const char* get_title() const override { return "Tags"; } + PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override; + + void update() override; + void add_room_body_item_to_tag(std::shared_ptr body_item, const std::string &tag); + void remove_room_body_item_from_tag(std::shared_ptr body_item, const std::string &tag); + + void move_room_to_top(RoomData *room); + + MatrixQuickMedia *matrix_delegate = nullptr; + MatrixRoomsPage *current_rooms_page = nullptr; + private: + struct TagData { + std::shared_ptr tag_item; + std::vector> room_body_items; + }; + + std::mutex mutex; + Body *body; + std::map tag_body_items_by_name; + std::map>> add_room_body_items_by_tags; + std::map>> remove_room_body_items_by_tags; + }; + + // Dummy, only play one video. TODO: Play all videos in room, as related videos? + class MatrixVideoPage : public Page { + public: + MatrixVideoPage(Program *program) : Page(program) {} + const char* get_title() const override { return ""; } + PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override { + (void)title; + (void)url; + (void)result_tabs; + return PluginResult::ERR; + } + PageTypez get_type() const override { return PageTypez::VIDEO; } + }; + + class MatrixChatPage : public Page { + public: + MatrixChatPage(Program *program, std::string room_id) : Page(program), room_id(std::move(room_id)) {} + const char* get_title() const override { return ""; } + PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override { + (void)title; + (void)url; + (void)result_tabs; + return PluginResult::ERR; + } + PageTypez get_type() const override { return PageTypez::CHAT; } + void update() override; + + const std::string room_id; + MatrixQuickMedia *matrix_delegate = nullptr; + }; + class Matrix { public: - PluginResult sync(RoomSyncData &room_sync_data); - void get_room_join_updates(Rooms &new_rooms); + void start_sync(MatrixDelegate *delegate); + void stop_sync(); + bool is_initial_sync_finished() const; + void get_room_sync_data(RoomData *room, SyncData &sync_data); + void get_all_synced_room_messages(RoomData *room, Messages &messages); void get_all_pinned_events(RoomData *room, std::vector &events); PluginResult get_previous_room_messages(RoomData *room, Messages &messages); // |url| should only be set when uploading media. // TODO: Make api better. - PluginResult post_message(RoomData *room, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info); + PluginResult post_message(RoomData *room, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info, const std::string &msgtype = ""); // |relates_to| is from |BodyItem.userdata| and is of type |Message*| PluginResult post_reply(RoomData *room, const std::string &body, void *relates_to); // |relates_to| is from |BodyItem.userdata| and is of type |Message*| @@ -201,28 +327,27 @@ namespace QuickMedia { // Returns nullptr if message cant be found. Note: cached std::shared_ptr get_message_by_id(RoomData *room, const std::string &event_id); + RoomData* get_room_by_id(const std::string &id); + bool use_tor = false; private: - PluginResult sync_response_to_body_items(const rapidjson::Document &root, RoomSyncData &room_sync_data); + PluginResult parse_sync_response(const rapidjson::Document &root, MatrixDelegate *delegate); + PluginResult parse_sync_account_data(const rapidjson::Value &account_data_json, std::optional> &dm_rooms); + PluginResult parse_sync_room_data(const rapidjson::Value &rooms_json, MatrixDelegate *delegate); PluginResult get_previous_room_messages(RoomData *room_data); void events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data); void events_add_user_read_markers(const rapidjson::Value &events_json, RoomData *room_data); - void events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncData *room_sync_data, bool has_unread_notifications); + void events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, MatrixDelegate *delegate, bool has_unread_notifications); void events_set_room_name(const rapidjson::Value &events_json, RoomData *room_data); - void events_add_pinned_events(const rapidjson::Value &events_json, RoomData *room_data, RoomSyncData &room_sync_data); - void events_add_room_to_tags(const rapidjson::Value &events_json, RoomData *room_data); + void events_add_pinned_events(const rapidjson::Value &events_json, RoomData *room_data); + void events_add_room_to_tags(const rapidjson::Value &events_json, RoomData *room_data, MatrixDelegate *delegate); std::shared_ptr parse_message_event(const rapidjson::Value &event_item_json, RoomData *room_data); PluginResult upload_file(RoomData *room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg); - - std::shared_ptr get_edited_message_original_message(RoomData *room_data, std::shared_ptr message); - - RoomData* get_room_by_id(const std::string &id); void add_room(std::unique_ptr room); DownloadResult download_json(rapidjson::Document &result, const std::string &url, std::vector additional_args, bool use_browser_useragent = false, std::string *err_msg = nullptr) const; private: std::vector> rooms; std::unordered_map room_data_by_id; // value is an index into |rooms| - std::map> rooms_by_tag_name; // value is an index into |rooms| size_t room_list_read_index = 0; std::mutex room_data_mutex; std::string user_id; @@ -231,5 +356,8 @@ namespace QuickMedia { std::string homeserver; std::optional upload_limit; std::string next_batch; + + std::thread sync_thread; + bool sync_running = false; }; } \ No newline at end of file -- cgit v1.2.3