Advertisement
Guest User

Untitled

a guest
Aug 13th, 2022
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.78 KB | None | 0 0
  1. #include <iostream>
  2. #include <uwebsockets/App.h>
  3. #include <nlohmann/json.hpp>
  4. using namespace std;
  5. using json = nlohmann::json;
  6.  
  7. const string PRIVATE_MSG = "PRIVATE_MSG";
  8. const string PUBLIC_MSG = "PUBLIC_MSG";
  9. const string STATUS = "STATUS";
  10. const string SET_NAME = "SET_NAME";
  11. const string PUBLIC_CHANNEL = "PUBLIC_CHANNEL";
  12.  
  13. // Структура, где мы будем хранить информацию о каждом подключившемся
  14. struct UserData {
  15.     int id;
  16.     string name;
  17. };
  18.  
  19. // Чтобы записывать типы покороче
  20. typedef uWS::WebSocket<false, true, UserData>* websock;
  21. string personal_channel(UserData* data);
  22. // Карта, ключ = айди пользователя, значения = данные пользователя
  23. map<int, UserData*> all_users;
  24.  
  25. // "отправить приватное сообщение" = PRIVATE_MSG
  26. // JSON {"command": "PRIVATE_MSG", "user_to": 11, "text" : "Эй привет 11ый!"}
  27. void process_private_msg(websock ws, json parsed_data) {
  28.     UserData* data = ws->getUserData(); // Получаем информацию о текущему пользовале
  29.  
  30.     json payload;
  31.     payload["command"] = PRIVATE_MSG;
  32.     payload["user_from"] = data->id;
  33.     payload["text"] = parsed_data["text"];
  34.    
  35.     //ToDO check if user exists
  36.     UserData* recepient = all_users[parsed_data["user_to"]];
  37.  
  38.     ws->publish(personal_channel(recepient), payload.dump());
  39. }
  40.  
  41. // JSON {"command": "PUBLIC_MSG", "text" : "Всем приветы в этом чате!"}
  42. void process_public_msg(websock ws, json parsed_data) {
  43.     UserData* data = ws->getUserData();
  44.  
  45.     json payload = {
  46.         {"command", PUBLIC_MSG },
  47.         {"text", parsed_data["text"]},
  48.         {"user_from", data->id}
  49.     };
  50.  
  51.     ws->publish(PUBLIC_CHANNEL, payload.dump());
  52. }
  53.  
  54. // Кто в онлайне, а кто в оффлайне?
  55. // {"command": "STATUS", "online": True/False, "user_id": 10}
  56. string user_status(UserData* data, bool online) {
  57.     json payload = {
  58.         {"command", STATUS},
  59.         {"online", online},
  60.         {"user_id", data->id},
  61.         {"name", data->name}
  62.     };
  63.     return payload.dump();
  64. }
  65.  
  66. // {"command":"SET_NAME", "name": "AKOKO"}
  67. void process_set_name(websock ws, json parsed_data) {
  68.     UserData* data = ws->getUserData();
  69.     data->name = parsed_data["name"]; // Обновляем имя
  70.  
  71.     ws->publish(PUBLIC_CHANNEL, user_status(data, true)); // Всем сообщаем
  72. }
  73.  
  74. string personal_channel(UserData* data) {
  75.     return "USER_" + to_string(data->id);
  76. }
  77.  
  78.  
  79.  
  80.  
  81. int main()
  82. {
  83.     int latest_user_id = 10; // ID последнего подключившегося
  84.     uWS::App app = uWS::App(); // Создали приложение
  85.    
  86.     // Создали раздел "/" на сайте
  87.     app.get("/", [](auto *response, auto *request) {
  88.         response->writeHeader("Content-Type", "text/html; charset=utf-8"); // Отдаем ХТМЛ
  89.         response->end("Hello, this is <b>SkillChat</b> Server C++ 5000"); // <- Вот этот ХТМЛ
  90.     });
  91.     // [0-1000] [ 1001-3000]
  92.     app.ws<UserData>("/*", {
  93.         // "[]() {}" - Лямбда - функция
  94.         // открытие соединения
  95.         // Назначить ID
  96.         // Сообщить всем что человек (такой-то) подключился
  97.         .open = [&latest_user_id](websock ws) {
  98.             UserData* data = ws->getUserData(); // Получаем данные пользователя
  99.             data->id = latest_user_id++; // Каждому следующему подключив. будет назначен следующий АЙди
  100.            
  101.             data->name = "UnnamedUser#" + to_string(data->id); // Даем временное имя
  102.            
  103.             all_users[data->id] = data; // Положить информацию о пользователе в карту
  104.  
  105.             cout << "New user connected: " << data->id << endl;
  106.  
  107.             ws->subscribe(personal_channel(data)); // Каждого пользователя подписываем на личный канал
  108.  
  109.             ws->publish(PUBLIC_CHANNEL, user_status(data, true)); // Уведомляем всех что "новичок" подключился
  110.  
  111.             ws->subscribe(PUBLIC_CHANNEL); // Всех-всех-всех подписываем на публичный канал
  112.  
  113.             for (auto item : all_users) {
  114.                 //item.second UserData*
  115.                 //item.first int == id
  116.                 ws->send(user_status(item.second, true), uWS::OpCode::TEXT);
  117.             }
  118.             // ToDo: уведомим новичка о всех "старичках" в чате
  119.         },
  120.         // при получении информации от клиента
  121.         // "отправить публичное сообщение" = PUBLIC_MSG
  122.         // "представиться" = SET_NAME
  123.  
  124.         .message = [](websock ws, string_view message, uWS::OpCode opcode) {
  125.            
  126.             json parsed_data;
  127.             try {
  128.                 parsed_data = json::parse(message); // Распарсить JSON
  129.             }
  130.             catch (const json::parse_error& err) {
  131.                 cout << err.what() << endl;
  132.                 return;
  133.             }
  134.             string command = parsed_data["command"];
  135.  
  136.             cout << "Got command " << command << endl;
  137.  
  138.             if (command == PRIVATE_MSG) {
  139.                 process_private_msg(ws, parsed_data);
  140.             }
  141.  
  142.             if (command == PUBLIC_MSG) {
  143.                 process_public_msg(ws, parsed_data);
  144.             }
  145.  
  146.             if (command == SET_NAME) {
  147.                 process_set_name(ws, parsed_data);
  148.             }
  149.             // ToDo: command "SET_NAME"
  150.         },
  151.         // при закрытии соединения
  152.         // Сообщить всем что человек (такой-то) отключился
  153.         .close = [&app](websock ws, int, string_view) {
  154.             UserData* data = ws->getUserData();
  155.             // ToDo: Всем сообщить что пользователь отключился
  156.             app.publish(PUBLIC_CHANNEL, user_status(data, false), uWS::OpCode::TEXT);
  157.             all_users.erase(data->id); // Стираем пользователя
  158.         },
  159.     });
  160.    
  161.     app.listen(9001, [](auto *) {});
  162.     app.run();
  163. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement