| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | ** EPITECH PROJECT, 2024 | ||
| 3 | ** zappy/ai/client | ||
| 4 | ** File description: | ||
| 5 | ** Client.cpp | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "Client.hpp" | ||
| 9 | |||
| 10 | ✗ | Client::Client(const std::string &host, const std::string &teamName, int port) | |
| 11 | ✗ | : _host(host), _teamName(teamName), _port(port) | |
| 12 | { | ||
| 13 | ✗ | setupConnection(); | |
| 14 | ✗ | } | |
| 15 | |||
| 16 | ✗ | Client::~Client() | |
| 17 | { | ||
| 18 | ✗ | close(_sockfd); | |
| 19 | ✗ | } | |
| 20 | |||
| 21 | ✗ | void Client::run() | |
| 22 | { | ||
| 23 | ✗ | printColor("Run client\n\n", BRIGHT_BLUE); | |
| 24 | |||
| 25 | ✗ | authenticate(); | |
| 26 | ✗ | loop(); | |
| 27 | } | ||
| 28 | |||
| 29 | ✗ | void Client::setupConnection() | |
| 30 | { | ||
| 31 | ✗ | _sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
| 32 | ✗ | if (_sockfd < 0) | |
| 33 | { | ||
| 34 | ✗ | perror("Socket creation failed"); | |
| 35 | ✗ | exit(EXIT_FAILURE); | |
| 36 | } | ||
| 37 | |||
| 38 | ✗ | struct sockaddr_in serv_addr; | |
| 39 | |||
| 40 | ✗ | serv_addr.sin_family = AF_INET; | |
| 41 | ✗ | serv_addr.sin_port = htons(_port); | |
| 42 | ✗ | if (inet_pton(AF_INET, _host.c_str(), &serv_addr.sin_addr) <= 0) | |
| 43 | { | ||
| 44 | ✗ | perror("Invalid address or address not supported"); | |
| 45 | ✗ | exit(EXIT_FAILURE); | |
| 46 | } | ||
| 47 | ✗ | if (connect(_sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) | |
| 48 | { | ||
| 49 | ✗ | perror("Connection failed"); | |
| 50 | ✗ | exit(EXIT_FAILURE); | |
| 51 | } | ||
| 52 | else | ||
| 53 | ✗ | printColor("🚀✅ Connected to server: " + _host + ":" + std::to_string(_port) + " on team: " + _teamName + "\n", BRIGHT_BLUE); | |
| 54 | ✗ | } | |
| 55 | |||
| 56 | ✗ | void Client::authenticate() | |
| 57 | { | ||
| 58 | std::string buffer; | ||
| 59 | ✗ | Message _message; | |
| 60 | ✗ | unsigned int timeToGetIdentity = 0; | |
| 61 | ✗ | std::string askForIdentity = ""; | |
| 62 | |||
| 63 | // To pass the first message WELCOME | ||
| 64 | ✗ | recvMessage(buffer); | |
| 65 | |||
| 66 | // Ask two time for identity | ||
| 67 | ✗ | _message.format("I'm_searching_my_identity"); | |
| 68 | ✗ | askForIdentity = "Broadcast " + _message.content; | |
| 69 | ✗ | sendMessage(_teamName); | |
| 70 | ✗ | sendMessage(askForIdentity); | |
| 71 | ✗ | sendMessage(askForIdentity); | |
| 72 | _message.content = ""; | ||
| 73 | |||
| 74 | auto condition = [&]() | ||
| 75 | ✗ | { return timeToGetIdentity < 3; }; | |
| 76 | |||
| 77 | ✗ | auto action = [&]() | |
| 78 | { | ||
| 79 | std::string response; | ||
| 80 | ✗ | recvMessage(response); | |
| 81 | ✗ | if (response.find("ko") != std::string::npos) | |
| 82 | { | ||
| 83 | ✗ | PRINT_ERROR("Authentication failed: verify teamName"); | |
| 84 | ✗ | close(_sockfd); | |
| 85 | ✗ | exit(EXIT_FAILURE); | |
| 86 | } | ||
| 87 | ✗ | if (response.find("message") != std::string::npos) | |
| 88 | { | ||
| 89 | ✗ | _message.content = response; | |
| 90 | ✗ | _message.vigenereDecrypt(); | |
| 91 | return; | ||
| 92 | } | ||
| 93 | ✗ | timeToGetIdentity++; | |
| 94 | ✗ | _messageToReadBeforeStart--; | |
| 95 | ✗ | }; | |
| 96 | ✗ | interactWithServer(condition, action); | |
| 97 | try | ||
| 98 | { | ||
| 99 | ✗ | initBot(_message.content); | |
| 100 | } | ||
| 101 | ✗ | catch (const ClientException &e) | |
| 102 | { | ||
| 103 | ✗ | PRINT_ERROR(e.what()); | |
| 104 | ✗ | close(_sockfd); | |
| 105 | ✗ | exit(EXIT_FAILURE); | |
| 106 | ✗ | } | |
| 107 | ✗ | } | |
| 108 | |||
| 109 | ✗ | void Client::initBot(const std::string identityMessage) | |
| 110 | { | ||
| 111 | unsigned int id = 0; | ||
| 112 | unsigned int currentMessageId = 0; | ||
| 113 | |||
| 114 | ✗ | if (!identityMessage.empty()) | |
| 115 | { | ||
| 116 | ✗ | std::cout << "identityMessage: " << identityMessage << std::endl; | |
| 117 | ✗ | std::string job = ""; | |
| 118 | ✗ | std::string prefixId = "you_are_bot="; | |
| 119 | ✗ | std::string prefixJob = "your_job="; | |
| 120 | ✗ | std::string prefixCurrentMessageId = "currentMessageId="; | |
| 121 | size_t pos = identityMessage.find(prefixId); | ||
| 122 | size_t posJob = identityMessage.find(prefixJob); | ||
| 123 | size_t posCurrentMessageId = identityMessage.find(prefixCurrentMessageId); | ||
| 124 | |||
| 125 | ✗ | if (pos != std::string::npos) | |
| 126 | { | ||
| 127 | ✗ | std::string idStr = identityMessage.substr(pos + prefixId.size()); | |
| 128 | ✗ | id = std::stoi(idStr); | |
| 129 | } | ||
| 130 | ✗ | if (posCurrentMessageId != std::string::npos) | |
| 131 | { | ||
| 132 | ✗ | std::string currentMessageIdStr = identityMessage.substr(posCurrentMessageId + prefixCurrentMessageId.size()); | |
| 133 | ✗ | currentMessageId = std::stoi(currentMessageIdStr); | |
| 134 | } | ||
| 135 | ✗ | if (posJob != std::string::npos) | |
| 136 | { | ||
| 137 | ✗ | job = identityMessage.substr(posJob + prefixJob.size()); | |
| 138 | ✗ | if (job.find("SIMPLE_BOT") != std::string::npos) | |
| 139 | ✗ | _bot = BotFactory::createBot("SimpleBot"); | |
| 140 | } | ||
| 141 | else | ||
| 142 | { | ||
| 143 | ✗ | _bot = BotFactory::createBot("SimpleBot"); | |
| 144 | } | ||
| 145 | } | ||
| 146 | else | ||
| 147 | { | ||
| 148 | ✗ | _bot = BotFactory::createBot("SimpleBot"); // TODO: is forker normally | |
| 149 | ✗ | if (_bot == nullptr) | |
| 150 | ✗ | throw ClientException("BotFactory failed"); | |
| 151 | } | ||
| 152 | ✗ | if (_bot != nullptr) | |
| 153 | { | ||
| 154 | ✗ | _bot->init(_sockfd, _teamName, _host, _port, id, currentMessageId); | |
| 155 | } | ||
| 156 | else | ||
| 157 | { | ||
| 158 | ✗ | throw ClientException("Bot is null"); | |
| 159 | } | ||
| 160 | ✗ | } | |
| 161 | |||
| 162 | ✗ | void Client::sendMessage(const std::string &message) | |
| 163 | { | ||
| 164 | ✗ | std::string messageToSend = message + "\n"; | |
| 165 | |||
| 166 | ✗ | send(_sockfd, messageToSend.c_str(), messageToSend.size(), 0); | |
| 167 | ✗ | } | |
| 168 | |||
| 169 | ✗ | void Client::loop() | |
| 170 | { | ||
| 171 | // clear messsages of servers before start | ||
| 172 | auto condition = [&]() | ||
| 173 | ✗ | { return _messageToReadBeforeStart > 0; }; | |
| 174 | ✗ | auto action = [&]() | |
| 175 | { | ||
| 176 | std::string response; | ||
| 177 | ✗ | recvMessage(response); | |
| 178 | ✗ | _messageToReadBeforeStart--; | |
| 179 | ✗ | }; | |
| 180 | ✗ | interactWithServer(condition, action); | |
| 181 | |||
| 182 | ✗ | _bot->run("start"); | |
| 183 | auto conditionStart = [&]() | ||
| 184 | { return true; }; | ||
| 185 | ✗ | auto actionStart = [&]() | |
| 186 | { | ||
| 187 | std::string response; | ||
| 188 | ✗ | recvMessage(response); | |
| 189 | ✗ | _bot->run(response); | |
| 190 | ✗ | }; | |
| 191 | ✗ | interactWithServer(conditionStart, actionStart); | |
| 192 | } | ||
| 193 | |||
| 194 | ✗ | void Client::recvMessage(std::string &buffer) | |
| 195 | { | ||
| 196 | ✗ | char recvBuffer[1024] = {0}; | |
| 197 | ✗ | int valread = read(_sockfd, recvBuffer, 1024); | |
| 198 | |||
| 199 | ✗ | if (valread < 0) | |
| 200 | { | ||
| 201 | ✗ | PRINT_ERROR("Read failed"); | |
| 202 | ✗ | close(_sockfd); | |
| 203 | ✗ | exit(FAILURE); | |
| 204 | } | ||
| 205 | ✗ | else if (valread == 0) | |
| 206 | { | ||
| 207 | ✗ | PRINT_ERROR("Server closed the connection"); | |
| 208 | ✗ | close(_sockfd); | |
| 209 | ✗ | exit(FAILURE); | |
| 210 | } | ||
| 211 | |||
| 212 | ✗ | buffer = std::string(recvBuffer, valread); | |
| 213 | ✗ | } | |
| 214 | |||
| 215 | template <typename ConditionFunc, typename ActionFunc> | ||
| 216 | ✗ | void Client::interactWithServer(ConditionFunc condition, ActionFunc action) | |
| 217 | { | ||
| 218 | ✗ | while (condition()) | |
| 219 | { | ||
| 220 | ✗ | FD_ZERO(&_readfds); | |
| 221 | ✗ | FD_SET(_sockfd, &_readfds); | |
| 222 | ✗ | _tv.tv_sec = 0; | |
| 223 | ✗ | _tv.tv_usec = 10000; | |
| 224 | ✗ | int activity = select(_sockfd + 1, &_readfds, NULL, NULL, &_tv); | |
| 225 | |||
| 226 | ✗ | if (activity > 0 && FD_ISSET(_sockfd, &_readfds)) | |
| 227 | ✗ | action(); | |
| 228 | } | ||
| 229 | ✗ | } | |
| 230 |