#pragma once #include "../include/FileAnalyzer.hpp" #include "Plugin.hpp" #include "Page.hpp" #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; } bool is_video_page() const override { return true; } }; struct RoomData; struct UserInfo { friend struct RoomData; std::string user_id; std::string display_name; std::string avatar_url; sf::Color display_name_color; private: std::string read_marker_event_id; }; enum class MessageType { TEXT, IMAGE, VIDEO, AUDIO, FILE }; struct Message { std::shared_ptr user; std::string event_id; std::string body; std::string url; std::string thumbnail_url; std::string replaces_event_id; bool mentions_me = false; time_t timestamp = 0; MessageType type; }; struct RoomData { std::shared_ptr get_user_by_id(const std::string &user_id); void add_user(std::shared_ptr user); void set_user_read_marker(std::shared_ptr &user, const std::string &event_id); std::string get_user_read_marker(std::shared_ptr &user); // Ignores duplicates, returns the number of inserted elements size_t prepend_messages_reverse(std::vector> new_messages); // Ignores duplicates, returns the number of inserted elements size_t append_messages(std::vector> new_messages); std::shared_ptr get_message_by_id(const std::string &id); std::vector> get_users_excluding_me(const std::string &my_user_id); void acquire_room_lock(); void release_room_lock(); const std::vector>& get_messages_thread_unsafe() const; std::string id; std::string name; std::string avatar_url; std::string prev_batch; bool initial_fetch_finished = false; size_t last_read_index = 0; private: std::mutex user_mutex; std::mutex room_mutex; // Each room has its own list of user data, even if multiple rooms has the same user // because users can have different display names and avatars in different rooms. std::unordered_map> user_info_by_user_id; std::vector> messages; std::unordered_map> message_by_event_id; }; enum class MessageDirection { BEFORE, AFTER }; struct UploadInfo { ContentType content_type; size_t file_size; std::optional dimensions; std::optional duration_seconds; std::string content_uri; }; using RoomSyncMessages = std::unordered_map, std::vector>>; class Matrix { public: PluginResult sync(RoomSyncMessages &room_messages); PluginResult get_joined_rooms(BodyItems &result_items); PluginResult get_all_synced_room_messages(const std::string &room_id, BodyItems &result_items); PluginResult get_new_room_messages(const std::string &room_id, BodyItems &result_items); PluginResult get_previous_room_messages(const std::string &room_id, BodyItems &result_items); // |url| should only be set when uploading media. // TODO: Make api better. PluginResult post_message(const std::string &room_id, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info); // |relates_to| is from |BodyItem.userdata| and is of type |Message*| PluginResult post_reply(const std::string &room_id, const std::string &body, void *relates_to); // |relates_to| is from |BodyItem.userdata| and is of type |Message*| PluginResult post_edit(const std::string &room_id, const std::string &body, void *relates_to); PluginResult post_file(const std::string &room_id, const std::string &filepath, std::string &err_msg); PluginResult login(const std::string &username, const std::string &password, const std::string &homeserver, std::string &err_msg); PluginResult logout(); // |message| is from |BodyItem.userdata| and is of type |Message*| PluginResult delete_message(const std::string &room_id, void *message, std::string &err_msg); PluginResult load_and_verify_cached_session(); PluginResult on_start_typing(const std::string &room_id); PluginResult on_stop_typing(const std::string &room_id); PluginResult set_read_marker(const std::string &room_id, const Message *message); // |message| is from |BodyItem.userdata| and is of type |Message*| bool was_message_posted_by_me(void *message); std::string message_get_author_displayname(Message *message) const; // Cached PluginResult get_config(int *upload_size); std::shared_ptr get_me(const std::string &room_id); bool use_tor = false; private: PluginResult sync_response_to_body_items(const rapidjson::Document &root, RoomSyncMessages &room_messages); PluginResult get_previous_room_messages(std::shared_ptr &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, std::shared_ptr &room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications); void events_set_room_name(const rapidjson::Value &events_json, RoomData *room_data); PluginResult upload_file(const std::string &room_id, 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); std::shared_ptr get_room_by_id(const std::string &id); void add_room(std::shared_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::unordered_map> room_data_by_id; std::mutex room_data_mutex; std::string user_id; std::string username; std::string access_token; std::string homeserver; std::optional upload_limit; std::string next_batch; }; }