mutriz

git clone git://archive.git.mtrnord.blog/Nordgedanken/mutriz.git
Log | Files | Refs

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 }