#include "ClientManager/ClientManager.hpp" #include "Utils/ConfigManager.hpp" #include "Utils/StringTokenizer.hpp" #include "Socket/Log.hpp" #include namespace Chattr { void ClientManager::_IOCPClient(Chattr::ThreadPool* thread, Chattr::IOCPPASSINDATA* data) { if (data->event == IOCPEVENT::QUIT) { delete data; return; } Chattr::Packet pack; int packetSize = data->transferredbytes; if (data->event == IOCPEVENT::WRITE && data->transferredbytes >= data->wsabuf.len) { data->event = IOCPEVENT::READ; data->wsabuf.len = 1500; data->IOCPInstance->recv(data, 1); return; } memcpy(pack.serialized, data->wsabuf.buf, data->wsabuf.len); std::uint16_t packetLength = ::ntohs(pack.__data.packetLength); // if (data->event == IOCPEVENT::READ && data->transferredbytes < packetLength + 8) { // data->IOCPInstance->recv(data, 1); // data->wsabuf.len = 1500; // return; // } pack.convToH(); PacketSet packetSet = packetParser(pack); pack.convToN(); switch (packetSet) { case PacketSet::LOGINRESPONSE: { LoginResponsePacket loginResponsePacket; std::memcpy(&loginResponsePacket.serialized, &pack.serialized, 8 + packetLength); loginResponsePacket.convToH(); lastResponsePacket_ = std::future(); auto promise = std::promise(); lastResponsePacket_ = promise.get_future(); promise.set_value(loginResponsePacket); processLoginResponsePacket(loginResponsePacket, data); } break; case PacketSet::ROOMCREATERESPONSE: case PacketSet::ROOMLISTRESPONSE: case PacketSet::ROOMJOINRESPONSE: case PacketSet::ROOMEXITRESPONSE: case PacketSet::USERSLISTRESPONSE: { UsersListResponsePacket usersListResponsePacket; std::memcpy(&usersListResponsePacket.serialized, &pack.serialized, 8 + packetLength); usersListResponsePacket.convToH(); lastResponsePacket_ = std::future(); auto promise = std::promise(); lastResponsePacket_ = promise.get_future(); promise.set_value(usersListResponsePacket); processUsersListResponsePacket(usersListResponsePacket, data); } case PacketSet::RESPONSE: { ResponsePacket responsePacket; std::memcpy(&responsePacket.serialized, &pack.serialized, 8 + packetLength); responsePacket.convToH(); lastResponsePacket_ = std::future(); auto promise = std::promise(); lastResponsePacket_ = promise.get_future(); promise.set_value(responsePacket); processResponsePacket(responsePacket, data); } break; case PacketSet::DATAPOST: { DataPostPacket dataPostPacket; std::memcpy(&dataPostPacket.serialized, &pack.serialized, 8 + packetLength); dataPostPacket.convToH(); processDataPostPacket(dataPostPacket, data); } break; case PacketSet::CONTINUE: { ContinuePacket continuePacket; std::memcpy(&continuePacket.serialized, &pack.serialized, 8 + packetLength); continuePacket.convToH(); processContinuePacket(continuePacket, data); } break; case PacketSet::INVALID: default: { } break; } iocp_.recv(data_, 1); } PacketSet ClientManager::packetParser(Packet Packet) { if (Packet.__data.packetLength < 0 || Packet.__data.packetLength > 1492) return PacketSet::INVALID; switch (Packet.__data.packetType) { case PacketCategory::PACKET_POST: if (Packet.__data.requestType != RequestType::DATA) { return PacketSet::INVALID; } switch (Packet.__data.dataType) { case DataType::TEXT: case DataType::BINARY: return PacketSet::DATAPOST; default: return PacketSet::INVALID; } break; case PacketCategory::PACKET_REQUEST: switch (Packet.__data.requestType) { case RequestType::LOGIN: return PacketSet::LOGINREQUEST; case RequestType::ROOM_CREATE: return PacketSet::ROOMCREATEREQUEST; case RequestType::ROOM_LIST: return PacketSet::ROOMLISTREQUEST; case RequestType::ROOM_JOIN: return PacketSet::ROOMJOINREQUEST; case RequestType::ROOM_EXIT: return PacketSet::ROOMEXITREQUEST; case RequestType::USERS_LIST: return PacketSet::USERSLISTREQUEST; case RequestType::DATA: return PacketSet::INVALID; } break; case PacketCategory::PACKET_RESPONSE: switch (Packet.__data.requestType) { case RequestType::LOGIN: return PacketSet::LOGINRESPONSE; case RequestType::ROOM_CREATE: return PacketSet::ROOMCREATERESPONSE; case RequestType::ROOM_LIST: return PacketSet::ROOMLISTRESPONSE; case RequestType::ROOM_JOIN: return PacketSet::ROOMJOINRESPONSE; case RequestType::ROOM_EXIT: return PacketSet::ROOMEXITRESPONSE; case RequestType::USERS_LIST: return PacketSet::USERSLISTRESPONSE; case RequestType::DATA: return PacketSet::RESPONSE; default: return PacketSet::INVALID; } break; case PacketCategory::PACKET_CONTINUE: return PacketSet::CONTINUE; default: return PacketSet::INVALID; } return PacketSet::INVALID; } void ClientManager::processResponsePacket(ResponsePacket responsePacket, IOCPPASSINDATA* data) { responsePacket; } void ClientManager::processLoginResponsePacket(LoginResponsePacket loginResponsePacket, IOCPPASSINDATA* data) { ::memcpy(&myID_.snowflake, loginResponsePacket.__data.yourId, sizeof(Snowflake)); } void ClientManager::processRoomCreateResponsePacket(RoomCreateResponsePacket roomCreateResponsePacket, Chattr::IOCPPASSINDATA* data) { } void ClientManager::processRoomListResponse(RoomListResponsePacket roomListResponsePacket, Chattr::IOCPPASSINDATA* data) { } void ClientManager::processRoomJoinResponsePacket(RoomJoinResponsePacket roomJoinResponsePacket, Chattr::IOCPPASSINDATA* data) { } void ClientManager::processRoomExitResponsePacket(RoomExitResponsePacket roomExitResponsePacket, Chattr::IOCPPASSINDATA* data) { } void ClientManager::processUsersListResponsePacket(UsersListResponsePacket usersListResponsePacket, Chattr::IOCPPASSINDATA* data) { Snowflake userId; ::memcpy(&userId.snowflake, usersListResponsePacket.__data.userId, sizeof(Snowflake)); std::string userName((char*)usersListResponsePacket.__data.name, usersListResponsePacket.__data.packetLength - (sizeof(std::uint16_t) * 7)); userNames_[userId] = userName; findUserId_[userName] = userId; spdlog::info("{}", userName); } void ClientManager::processDataPostPacket(DataPostPacket dataPostPacket, IOCPPASSINDATA* data) { Snowflake sentUserId; ::memcpy(&sentUserId.snowflake, dataPostPacket.__data.destId, sizeof(Snowflake)); std::string sentUserName = userNames_[sentUserId]; std::string message((char*)dataPostPacket.__data.data, dataPostPacket.__data.packetLength - (sizeof(std::uint16_t) * 5)); spdlog::info("[{}] {}", sentUserName, message); // todo: pass data to main thread } void ClientManager::processContinuePacket(ContinuePacket continuePacket, IOCPPASSINDATA* data) { } void ClientManager::sendMessage(Snowflake ID, std::string message) { DataPostPacket dataPostPacket; dataPostPacket.__data.packetType = PacketCategory::PACKET_POST; dataPostPacket.__data.requestType = RequestType::DATA; dataPostPacket.__data.dataType = DataType::TEXT; dataPostPacket.__data.packetLength = message.size() + sizeof(Snowflake) * 2; memcpy(dataPostPacket.__data.sourceId, &myID_.snowflake, sizeof(Snowflake)); memcpy(dataPostPacket.__data.destId, &ID.snowflake, sizeof(Snowflake)); memcpy(dataPostPacket.__data.data, message.c_str(), message.size()); int packetLength = dataPostPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = data_->sendbytes = packetLength + 8; dataPostPacket.convToN(); memcpy(data_->wsabuf.buf, dataPostPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); } void ClientManager::registerUser(std::string userName) { LoginRequestPacket loginRequestPacket; loginRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; loginRequestPacket.__data.requestType = RequestType::LOGIN; loginRequestPacket.__data.dataType = DataType::BINARY; loginRequestPacket.__data.packetLength = userName.size(); memcpy(loginRequestPacket.__data.data, userName.c_str(), userName.size()); int packetLength = loginRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; loginRequestPacket.convToN(); memcpy(data_->wsabuf.buf, loginRequestPacket.serialized, packetLength + 8); data_->sendbytes = packetLength + 8; iocp_.send(data_, 1, 0, true); } void ClientManager::getUserList() { UsersListRequestPacket usersListRequestPacket; usersListRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; usersListRequestPacket.__data.requestType = RequestType::USERS_LIST; usersListRequestPacket.__data.dataType = DataType::BINARY; usersListRequestPacket.__data.packetLength = 0; int packetLength = usersListRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; usersListRequestPacket.convToN(); memcpy(data_->wsabuf.buf, usersListRequestPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); } void ClientManager::createRoom(std::string roomName) { RoomCreateRequestPacket roomCreateRequestPacket; roomCreateRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; roomCreateRequestPacket.__data.requestType = RequestType::ROOM_CREATE; roomCreateRequestPacket.__data.dataType = DataType::BINARY; roomCreateRequestPacket.__data.packetLength = roomName.size(); memcpy(roomCreateRequestPacket.__data.data, roomName.c_str(), roomName.size()); int packetLength = roomCreateRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; roomCreateRequestPacket.convToN(); memcpy(data_->wsabuf.buf, roomCreateRequestPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); } void ClientManager::getRoomList() { RoomListRequestPacket roomListRequestPacket; roomListRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; roomListRequestPacket.__data.requestType = RequestType::ROOM_LIST; roomListRequestPacket.__data.dataType = DataType::BINARY; roomListRequestPacket.__data.packetLength = 0; int packetLength = roomListRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; roomListRequestPacket.convToN(); memcpy(data_->wsabuf.buf, roomListRequestPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); } void ClientManager::joinRoom(Snowflake UID, Snowflake RID) { RoomJoinRequestPacket roomJoinRequestPacket; roomJoinRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; roomJoinRequestPacket.__data.requestType = RequestType::ROOM_JOIN; roomJoinRequestPacket.__data.dataType = DataType::BINARY; roomJoinRequestPacket.__data.packetLength = sizeof(Snowflake) * 2; memcpy(roomJoinRequestPacket.__data.myId, &UID.snowflake, sizeof(Snowflake)); memcpy(roomJoinRequestPacket.__data.roomId, &RID.snowflake, sizeof(Snowflake)); int packetLength = roomJoinRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; roomJoinRequestPacket.convToN(); memcpy(data_->wsabuf.buf, roomJoinRequestPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); inRoom_ = true; myRoomID_ = RID; } void ClientManager::exitRoom(Snowflake UID, Snowflake RID) { RoomExitRequestPacket roomExitRequestPacket; roomExitRequestPacket.__data.packetType = PacketCategory::PACKET_REQUEST; roomExitRequestPacket.__data.requestType = RequestType::ROOM_EXIT; roomExitRequestPacket.__data.dataType = DataType::BINARY; roomExitRequestPacket.__data.packetLength = sizeof(Snowflake) * 2; memcpy(roomExitRequestPacket.__data.myId, &UID.snowflake, sizeof(Snowflake)); memcpy(roomExitRequestPacket.__data.roomId, &RID.snowflake, sizeof(Snowflake)); int packetLength = roomExitRequestPacket.__data.packetLength; data_->recvbytes = data_->sendbytes = 0; data_->transferredbytes = 0; data_->wsabuf.len = packetLength + 8; roomExitRequestPacket.convToN(); memcpy(data_->wsabuf.buf, roomExitRequestPacket.serialized, packetLength + 8); iocp_.send(data_, 1, 0, true); inRoom_ = false; } void ClientManager::run() { StringTokenizer tokenizer; std::string nickname; std::cout << "Please enter your nickname: "; std::getline(std::cin, nickname); tokenizer.set(nickname.c_str(), nickname.size()); registerUser(tokenizer.get()[0]); std::cout << "Commads:" << std::endl; std::cout << "/w : Send direct message to specified user" << std::endl; std::cout << "/join : Enter specified room" << std::endl; std::cout << "/leave : Exit current room" << std::endl; std::cout << "/create : Create room" << std::endl; std::cout << "/userlist : Print all registred users" << std::endl; std::cout << "/roomlist : Print all registred rooms" << std::endl; std::cout << "/exit : Terminate this program" << std::endl; while (true) { std::string input; std::unique_lock lock2(screenMutex_); if (inRoom_) { std::cout << "[" + nickname + "@" + roomNames_[myRoomID_] + "]" + " "; } else { std::cout << "[" + nickname + "]" + " "; } lock2.unlock(); std::getline(std::cin, input); tokenizer.set(input.c_str(), input.size()); auto tokens = tokenizer.get(); if (tokens.size() == 0) continue; if (tokens[0] == "/w") { if (findUserId_.find(tokens[1]) == findUserId_.end()) { resourceMutex_.lock(); messageQueue_.push("User not found"); resourceMutex_.unlock(); continue; } Snowflake destId = findUserId_[tokens[1]]; std::string message; for (int i = 2; i < tokens.size(); i++) message += tokens[i] + " "; sendMessage(destId, message); } else if (tokens[0] == "/join") { std::string roomName; for (int i = 1; i < tokens.size(); i++) roomName += tokens[i]; if (findRoomId_.find(roomName) == findRoomId_.end()) { resourceMutex_.lock(); messageQueue_.push("Room not found"); resourceMutex_.unlock(); continue; } joinRoom(myID_, findRoomId_[roomName]); } else if (tokens[0] == "/leave") { if (!inRoom_) { resourceMutex_.lock(); messageQueue_.push("You are not in any room"); resourceMutex_.unlock(); continue; } exitRoom(myID_, myRoomID_); } else if (tokens[0] == "/create") { std::string roomName = tokenizer.get()[1]; createRoom(roomName); } else if (tokens[0] == "/userlist") getUserList(); else if (tokens[0] == "/roomlist") getRoomList(); else if (tokens[0] == "/exit") { break; } else if (inRoom_) { std::string message; for (int i = 0; i < tokens.size(); i++) message += tokens[i]; sendMessage(myRoomID_, message); } else { resourceMutex_.lock(); messageQueue_.push("Command not found"); resourceMutex_.unlock(); } } } }