#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; 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); 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), ...); } std::vector> fragmentedMessage = fragment_message(ss->view(), NetLibrary::FRAGMENT_MESSAGE_STRIDE); auto& messageQueue = client->messageQueues[channel]; if(fragmentedMessage.empty()) messageQueue.emplace(ss); else if(channel != UNRELIABLE_COMMAND_CHANNEL) { // Just drop unreliable messages that are fragmented for(auto& ss2 : fragmentedMessage) messageQueue.emplace(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), ...); } 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(ss); else if(channel != UNRELIABLE_COMMAND_CHANNEL) { // Just drop unreliable messages that are fragmented for(auto& ss2 : fragmentedMessage) messageQueue.emplace(ss2); } } } } bool is_disconnected(); void add_recv_callback(MessageCommandType commandID, const NetServerRecvCallback& callback); void add_disconnect_callback(const NetServerDisconnectCallback& callback); 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::mutex clientList; 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; };