1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
#pragma once
#include "../include/FileAnalyzer.hpp"
#include "Plugin.hpp"
#include <unordered_map>
#include <json/value.h>
namespace QuickMedia {
struct UserInfo {
std::string user_id;
std::string display_name;
std::string avatar_url;
sf::Color display_name_color;
};
enum class MessageType {
TEXT,
IMAGE,
VIDEO,
AUDIO,
FILE
};
struct Message {
// Index into |RoomData.user_info|
size_t user_id;
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::string id;
// 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.
// The value is an index to |user_info|.
std::unordered_map<std::string, size_t> user_info_by_user_id;
std::vector<UserInfo> user_info;
std::vector<std::shared_ptr<Message>> messages;
std::unordered_map<std::string, std::shared_ptr<Message>> message_by_event_id;
std::string name;
std::string avatar_url;
std::string prev_batch;
bool initial_fetch_finished = false;
size_t last_read_index = 0;
};
enum class MessageDirection {
BEFORE,
AFTER
};
struct UploadInfo {
ContentType content_type;
size_t file_size;
std::optional<Dimensions> dimensions;
std::optional<double> duration_seconds;
std::string content_uri;
};
using RoomSyncMessages = std::unordered_map<RoomData*, std::vector<std::shared_ptr<Message>>>;
class Matrix : public Plugin {
public:
Matrix();
virtual ~Matrix() = default;
bool search_is_filter() override { return true; }
bool search_suggestions_has_thumbnails() const override { return true; }
bool search_results_has_thumbnails() const override { return false; }
int get_search_delay() const override { return 0; }
bool search_suggestion_is_search() const override { return true; }
Page get_page_after_search() const override { return Page::EXIT; }
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);
SearchResult search(const std::string &text, BodyItems &result_items) override;
// |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<UploadInfo> &file_info, const std::optional<UploadInfo> &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(const std::string &room_id, void *message) const;
std::string message_get_author_displayname(RoomData *room_data, Message *message) const;
// Cached
PluginResult get_config(int *upload_size);
private:
PluginResult sync_response_to_body_items(const Json::Value &root, RoomSyncMessages &room_messages);
PluginResult get_previous_room_messages(const std::string &room_id, RoomData *room_data);
void events_add_user_info(const Json::Value &events_json, RoomData *room_data);
void events_add_messages(const Json::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications);
void events_set_room_name(const Json::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<Message> get_edited_message_original_message(RoomData *room_data, std::shared_ptr<Message> message);
private:
std::unordered_map<std::string, std::unique_ptr<RoomData>> room_data_by_id;
std::string user_id;
std::string username;
std::string access_token;
std::string homeserver;
std::optional<int> upload_limit;
std::string next_batch;
};
}
|