diff --git a/server/src/client/ConnectedClient.h b/server/src/client/ConnectedClient.h index 91aace8..22f1a34 100644 --- a/server/src/client/ConnectedClient.h +++ b/server/src/client/ConnectedClient.h @@ -328,7 +328,7 @@ namespace ts { std::deque> visibleClients{}; /* variable locked with channel_lock */ std::deque> mutedClients{}; /* variable locked with channel_lock */ - std::deque> openChats{}; /* variable locked with channel_lock */ + std::deque> open_private_conversations{}; /* variable locked with channel_lock */ std::chrono::system_clock::time_point lastNeededNotify; std::shared_ptr lastNeededPermissionNotifyChannel = nullptr; diff --git a/server/src/client/command_handler/client.cpp b/server/src/client/command_handler/client.cpp index f5d88ba..0d8aa41 100644 --- a/server/src/client/command_handler/client.cpp +++ b/server/src/client/command_handler/client.cpp @@ -359,15 +359,15 @@ command_result ConnectedClient::handleCommandClientChatClosed(Command &cmd) { if (!client) return command_result{error::client_invalid_id}; { unique_lock channel_lock(this->channel_lock); - this->openChats.erase(remove_if(this->openChats.begin(), this->openChats.end(), [&](const weak_ptr& weak) { + this->open_private_conversations.erase(remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [&](const weak_ptr& weak) { return weak.lock() == client; - }), this->openChats.end()); + }), this->open_private_conversations.end()); } { unique_lock channel_lock(client->get_channel_lock()); - client->openChats.erase(remove_if(client->openChats.begin(), client->openChats.end(), [&](const weak_ptr& weak) { + client->open_private_conversations.erase(remove_if(client->open_private_conversations.begin(), client->open_private_conversations.end(), [&](const weak_ptr& weak) { return weak.lock().get() == this; - }), client->openChats.end()); + }), client->open_private_conversations.end()); } client->notifyClientChatClosed(_this.lock()); return command_result{error::ok}; @@ -1047,51 +1047,64 @@ command_result ConnectedClient::handleCommandClientDbInfo(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_client_dbinfo, 1); - deque cldbids; - for(int index = 0; index < cmd.bulkCount(); index++) + std::deque cldbids; + for(int index = 0; index < cmd.bulkCount(); index++) { cldbids.push_back(cmd[index]["cldbid"]); + } auto basic = serverInstance->databaseHelper()->queryDatabaseInfo(this->server, cldbids); - if (basic.empty()) return command_result{error::database_empty_result}; + if (basic.empty()) { + return command_result{error::database_empty_result}; + } auto allow_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, 0)); - Command res(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifyclientdbinfo" : ""); + ts::command_builder result{this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifyclientdbinfo" : ""}; + result.reserve_bulks(basic.size()); size_t index = 0; for(const auto& info : basic) { - res[index]["client_base64HashClientUID"] = hex::hex(base64::validate(info->client_unique_id) ? base64::decode(info->client_unique_id) : info->client_unique_id, 'a', 'q'); - res[index]["client_unique_identifier"] = info->client_unique_id; - res[index]["client_nickname"] = info->client_nickname; - res[index]["client_database_id"] = info->client_database_id; - res[index]["client_created"] = chrono::duration_cast(info->client_created.time_since_epoch()).count(); - res[index]["client_lastconnected"] = chrono::duration_cast(info->client_last_connected.time_since_epoch()).count(); - res[index]["client_totalconnections"] = info->client_total_connections; - res[index]["client_database_id"] = info->client_database_id; + auto bulk = result.bulk(index++); + bulk.reserve(800); + + bulk.put_unchecked("client_base64HashClientUID", hex::hex(base64::validate(info->client_unique_id) ? base64::decode(info->client_unique_id) : info->client_unique_id, 'a', 'q')); + bulk.put_unchecked(property::CLIENT_UNIQUE_IDENTIFIER, info->client_unique_id); + bulk.put_unchecked(property::CLIENT_NICKNAME, info->client_nickname); + bulk.put_unchecked(property::CLIENT_DATABASE_ID, info->client_database_id); + bulk.put_unchecked(property::CLIENT_CREATED, chrono::duration_cast(info->client_created.time_since_epoch()).count()); + bulk.put_unchecked(property::CLIENT_LASTCONNECTED, chrono::duration_cast(info->client_last_connected.time_since_epoch()).count()); + bulk.put_unchecked(property::CLIENT_TOTALCONNECTIONS, info->client_total_connections); + bulk.put_unchecked(property::CLIENT_DATABASE_ID, info->client_database_id); auto props = serverInstance->databaseHelper()->loadClientProperties(this->server, info->client_database_id, ClientType::CLIENT_TEAMSPEAK); - if (allow_ip) - res[index]["client_lastip"] = (*props)[property::CONNECTION_CLIENT_IP].as(); - else - res[index]["client_lastip"] = "hidden"; + if(allow_ip) { + bulk.put_unchecked("client_lastip", (*props)[property::CONNECTION_CLIENT_IP].as()); + } else { + bulk.put_unchecked("client_lastip", "hidden"); + } - res[index]["client_icon_id"] = (*props)[property::CLIENT_ICON_ID].as(); - res[index]["client_badges"] = (*props)[property::CLIENT_BADGES].as(); - res[index]["client_version"] = (*props)[property::CLIENT_VERSION].as(); - res[index]["client_platform"] = (*props)[property::CLIENT_PLATFORM].as(); - res[index]["client_hwid"] = (*props)[property::CLIENT_HARDWARE_ID].as(); - res[index]["client_total_bytes_downloaded"] = (*props)[property::CLIENT_TOTAL_BYTES_DOWNLOADED].as(); - res[index]["client_total_bytes_uploaded"] = (*props)[property::CLIENT_TOTAL_BYTES_UPLOADED].as(); - res[index]["client_month_bytes_downloaded"] = (*props)[property::CLIENT_MONTH_BYTES_DOWNLOADED].as(); - res[index]["client_month_bytes_uploaded"] = (*props)[property::CLIENT_MONTH_BYTES_DOWNLOADED].as(); - res[index]["client_description"] = (*props)[property::CLIENT_DESCRIPTION].as(); - res[index]["client_flag_avatar"] = (*props)[property::CLIENT_FLAG_AVATAR].as(); +#define ASSIGN_PROPERTY(property) \ + bulk.put_unchecked(property, (*props)[property].as()); + + ASSIGN_PROPERTY(property::CLIENT_ICON_ID); + ASSIGN_PROPERTY(property::CLIENT_BADGES); + ASSIGN_PROPERTY(property::CLIENT_VERSION); + ASSIGN_PROPERTY(property::CLIENT_PLATFORM); + ASSIGN_PROPERTY(property::CLIENT_HARDWARE_ID); + ASSIGN_PROPERTY(property::CLIENT_TOTAL_BYTES_DOWNLOADED); + ASSIGN_PROPERTY(property::CLIENT_TOTAL_BYTES_UPLOADED); + ASSIGN_PROPERTY(property::CLIENT_MONTH_BYTES_DOWNLOADED); + ASSIGN_PROPERTY(property::CLIENT_MONTH_BYTES_DOWNLOADED); + ASSIGN_PROPERTY(property::CLIENT_DESCRIPTION); + ASSIGN_PROPERTY(property::CLIENT_FLAG_AVATAR); + + ASSIGN_PROPERTY(property::CLIENT_MONTH_ONLINE_TIME); + ASSIGN_PROPERTY(property::CLIENT_TOTAL_ONLINE_TIME); +#undef ASSIGN_PROPERTY - res[index]["client_month_online_time"] = (*props)[property::CLIENT_MONTH_ONLINE_TIME].as(); - res[index]["client_total_online_time"] = (*props)[property::CLIENT_TOTAL_ONLINE_TIME].as(); index++; } - this->sendCommand(res); + this->sendCommand(result); return command_result{error::ok}; } diff --git a/server/src/client/command_handler/misc.cpp b/server/src/client/command_handler/misc.cpp index 77fe27b..387f926 100644 --- a/server/src/client/command_handler/misc.cpp +++ b/server/src/client/command_handler/misc.cpp @@ -551,12 +551,15 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) { ConnectedLockedClient target{this->server->find_client_by_id(cmd["target"].as())}; if (!target) return command_result{error::client_invalid_id}; - bool chat_open = false; + bool chat_open{false}; { - shared_lock channel_lock(this->channel_lock); - this->openChats.erase(remove_if(this->openChats.begin(), this->openChats.end(), [](const weak_ptr& weak) { return !weak.lock(); }), this->openChats.end()); - for(const auto& entry : this->openChats) { + std::unique_lock self_channel_lock{this->channel_lock}; + this->open_private_conversations.erase(std::remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [](const weak_ptr& weak) { + return !weak.lock(); + }), this->open_private_conversations.end()); + + for(const auto& entry : this->open_private_conversations) { if(entry.lock() == target) { chat_open = true; break; @@ -565,24 +568,30 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) { } if(!chat_open) { - if (target.client == this) + if(target.client == this) { ACTION_REQUIRES_PERMISSION(permission::b_client_even_textmessage_send, 1, this->getChannelId()); - if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()), false)) + } + + if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()), false)) { return command_result{permission::i_client_private_textmessage_power}; + } { - unique_lock channel_lock(target->get_channel_lock()); - target->openChats.push_back(_this); + std::unique_lock target_channel_lock{target->get_channel_lock()}; + target->open_private_conversations.push_back(_this); } { - unique_lock channel_lock(this->channel_lock); - this->openChats.push_back(target.client); + std::unique_lock self_channel_lock{this->channel_lock}; + this->open_private_conversations.push_back(target.client); } } - if(this->handleTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, cmd["msg"], target.client)) return command_result{error::ok}; + if(this->handleTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, cmd["msg"], target.client)) { + return command_result{error::ok}; + } + target->notifyTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, _this.lock(), target->getClientId(), 0, timestamp, cmd["msg"].string()); this->notifyTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, _this.lock(), target->getClientId(), 0, timestamp, cmd["msg"].string()); } else if (cmd["targetmode"] == ChatMessageMode::TEXTMODE_CHANNEL) {