448 lines
16 KiB
C++
448 lines
16 KiB
C++
#include "ClientManager/ClientManager.hpp"
|
|
#include "Utils/ConfigManager.hpp"
|
|
#include "Utils/StringTokenizer.hpp"
|
|
#include "Socket/Log.hpp"
|
|
#include <iostream>
|
|
|
|
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<ResponsePacket>();
|
|
auto promise = std::promise<ResponsePacket>();
|
|
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<ResponsePacket>();
|
|
auto promise = std::promise<ResponsePacket>();
|
|
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<ResponsePacket>();
|
|
auto promise = std::promise<ResponsePacket>();
|
|
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 <username> : Send direct message to specified user" << std::endl;
|
|
std::cout << "/join <roomname> : Enter specified room" << std::endl;
|
|
std::cout << "/leave : Exit current room" << std::endl;
|
|
std::cout << "/create <roomname> : 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<std::mutex> 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();
|
|
}
|
|
}
|
|
}
|
|
|
|
} |