main.cpp (7067B)
1 #include <boost/beast.hpp> 2 #include <iostream> 3 #ifdef WIN32 4 #include <windows.h> 5 #else 6 #include <cstdlib> 7 #endif 8 #include <variant.hpp> 9 10 #include "client.hpp" 11 #include "errors.hpp" 12 #include "mtx.hpp" 13 14 // 15 // Simple usage example of the /login & /sync endpoints which 16 // will print the stream of messages from all rooms as received by the client. 17 // 18 19 using namespace std; 20 using namespace mtx::client; 21 using namespace mtx::events; 22 23 using TimelineEvent = mtx::events::collections::TimelineEvents; 24 25 void 26 print_errors(RequestErr err) 27 { 28 if (err->status_code != boost::beast::http::status::unknown) 29 cout << err->status_code << "\n"; 30 if (!err->matrix_error.error.empty()) 31 cout << err->matrix_error.error << "\n"; 32 if (err->error_code) 33 cout << err->error_code.message() << "\n"; 34 } 35 36 // Check if the given event has a textual representation. 37 bool 38 is_room_message(const TimelineEvent &event) 39 { 40 return mpark::holds_alternative<mtx::events::RoomEvent<msg::Audio>>(event) || 41 mpark::holds_alternative<mtx::events::RoomEvent<msg::Emote>>(event) || 42 mpark::holds_alternative<mtx::events::RoomEvent<msg::File>>(event) || 43 mpark::holds_alternative<mtx::events::RoomEvent<msg::Image>>(event) || 44 mpark::holds_alternative<mtx::events::RoomEvent<msg::Notice>>(event) || 45 mpark::holds_alternative<mtx::events::RoomEvent<msg::Text>>(event) || 46 mpark::holds_alternative<mtx::events::RoomEvent<msg::Video>>(event); 47 } 48 49 // Retrieves the fallback body value from the event. 50 std::string 51 get_body(const TimelineEvent &event) 52 { 53 if (mpark::holds_alternative<RoomEvent<msg::Audio>>(event)) 54 return mpark::get<RoomEvent<msg::Audio>>(event).content.body; 55 else if (mpark::holds_alternative<RoomEvent<msg::Emote>>(event)) 56 return mpark::get<RoomEvent<msg::Emote>>(event).content.body; 57 else if (mpark::holds_alternative<RoomEvent<msg::File>>(event)) 58 return mpark::get<RoomEvent<msg::File>>(event).content.body; 59 else if (mpark::holds_alternative<RoomEvent<msg::Image>>(event)) 60 return mpark::get<RoomEvent<msg::Image>>(event).content.body; 61 else if (mpark::holds_alternative<RoomEvent<msg::Notice>>(event)) 62 return mpark::get<RoomEvent<msg::Notice>>(event).content.body; 63 else if (mpark::holds_alternative<RoomEvent<msg::Text>>(event)) 64 return mpark::get<RoomEvent<msg::Text>>(event).content.body; 65 else if (mpark::holds_alternative<RoomEvent<msg::Video>>(event)) 66 return mpark::get<RoomEvent<msg::Video>>(event).content.body; 67 68 return ""; 69 } 70 71 // Retrieves the sender of the event. 72 std::string 73 get_sender(const TimelineEvent &event) 74 { 75 return mpark::visit([](auto e) { return e.sender; }, event); 76 } 77 78 // Simple print of the message contents. 79 void 80 print_message(const TimelineEvent &event) 81 { 82 if (is_room_message(event)) 83 cout << get_sender(event) << ": " << get_body(event) << "\n"; 84 } 85 86 // Callback to executed after a /sync request completes. 87 void 88 sync_handler(shared_ptr<Client> client, const mtx::responses::Sync &res, RequestErr err) 89 { 90 if (err) { 91 cout << "sync error:\n"; 92 print_errors(err); 93 94 client->sync( 95 "", 96 client->next_batch_token(), 97 false, 98 30000, 99 std::bind(&sync_handler, client, std::placeholders::_1, std::placeholders::_2)); 100 101 return; 102 } 103 104 for (const auto room : res.rooms.join) { 105 for (const auto msg : room.second.timeline.events) 106 print_message(msg); 107 } 108 109 client->set_next_batch_token(res.next_batch); 110 111 client->sync( 112 "", 113 client->next_batch_token(), 114 false, 115 30000, 116 std::bind(&sync_handler, client, std::placeholders::_1, std::placeholders::_2)); 117 } 118 119 // Callback to executed after the first (initial) /sync request completes. 120 void 121 initial_sync_handler(shared_ptr<Client> client, const nlohmann::json &res, RequestErr err) 122 { 123 if (err) { 124 cout << "error during initial sync:\n"; 125 print_errors(err); 126 127 if (err->status_code != boost::beast::http::status::ok) { 128 cout << "retrying initial sync ...\n"; 129 client->sync("", 130 "", 131 false, 132 0, 133 std::bind(&initial_sync_handler, 134 client, 135 std::placeholders::_1, 136 std::placeholders::_2)); 137 } 138 139 return; 140 } 141 142 client->set_next_batch_token(res.at("next_batch")); 143 144 client->sync( 145 "", 146 client->next_batch_token(), 147 false, 148 30000, 149 std::bind(&sync_handler, client, std::placeholders::_1, std::placeholders::_2)); 150 } 151 152 #ifdef WIN32 153 string getpassword(const char *prompt, bool show_asterisk=true) 154 { 155 const char BACKSPACE=8; 156 const char RETURN=13; 157 158 string password; 159 unsigned char ch=0; 160 161 cout <<prompt<<endl; 162 163 DWORD con_mode; 164 DWORD dwRead; 165 166 HANDLE hIn=GetStdHandle(STD_INPUT_HANDLE); 167 168 GetConsoleMode( hIn, &con_mode ); 169 SetConsoleMode( hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT) ); 170 171 while(ReadConsoleA( hIn, &ch, 1, &dwRead, NULL) && ch !=RETURN) 172 { 173 if(ch==BACKSPACE) 174 { 175 if(password.length()!=0) 176 { 177 if(show_asterisk) 178 cout <<"\b \b"; 179 password.resize(password.length()-1); 180 } 181 } 182 else 183 { 184 password+=ch; 185 if(show_asterisk) 186 cout <<'*'; 187 } 188 } 189 cout <<endl; 190 return password; 191 } 192 #else 193 string getpassword(const char *prompt, bool show_asterisk=true) 194 { 195 return getpass("Password: "); 196 } 197 #endif 198 199 int 200 main() 201 { 202 std::string username, server, password; 203 204 cout << "Username: "; 205 std::getline(std::cin, username); 206 207 cout << "HomeServer: "; 208 std::getline(std::cin, server); 209 210 password = getpassword("Password: "); 211 212 auto client = std::make_shared<Client>(server); 213 214 client->login( 215 username, password, [client](const mtx::responses::Login &res, RequestErr err) { 216 if (err) { 217 cout << "There was an error during login: " << err->matrix_error.error 218 << "\n"; 219 return; 220 } 221 222 cout << "Logged in as: " << res.user_id.to_string() << "\n"; 223 client->set_access_token(res.access_token); 224 225 client->sync( 226 "", 227 "", 228 false, 229 0, 230 std::bind( 231 &initial_sync_handler, client, std::placeholders::_1, std::placeholders::_2)); 232 }); 233 234 client->close(); 235 236 return 0; 237 }