#pragma once #include #include #include #include #include #include #include #include "ByteStream.hpp" #include "NetLibrary.hpp" class NetServer : public std::enable_shared_from_this { public: struct ClientData; typedef std::function, cereal::PortableBinaryInputArchive&)> NetServerRecvCallback; typedef std::function)> NetServerConnectCallback; typedef std::function)> NetServerDisconnectCallback; struct ClientData : public std::enable_shared_from_this { std::unordered_map>> messages; std::unordered_map pfm; MessageOrder nextMessageOrderToSend = 0; MessageOrder nextMessageOrderToExpect = 0; std::unordered_map> channels; std::mutex receivedMessagesMutex; struct ReceivedMessage { std::string channel; rtc::binary data; }; std::queue receivedMessages; struct OutgoingMessage { MessageOrder order; std::shared_ptr ss; }; std::unordered_map> messageQueues; uint64_t customID; void send_queued_messages(NetServer& server); void parse_received_messages(NetServer& server); void send_str_as_bytes(std::shared_ptr channel, const std::string& str); NetLibrary::DownloadProgress get_progress_into_fragmented_message(const std::string& channel) const; std::atomic setToDisconnect = false; std::chrono::steady_clock::time_point lastMessageTime; friend class NetServer; friend class NetClient; }; NetServer(const std::string& serverLocalID); ~NetServer(); void update(); template void send_items_to_client(std::shared_ptr client, const std::string& channel, Args&&... items) { if(!client) return; auto ss(std::make_shared()); { cereal::PortableBinaryOutputArchive m(*ss); (m(items), ...); } auto& messageQueue = client->messageQueues[channel]; if(channel == UNRELIABLE_COMMAND_CHANNEL) { if(ss->view().length() <= NetLibrary::MAX_UNRELIABLE_MESSAGE_SIZE) // Drop unreliable messages that are too big messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss); } else { std::vector> fragmentedMessage = fragment_message(ss->view(), NetLibrary::FRAGMENT_MESSAGE_STRIDE); if(fragmentedMessage.empty()) messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss); else { for(auto& ss2 : fragmentedMessage) messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss2); } } } template void send_items_to_all_clients(const std::string& channel, Args&&... items) { send_items_to_client_if([&](std::shared_ptr c) { return true; }, channel, items...); } template void send_items_to_all_clients_except(std::shared_ptr client, const std::string& channel, Args&&... items) { send_items_to_client_if([&](std::shared_ptr c) { return c != client; }, channel, items...); } template void send_items_to_client_if(std::function)> clientChecker, const std::string& channel, Args&&... items) { auto ss(std::make_shared()); { cereal::PortableBinaryOutputArchive m(*ss); (m(items), ...); } if(channel == UNRELIABLE_COMMAND_CHANNEL) { if(ss->view().length() <= NetLibrary::MAX_UNRELIABLE_MESSAGE_SIZE) { // Drop unreliable messages that are too big for(auto& client : clients) { if(client && clientChecker(client)) { auto& messageQueue = client->messageQueues[channel]; messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss); } } } } else { std::vector> fragmentedMessage = fragment_message(ss->view(), NetLibrary::FRAGMENT_MESSAGE_STRIDE); for(auto& client : clients) { if(client && clientChecker(client)) { auto& messageQueue = client->messageQueues[channel]; if(fragmentedMessage.empty()) messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss); else { for(auto& ss2 : fragmentedMessage) messageQueue.emplace(NetLibrary::calc_order_for_queued_message(channel, client->nextMessageOrderToSend), ss2); } } } } } bool is_disconnected() const; void add_recv_callback(MessageCommandType commandID, const NetServerRecvCallback& callback); void add_disconnect_callback(const NetServerDisconnectCallback& callback); const std::vector> get_client_list() const; private: void parse_received_messages(); void send_queued_messages(); void client_connected(std::shared_ptr connection, const std::string& clientLocalID); std::atomic isDisconnected = false; std::string localID; std::vector> clients; // Adding an add list, because i dont want to block the entire clients vector with a mutex std::mutex clientsToAddMutex; std::vector> clientsToAdd; std::unordered_map recvCallbacks; NetServerDisconnectCallback disconnectCallback; NetClient* directConnectClient = nullptr; std::shared_ptr directConnectClientData; friend class NetLibrary; friend class NetClient; };