Vaseker

CPP Lesson 2 Homework

Jan 19th, 2021
923
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Skillbox chat day 2.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
  2. //
  3.  
  4. #include <iostream>
  5. #include <uwebsockets/App.h>
  6.  
  7. using namespace std;
  8.  
  9. // START OF DAY 1
  10.  
  11. #include <regex>
  12. #include <algorithm>
  13.  
  14. map<string, string> knowledge = {
  15.     {"hello", "oh,. hello, human"},
  16.     {"what", "ChatBot ewfgwegwthth"},
  17.     {"how", "fine qgkqogk wffw"},
  18.     {"do", "Coding gqokgoqgkq"}
  19. };
  20.  
  21. string to_lower(string text) {
  22.     transform(text.begin(), text.end(), text.begin(), ::tolower);
  23.  
  24.     return text;
  25. }
  26.  
  27. string botAnswer(string question) {
  28.     string answer;
  29.  
  30.     question = to_lower(question);
  31.  
  32.     for (auto entry : knowledge) {
  33.         regex expression = regex(".*" + entry.first + ".*");
  34.  
  35.         if (answer.empty() && regex_match(question, expression)) {
  36.             // отвечаем на первый попавшийся знакомый вопрос
  37.             // пока не умею создавать массивы неизвестной длины, чтобы выдать N ответов
  38.             answer = entry.second;
  39.         }
  40.     }
  41.  
  42.     if (answer.empty()) {
  43.         answer = "Unknown command";
  44.     }
  45.  
  46.     return answer;
  47. }
  48.  
  49. // END OF DAY 1
  50.  
  51.  
  52. const string SET_NAME = "SET_NAME::";
  53. const string DIRECT = "DIRECT::";
  54.  
  55. bool isSetNameCommand(string_view message) {
  56.     return message.find(SET_NAME) == 0;
  57. }
  58.  
  59. bool isInvalidName(string_view message) {
  60.     const string name = string(message.substr(SET_NAME.length() + 2));
  61.  
  62.     if (name.find("::") != string::npos) {
  63.         return true;
  64.     }
  65.  
  66.     if (name.length() > 255) {
  67.         return true;
  68.     }
  69.  
  70.     return false;
  71. }
  72.  
  73. string parseName(string_view message) {
  74.     return string(message.substr(SET_NAME.length()));
  75. }
  76.  
  77. string parseReceiverId(string_view message) {
  78.     string_view rest = message.substr(DIRECT.length());
  79.     int pos = rest.find("::");
  80.     string_view id = rest.substr(0, pos);
  81.  
  82.     return string(id);
  83. }
  84.  
  85. string parseDirectMessage(string_view message) {
  86.     string_view rest = message.substr(DIRECT.length());
  87.     int pos = rest.find("::");
  88.     string_view text = rest.substr(pos + 2);
  89.  
  90.     return string(text);
  91. }
  92.  
  93. bool isDirectCommand(string_view message) {
  94.     return message.find(DIRECT) == 0;
  95. }
  96.  
  97. /* This is a simple WebSocket echo server example.
  98.  * You may compile it with "WITH_OPENSSL=1 make" or with "make" */
  99.  
  100. int main() {
  101.     /* ws->getUserData returns one of these */
  102.     struct PerSocketData {
  103.         /* Fill with user data */
  104.         int user_id;
  105.         string name;
  106.     };
  107.  
  108.     int last_user_id = 2;
  109.  
  110.     /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.
  111.      * You may swap to using uWS:App() if you don't need SSL */
  112.     //uWS::SSLApp({
  113.     //    /* There are example certificates in uWebSockets.js repo */
  114.     //    .key_file_name = "../misc/key.pem",
  115.     //    .cert_file_name = "../misc/cert.pem",
  116.     //    .passphrase = "1234"
  117.     //})
  118.     uWS::App()
  119.     .ws<PerSocketData>("/*", {
  120.         /* Settings */
  121.         .compression = uWS::SHARED_COMPRESSOR,
  122.         .maxPayloadLength = 16 * 1024,
  123.         .idleTimeout = 600,
  124.         .maxBackpressure = 1 * 1024 * 1024,
  125.         /* Handlers */
  126.         .upgrade = nullptr,
  127.         .open = [&last_user_id](auto* connection) {
  128.             /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */
  129.             cout << "New connection created" << endl;
  130.  
  131.             PerSocketData* userData = (PerSocketData*)connection->getUserData();
  132.  
  133.             userData->user_id = last_user_id++;
  134.             userData->name = "Unnamed";
  135.  
  136.             connection->subscribe("broadcast");
  137.             connection->subscribe("user#" + to_string(userData->user_id));
  138.  
  139.             connection->publish("broadcast", "Total users connected: " + to_string(last_user_id - 2));
  140.         },
  141.         .message = [&last_user_id](auto* connection, std::string_view message, uWS::OpCode opCode) {
  142.             cout << "New message received: " << message << endl;
  143.  
  144.             PerSocketData* userData = (PerSocketData*)connection->getUserData();
  145.  
  146.             if (isSetNameCommand(message)) {
  147.                 if (isInvalidName(message)) {
  148.                     cout << "ERROR: Trying to set invalid name\n";
  149.                     connection->publish("user#" + to_string(userData->user_id), "Name is invalid (contain :: or too long)");
  150.                 }
  151.                 else {
  152.                     cout << "User set their name\n";
  153.                     userData->name = parseName(message);
  154.                 }
  155.             }
  156.  
  157.             if (isDirectCommand(message)) {
  158.                 string receiver = parseReceiverId(message);
  159.                 string text = parseDirectMessage(message);
  160.                 int id = stoi(receiver);
  161.  
  162.                 const string selfChannel = "user#" + to_string(userData->user_id);
  163.  
  164.                 if (id > last_user_id || id < 1) {
  165.                     cout << "ERROR: User trying to send message to wrong id \n";
  166.  
  167.                     connection->publish(selfChannel, "Error, there is no user with ID = " + receiver);
  168.                 }
  169.                 else if (id == 1) {
  170.                     cout << "User sent direct message to BOT\n";
  171.  
  172.                     connection->publish(selfChannel, botAnswer(text));
  173.                 }
  174.                 else {
  175.                     cout << "User sent direct message\n";
  176.  
  177.                     connection->publish("user#" + receiver, text);
  178.                 }
  179.             }
  180.         },
  181.         .close = [](auto*/*ws*/, int /*code*/, std::string_view /*message*/) {
  182.             /* You may access ws->getUserData() here */
  183.             cout << "Connection closed" << endl;
  184.         }
  185.         //.drain = [](auto*/*ws*/) {
  186.         //    /* Check ws->getBufferedAmount() here */
  187.         //},
  188.         //.ping = [](auto*/*ws*/) {
  189.         //    /* Not implemented yet */
  190.         //},
  191.         //.pong = [](auto*/*ws*/) {
  192.         //    /* Not implemented yet */
  193.         //},
  194.     })
  195.     .listen(9001, [](auto* listen_socket) {
  196.         if (listen_socket) {
  197.             cout << "Listening on port " << 9001 << endl;
  198.         }
  199.     })
  200.     .run();
  201. }
RAW Paste Data