// // Created by WolverinDEV on 29/07/2020. // #include "./ServerCommandExecutor.h" #include "./PacketDecoder.h" #include "./VoiceClientConnection.h" using namespace ts; using namespace ts::server::server::udp; ServerCommandExecutor::ServerCommandExecutor(VoiceClient *client) : client{client} {} ServerCommandExecutor::~ServerCommandExecutor() { this->reset(); } void ServerCommandExecutor::reset() { std::unique_lock pc_lock{this->pending_commands_lock}; auto head = std::exchange(this->pending_commands_head, nullptr); this->pending_commands_tail = &this->pending_commands_head; pc_lock.unlock(); while(head) { auto cmd = head->next_command; ReassembledCommand::free(head); head = cmd; } } void ServerCommandExecutor::force_insert_command(const pipes::buffer_view &buffer) { auto command = ReassembledCommand::allocate(buffer.length()); memcpy(command->command(), buffer.data_ptr(), command->length()); this->enqueue_command_execution(command); } void ServerCommandExecutor::enqueue_command_execution(ReassembledCommand *command) { assert(!command->next_command); bool command_handling_scheduled; { std::lock_guard pc_lock{this->pending_commands_lock}; *this->pending_commands_tail = command; this->pending_commands_tail = &command->next_command; command_handling_scheduled = std::exchange(this->has_command_handling_scheduled, true); } if(!command_handling_scheduled) { auto voice_server = this->client->getVoiceServer(); if(voice_server) voice_server->schedule_command_handling(&*client); } } void ServerCommandExecutor::execute_handle_command_packets(const std::chrono::system_clock::time_point& /* scheduled */) { if(!this->client->getServer() || this->client->connectionState() >= ConnectionState::DISCONNECTING) { return; } std::unique_ptr pending_command{nullptr, ReassembledCommand::free}; while(true) { { std::lock_guard pc_lock{this->pending_commands_lock}; pending_command.reset(this->pending_commands_head); if(!pending_command) { this->has_command_handling_scheduled = false; return; } else if(pending_command->next_command) { this->pending_commands_head = pending_command->next_command; } else { this->pending_commands_head = nullptr; this->pending_commands_tail = &this->pending_commands_head; } } auto startTime = std::chrono::system_clock::now(); try { this->client->handlePacketCommand(pipes::buffer_view{pending_command->command(), pending_command->length()}); } catch (std::exception& ex) { logCritical(this->client->getServerId(), "{} Exception reached root tree! {}", CLIENT_STR_LOG_PREFIX_(this->client), ex.what()); } auto end = std::chrono::system_clock::now(); if(end - startTime > std::chrono::milliseconds(10)) { logError(this->client->getServerId(), "{} Handling of command packet needs more than 10ms ({}ms)", CLIENT_STR_LOG_PREFIX_(this->client), duration_cast(end - startTime).count() ); } break; /* Maybe handle more than one command? Maybe some kind of time limit? */ } auto voice_server = this->client->getVoiceServer(); if(voice_server) { voice_server->schedule_command_handling(client); } }