Teaspeak-Server/server/src/client/voice/ServerCommandExecutor.cpp
2020-12-17 12:00:27 +01:00

99 lines
3.6 KiB
C++

//
// 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<ReassembledCommand, void(*)(ReassembledCommand*)> 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<std::chrono::milliseconds>(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);
}
}