First draft of the new snapshot system and database changes

This commit is contained in:
WolverinDEV
2020-07-30 20:25:45 +02:00
parent c60119af00
commit 72abd7e20e
20 changed files with 1558 additions and 961 deletions
@@ -391,8 +391,8 @@ bool ConnectedClient::handle_text_command(
for(const auto& song : bot_playlist->list_songs()) {
string invoker = "unknown";
for(const auto& e : dbinfo) {
if(e->cldbid == song->invoker) {
invoker = "[URL=client://0/" + e->uniqueId + "~" + e->lastName + "]" + e->lastName + "[/URL]";
if(e->client_database_id == song->invoker) {
invoker = "[URL=client://0/" + e->client_unique_id + "~" + e->client_nickname + "]" + e->client_nickname + "[/URL]";
break;
}
}
+66 -62
View File
@@ -1,11 +1,10 @@
#include <log/LogUtils.h>
#include <src/client/voice/VoiceClient.h>
#include <misc/sassert.h>
#include <misc/hex.h>
#include "DataClient.h"
#include "ConnectedClient.h"
#include "src/InstanceHandler.h"
#include "misc/base64.h"
#include <misc/base64.h>
#include "./DataClient.h"
#include "../InstanceHandler.h"
using namespace std;
using namespace ts;
@@ -22,52 +21,78 @@ DataClient::~DataClient() {
this->_properties = nullptr;
}
bool DataClient::loadDataForCurrentServer() { //TODO for query
if(this->getUid().empty()) return false;
constexpr static std::string_view kClientLoadCommand{R"(
SELECT
`client_database_id`,
`client_created`,
`client_last_connected`,
`client_total_connections`,
`client_month_upload`,
`client_month_download`,
`client_total_upload`,
`client_total_download`
FROM `clients_server` WHERE `server_id` = :sid AND `client_unique_id` = :uid
)"};
bool DataClient::loadDataForCurrentServer() {
auto uniqueId = this->getUid();
if(uniqueId.empty())
return false;
auto ref_server = this->server;
auto server_id = ref_server ? ref_server->getServerId() : 0;
properties()[property::CLIENT_DATABASE_ID] = 0;
properties()[property::CLIENT_CREATED] = 0;
properties()[property::CLIENT_TOTALCONNECTIONS] = 0;
this->clientPermissions = std::make_shared<permission::v2::PermissionManager>();
auto properties = this->properties();
sql::command{this->sql, std::string{kClientLoadCommand}, variable{":uid", uniqueId}, variable{":sid", server_id}}.query([&](int length, std::string* values, std::string* names) {
auto index{0};
ClientDbId client_db_id = 0;
sql::command(this->sql, "SELECT `cldbid`,`firstConnect`,`connections` FROM `clients` WHERE `serverId` = :sid AND `clientUid` = :uid LIMIT 1",
variable{":sid", server_id},
variable{":uid", this->getUid()}
).query([&](DataClient* cl, int length, string* values, string* names){
for (int index = 0; index < length; index++) {
try {
if (names[index] == "cldbid") {
client_db_id = stoull(values[index]);
} else if (names[index] == "firstConnect") {
cl->properties()[property::CLIENT_CREATED] = values[index];
} else if (names[index] == "connections") {
cl->properties()[property::CLIENT_TOTALCONNECTIONS] = values[index];
} else {
logWarning(LOG_INSTANCE, "Received unknown column with name {} within client list", names[index]);
}
} catch(const std::exception& ex) {
logError(server_id, "Failed to load client {} base properties from database. Colum parsing for column {} failed. Value: {}. Message: {}",
this->getUid(),
names[index],
values[index],
ex.what()
);
return 0;
}
try {
assert(names[index] == "client_database_id");
properties[property::CLIENT_DATABASE_ID] = std::stoull(values[index++]);
assert(names[index] == "client_created");
properties[property::CLIENT_CREATED] = std::stoull(values[index++]);
assert(names[index] == "client_last_connected");
properties[property::CLIENT_LASTCONNECTED] = std::stoull(values[index++]);
assert(names[index] == "client_total_connections");
properties[property::CLIENT_TOTALCONNECTIONS] = std::stoull(values[index++]);
assert(names[index] == "client_month_upload");
properties[property::CLIENT_MONTH_BYTES_UPLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_month_download");
properties[property::CLIENT_MONTH_BYTES_DOWNLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_total_upload");
properties[property::CLIENT_TOTAL_BYTES_UPLOADED] = std::stoull(values[index++]);
assert(names[index] == "client_total_download");
properties[property::CLIENT_TOTAL_BYTES_DOWNLOADED] = std::stoull(values[index++]);
assert(index == length);
} catch (std::exception& ex) {
logError(server_id, "Failed to load client {} base properties from database: {} (Index {})",
this->getUid(),
ex.what(),
index - 1
);
properties[property::CLIENT_DATABASE_ID] = 0;
}
return 0;
}, this);
});
if(client_db_id == 0)
if(this->properties()[property::CLIENT_DATABASE_ID].as<ClientDbId>() == 0)
return false;
this->properties()[property::CLIENT_DATABASE_ID] = client_db_id; /* do this before the property saving (it saved the cldbid as well!)*/
//Load general properties
deque<ts::PropertyWrapper> copied;
std::deque<ts::PropertyWrapper> copied;
for(const auto& prop : this->_properties->list_properties()){
if((prop.type().flags & property::FLAG_GLOBAL) == 0) continue;
if(prop.type().default_value == prop.value()) continue;
@@ -80,28 +105,7 @@ bool DataClient::loadDataForCurrentServer() { //TODO for query
return false;
}
auto client_type = this->getType();
if(client_type == CLIENT_TEAMSPEAK || ref_server) {
this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), client_type);
} else {
this->_properties = DatabaseHelper::default_properties_client(nullptr, client_type);
this->_properties->registerNotifyHandler([&, server_id, client_db_id](Property& prop){
std::string query;
if(prop.type() == property::CLIENT_TOTALCONNECTIONS)
query = "UPDATE `clients` SET `connections` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
else if(prop.type() == property::CLIENT_NICKNAME)
query = "UPDATE `clients` SET `lastName` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
else if(prop.type() == property::CLIENT_LASTCONNECTED)
query = "UPDATE `clients` SET `lastConnect` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
else
return;
debugMessage(server_id, "[Property] Updating general client table property for client {}. Key: {} Value: {}", client_db_id, prop.type().name, prop.value());
sql::command(this->sql, query, variable{":sid", 0}, variable{":cldbid", client_db_id}, variable{":value", prop.value()}).executeLater()
.waitAndGetLater(LOG_SQL_CMD, {1, "failed to update general client properties"});
});
}
this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), this->getType());
this->_properties->toggleSave(false);
for(const auto& e : copied) {
+165 -149
View File
@@ -367,18 +367,22 @@ command_result ConnectedClient::handleCommandClientChatClosed(Command &cmd) {
return command_result{error::ok};
}
//start=0 duration=10
//pattern=%asd%
struct ClientDbArgs {
shared_ptr<VirtualServer> server;
int index = 0;
int offset = 0;
int resultIndex = 0;
bool showIp = false;
bool largeInfo = false;
Command *result = nullptr;
};
constexpr static auto kDBListQuery{R"(
SELECT `clients`.*, `properties`.`value` as `client_description` FROM (
SELECT
`clients_server`.`client_database_id`,
`clients_server`.`client_unique_id`,
`clients_server`.`client_nickname`,
`clients_server`.`client_ip`,
`clients_server`.`client_created`,
`clients_server`.`client_last_connected`,
`clients_server`.`client_total_connections`,
`clients`.`client_login_name` FROM `clients_server`
INNER JOIN `clients` ON `clients`.`client_database_id` = `clients_server`.`client_database_id`
WHERE `server_id` = :serverId LIMIT :offset, :limit
) AS `clients`
LEFT JOIN `properties` ON `properties`.serverId = :serverId AND `properties`.key = 'client_description' AND `properties`.`id` = `clients`.`client_database_id`
)"};
command_result ConnectedClient::handleCommandClientDbList(Command &cmd) {
CMD_REQ_SERVER;
@@ -386,86 +390,79 @@ command_result ConnectedClient::handleCommandClientDbList(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(25);
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_client_dblist, 1);
Command notify(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientdblist" : "");
size_t offset = cmd[0].has("start") ? cmd["start"].as<size_t>() : 0;
size_t limit = cmd[0].has("duration") ? cmd["duration"].as<int>() : 0;
if(limit > 2000 || limit < 1)
limit = 2000;
if (!cmd[0].has("start"))
cmd["start"] = 0;
if (!cmd[0].has("duration"))
cmd["duration"] = 20;
if (cmd[0]["duration"].as<int>() > 2000) cmd["duration"] = 2000;
if (cmd[0]["duration"].as<int>() < 1) cmd["duration"] = 1;
ts::command_builder result{this->notify_response_command("notifyclientdblist")};
result.reserve_bulks(limit);
auto maxIndex = cmd["start"].as<uint32_t>() + cmd["duration"].as<uint32_t>();
ClientDbArgs args;
args.server = this->server;
args.offset = cmd["start"].as<uint32_t>();
args.result = &notify;
args.resultIndex = 0;
args.index = 0;
args.showIp = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, 0));
args.largeInfo = cmd.hasParm("details");
size_t command_index{0}, set_index{0};
(LOG_SQL_CMD)(sql::command(this->server->getSql(), "SELECT * FROM `clients` WHERE `serverId` = :sid ORDER BY `cldbid` ASC" + (maxIndex > 0 ? " LIMIT " + to_string(maxIndex) : ""), variable{":sid", this->server->getServerId()}).query(
[](ClientDbArgs *pArgs, int length, char **values, char **column) {
pArgs->index++;
if (pArgs->offset < pArgs->index) {
ClientDbId id = 0;
string uid, name, ip;
string created = "0", lastConnected = "0", connections = "0";
for (int index = 0; index < length; index++) {
string key = column[index];
if (key == "cldbid")
id = stoll(values[index]);
else if (key == "clientUid")
uid = values[index];
else if (key == "firstConnect")
created = values[index];
else if (key == "lastConnect")
lastConnected = values[index];
else if (key == "connections")
connections = values[index];
else if (key == "lastName")
name = values[index];
}
auto show_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, 0));
pArgs->result->operator[](pArgs->resultIndex)["cldbid"] = id;
pArgs->result->operator[](pArgs->resultIndex)["client_unique_identifier"] = uid;
pArgs->result->operator[](pArgs->resultIndex)["client_nickname"] = name;
pArgs->result->operator[](pArgs->resultIndex)["client_created"] = created;
pArgs->result->operator[](pArgs->resultIndex)["client_lastconnected"] = lastConnected;
pArgs->result->operator[](pArgs->resultIndex)["client_totalconnections"] = connections;
pArgs->result->operator[](pArgs->resultIndex)["client_description"] = "";
auto sqlResult = sql::command{this->server->getSql(), kDBListQuery, variable{":serverId", this->getServerId()}, variable{":offset", offset}, variable{":limit", limit}}
.query([&](int length, std::string* values, std::string* names) {
set_index++;
auto bulk = result.bulk(command_index++);
bulk.reserve(300);
auto props = serverInstance->databaseHelper()->loadClientProperties(pArgs->server, id, ClientType::CLIENT_TEAMSPEAK);
if (props) {
pArgs->result->operator[](pArgs->resultIndex)["client_lastip"] = (*props)[property::CONNECTION_CLIENT_IP].as<string>();
pArgs->result->operator[](pArgs->resultIndex)["client_description"] = (*props)[property::CLIENT_DESCRIPTION].as<string>();
auto index{0};
try {
assert(names[index] == "client_database_id");
bulk.put_unchecked("cldbid", values[index++]);
if (pArgs->largeInfo) {
pArgs->result->operator[](pArgs->resultIndex)["client_badges"] = (*props)[property::CLIENT_BADGES].as<string>();
pArgs->result->operator[](pArgs->resultIndex)["client_version"] = (*props)[property::CLIENT_VERSION].as<string>();
pArgs->result->operator[](pArgs->resultIndex)["client_platform"] = (*props)[property::CLIENT_PLATFORM].as<string>();
pArgs->result->operator[](pArgs->resultIndex)["client_hwid"] = (*props)[property::CLIENT_HARDWARE_ID].as<string>();
}
}
if (!pArgs->showIp)
pArgs->result->operator[](pArgs->resultIndex)["client_lastip"] = "hidden";
pArgs->resultIndex++;
}
return 0;
}, &args));
assert(names[index] == "client_unique_id");
bulk.put_unchecked("client_unique_identifier", values[index++]);
assert(names[index] == "client_nickname");
bulk.put_unchecked("client_nickname", values[index++]);
assert(names[index] == "client_ip");
bulk.put_unchecked("client_lastip", show_ip ? values[index++] : "hidden");
assert(names[index] == "client_created");
bulk.put_unchecked("client_lastconnected", values[index++]);
assert(names[index] == "client_last_connected");
bulk.put_unchecked("client_created", values[index++]);
assert(names[index] == "client_total_connections");
bulk.put_unchecked("client_totalconnections", values[index++]);
assert(names[index] == "client_login_name");
bulk.put_unchecked("client_login_name", values[index++]);
assert(names[index] == "client_description");
bulk.put_unchecked("client_description", values[index++]);
assert(index == length);
} catch (std::exception& ex) {
command_index--;
logError(this->getServerId(), "Failed to parse client base properties at index {}: {}. Offset: {} Limit: {} Set: {}",
index - 1,
ex.what(),
offset,
limit,
set_index - 1
);
}
});
if (command_index == 0)
return command_result{error::database_empty_result};
if (args.resultIndex == 0) return command_result{error::database_empty_result};
if (cmd.hasParm("count")) {
size_t result = 0;
sql::command(this->server->getSql(), "SELECT COUNT(*) AS `count` FROM `clients` WHERE `serverId` = :sid", variable{":sid", this->server->getServerId()}).query([](size_t *ptr, int, char **v, char **) {
*ptr = static_cast<size_t>(stoll(v[0]));
return 0;
}, &result);
notify[0]["count"] = result;
size_t count{0};
sql::command(this->server->getSql(), "SELECT COUNT(`client_database_id`) AS `count` FROM `clients_server` WHERE `server_id` = :sid", variable{":sid", this->server->getServerId()})
.query([&](int, std::string* v, std::string*) {
count = stoll(v[0]);
});
result.put_unchecked(0, "count", count);
}
this->sendCommand(notify);
this->sendCommand(result);
return command_result{error::ok};
}
@@ -869,8 +866,9 @@ command_result ConnectedClient::handleCommandClientGetDBIDfromUID(Command &cmd)
CMD_RESET_IDLE;
deque<string> unique_ids;
for(int index = 0; index < cmd.bulkCount(); index++)
unique_ids.push_back(cmd[index]["cluid"].as<string>());
for(int index = 0; index < cmd.bulkCount(); index++) {
unique_ids.push_back(cmd[index]["cluid"]);
}
auto res = serverInstance->databaseHelper()->queryDatabaseInfoByUid(this->server, unique_ids);
if (res.empty()) return command_result{error::database_empty_result};
@@ -878,8 +876,8 @@ command_result ConnectedClient::handleCommandClientGetDBIDfromUID(Command &cmd)
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientdbidfromuid" : "");
int result_index = 0;
for(auto& info : res) {
result[result_index]["cluid"] = info->uniqueId;
result[result_index]["cldbid"] = info->cldbid;
result[result_index]["cluid"] = info->client_unique_id;
result[result_index]["cldbid"] = info->client_database_id;
result_index++;
}
this->sendCommand(result);
@@ -900,10 +898,10 @@ command_result ConnectedClient::handleCommandClientGetNameFromDBID(Command &cmd)
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientgetnamefromdbid" : "");
int result_index = 0;
for(auto& info : res) {
result[result_index]["cluid"] = info->uniqueId;
result[result_index]["cldbid"] = info->cldbid;
result[result_index]["name"] = info->lastName;
result[result_index]["clname"] = info->lastName;
result[result_index]["cluid"] = info->client_unique_id;
result[result_index]["cldbid"] = info->client_database_id;
result[result_index]["name"] = info->client_nickname;
result[result_index]["clname"] = info->client_nickname;
result_index++;
}
this->sendCommand(result);
@@ -924,10 +922,10 @@ command_result ConnectedClient::handleCommandClientGetNameFromUid(Command &cmd)
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientnamefromuid" : "");
int result_index = 0;
for(auto& info : res) {
result[result_index]["cluid"] = info->uniqueId;
result[result_index]["cldbid"] = info->cldbid;
result[result_index]["name"] = info->lastName;
result[result_index]["clname"] = info->lastName;
result[result_index]["cluid"] = info->client_unique_id;
result[result_index]["cldbid"] = info->client_database_id;
result[result_index]["name"] = info->client_nickname;
result[result_index]["clname"] = info->client_nickname;
result_index++;
}
this->sendCommand(result);
@@ -1086,16 +1084,16 @@ command_result ConnectedClient::handleCommandClientDbInfo(Command &cmd) {
size_t index = 0;
for(const auto& info : basic) {
res[index]["client_base64HashClientUID"] = hex::hex(base64::validate(info->uniqueId) ? base64::decode(info->uniqueId) : info->uniqueId, 'a', 'q');
res[index]["client_unique_identifier"] = info->uniqueId;
res[index]["client_nickname"] = info->lastName;
res[index]["client_database_id"] = info->cldbid;
res[index]["client_created"] = chrono::duration_cast<chrono::seconds>(info->created.time_since_epoch()).count();
res[index]["client_lastconnected"] = chrono::duration_cast<chrono::seconds>(info->lastjoin.time_since_epoch()).count();
res[index]["client_totalconnections"] = info->connections;
res[index]["client_database_id"] = info->cldbid;
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<chrono::seconds>(info->client_created.time_since_epoch()).count();
res[index]["client_lastconnected"] = chrono::duration_cast<chrono::seconds>(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 props = serverInstance->databaseHelper()->loadClientProperties(this->server, info->cldbid, ClientType::CLIENT_TEAMSPEAK);
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<string>();
else
@@ -1136,13 +1134,6 @@ command_result ConnectedClient::handleCommandClientDBDelete(Command &cmd) {
return command_result{error::ok};
}
struct DBFindArgs {
int index = 0;
bool full = false;
bool ip = false;
Command cmd{""};
};
command_result ConnectedClient::handleCommandClientDBFind(Command &cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
@@ -1152,48 +1143,73 @@ command_result ConnectedClient::handleCommandClientDBFind(Command &cmd) {
bool uid = cmd.hasParm("uid");
string pattern = cmd["pattern"];
DBFindArgs args{};
args.cmd = Command(this->getType() == CLIENT_QUERY ? "" : "notifyclientdbfind");
args.full = cmd.hasParm("details");
args.ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, 0));
auto res = sql::command(this->sql, "SELECT * FROM `clients` WHERE `serverId` = :sid AND `" + std::string{uid ? "clientUid" : "lastName"} + "` LIKE :pattern LIMIT 50",
variable{":sid", this->server->getServerId()},
variable{":pattern", pattern}).query(
[&](DBFindArgs *ptr, int len, char **values, char **names) {
for (int index = 0; index < len; index++)
if (strcmp(names[index], "cldbid") == 0)
ptr->cmd[ptr->index]["cldbid"] = values[index];
else if (strcmp(names[index], "clientUid") == 0 && ptr->full)
ptr->cmd[ptr->index]["client_unique_identifier"] = values[index];
else if (strcmp(names[index], "lastConnect") == 0 && ptr->full)
ptr->cmd[ptr->index]["client_lastconnected"] = values[index];
else if (strcmp(names[index], "connections") == 0 && ptr->full)
ptr->cmd[ptr->index]["client_totalconnections"] = values[index];
else if (strcmp(names[index], "lastName") == 0 && ptr->full)
ptr->cmd[ptr->index]["client_nickname"] = values[index];
if (ptr->full) {
auto props = serverInstance->databaseHelper()->loadClientProperties(this->server, ptr->cmd[ptr->index]["cldbid"], ClientType::CLIENT_TEAMSPEAK);
if (props) {
if (ptr->ip) {
ptr->cmd[ptr->index]["client_lastip"] = (*props)[property::CONNECTION_CLIENT_IP].as<string>();
} else {
ptr->cmd[ptr->index]["client_lastip"] = "hidden";
}
ptr->cmd[ptr->index]["client_badges"] = (*props)[property::CLIENT_BADGES].as<string>();
ptr->cmd[ptr->index]["client_version"] = (*props)[property::CLIENT_VERSION].as<string>();
ptr->cmd[ptr->index]["client_platform"] = (*props)[property::CLIENT_PLATFORM].as<string>();
ptr->cmd[ptr->index]["client_hwid"] = (*props)[property::CLIENT_HARDWARE_ID].as<string>();
}
const auto detailed = cmd.hasParm("details");
const auto show_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, 0));
size_t command_index{0};
ts::command_builder result{this->notify_response_command("notifyclientdbfind")};
result.reserve_bulks(50);
constexpr static auto kBaseCommand{"SELECT `client_database_id`, `client_unique_id`, `client_nickname`, `client_ip`, `client_last_connected`, `client_total_connections` FROM `clients_server` WHERE "};
auto sql_result = sql::command{this->sql, std::string{kBaseCommand} + "`server_id` = :sid AND " + (uid ? "`client_unique_id`" : "`client_nickname`") + " LIKE :pattern LIMIT 50", variable{":sid", this->getServerId()}, variable{":pattern", pattern}}
.query([&](int length, std::string* values, std::string* names) {
auto bulk = result.bulk(command_index++);
bulk.reserve(300);
auto index{0};
ClientDbId client_database_id;
try {
assert(names[index] == "client_database_id");
client_database_id = std::stoull(values[index]);
bulk.put_unchecked("cldbid", values[index++]);
assert(names[index] == "client_unique_id");
bulk.put_unchecked("client_unique_identifier", values[index++]);
assert(names[index] == "client_nickname");
bulk.put_unchecked("client_nickname", values[index++]);
assert(names[index] == "client_ip");
if(detailed) {
bulk.put_unchecked("client_lastip", show_ip ? values[index++] : "hidden");
} else {
index++;
}
ptr->index++;
return 0;
}, &args);
auto pf = LOG_SQL_CMD;
pf(res);
if (args.index == 0) return command_result{error::database_empty_result};
this->sendCommand(args.cmd);
assert(names[index] == "client_last_connected");
bulk.put_unchecked("client_lastconnected", values[index++]);
assert(names[index] == "client_total_connections");
bulk.put_unchecked("client_totalconnections", values[index++]);
assert(index == length);
} catch (std::exception& ex) {
command_index--;
logError(this->getServerId(), "Failed to parse client base properties at index {}: {}. Search pattern: {}",
index - 1,
ex.what(),
pattern
);
return;
}
if(detailed) {
auto props = serverInstance->databaseHelper()->loadClientProperties(this->server, client_database_id, ClientType::CLIENT_TEAMSPEAK);
if (props) {
auto& properties = *props;
bulk.put_unchecked("client_badges", properties[property::CLIENT_BADGES].as<std::string>());
bulk.put_unchecked("client_version", properties[property::CLIENT_VERSION].as<std::string>());
bulk.put_unchecked("client_platform", properties[property::CLIENT_PLATFORM].as<std::string>());
bulk.put_unchecked("client_hwid", properties[property::CLIENT_HARDWARE_ID].as<std::string>());
}
}
});
if(command_index == 0)
return command_result{error::database_empty_result};
this->sendCommand(result);
return command_result{error::ok};
}
+6 -6
View File
@@ -714,7 +714,7 @@ command_result ConnectedClient::handleCommandBanAdd(Command &cmd) {
return command_result{permission::b_client_ban_create};
}
auto max_ban_time = server->calculate_permission(permission::i_client_ban_max_bantime, this->getClientDatabaseId(), this->getType(), 0);
auto max_ban_time = this->calculate_permission(permission::i_client_ban_max_bantime, this->getClientDatabaseId(), this->getType(), 0);
if(!max_ban_time.has_value) return command_result{permission::i_client_ban_max_bantime};
if (!max_ban_time.has_infinite_power()) {
if (max_ban_time.value < time)
@@ -1884,10 +1884,10 @@ command_result ConnectedClient::handleCommandComplainList(Command &cmd) {
result[index]["timestamp"] = chrono::duration_cast<chrono::seconds>(elm->created.time_since_epoch()).count();
for (const auto &e : dbInfo) {
if (e->cldbid == elm->target)
result[index]["tname"] = e->lastName;
if (e->cldbid == elm->invoker)
result[index]["fname"] = e->lastName;
if (e->client_database_id == elm->target)
result[index]["tname"] = e->client_nickname;
if (e->client_database_id == elm->invoker)
result[index]["fname"] = e->client_nickname;
}
index++;
}
@@ -2351,7 +2351,7 @@ command_result ConnectedClient::handleCommandQueryCreate(ts::Command &cmd) {
auto info = serverInstance->databaseHelper()->queryDatabaseInfo(server, {cmd["cldbid"].as<ClientDbId>()});
if(info.empty())
return command_result{error::database_empty_result};
uid = info[0]->uniqueId;
uid = info[0]->client_unique_id;
} else {
if(server) {
if(!permission::v2::permission_granted(1, server->calculate_permission(permission::b_client_query_create_own, this->getClientDatabaseId(), this->getType(), 0)))
@@ -98,7 +98,7 @@ void MusicClient::replay_song(const shared_ptr<music::PlayableSong> &entry, cons
auto info_list = serverInstance->databaseHelper()->queryDatabaseInfo(self->getServer(), {entry->getInvoker()});
if(!info_list.empty()) {
auto info = info_list.front();
invoker = "[URL=client://0/" + info->uniqueId + "~WolverinDEV]" + info->lastName + "[/URL]";
invoker = "[URL=client://0/" + info->client_unique_id + "~WolverinDEV]" + info->client_nickname + "[/URL]";
}
}
+16 -19
View File
@@ -102,7 +102,7 @@ command_result QueryClient::handleCommand(Command& cmd) {
case string_hash("bindinglist"):
return this->handleCommandBindingList(cmd);
case string_hash("serversnapshotdeploy"): {
#if 1
#if 0
return this->handleCommandServerSnapshotDeploy(cmd);
#else
auto cmd_str = cmd.build();
@@ -911,33 +911,30 @@ command_result QueryClient::handleCommandServerSnapshotDeployNew(const ts::comma
if(this->server) {
return command_result{error::not_implemented};
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_deploy, 1);
//host = this->server->properties()[property::VIRTUALSERVER_HOST].as<string>();
//port = this->server->properties()[property::VIRTUALSERVER_PORT].as<uint16_t>();
} else {
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_snapshot_deploy, 1);
}
std::string error{};
unique_lock server_create_lock(serverInstance->getVoiceServerManager()->server_create_lock);
//TODO: Create a server if no exists
auto result = serverInstance->getVoiceServerManager()->deploy_snapshot(error, this->server, command);
{ /* TODO: Only check if we're creating a new server */
auto instances = serverInstance->getVoiceServerManager()->serverInstances();
if(config::server::max_virtual_server != -1 && instances.size() > config::server::max_virtual_server)
using SnapshotDeployResult = VirtualServerManager::SnapshotDeployResult;
switch (result) {
case SnapshotDeployResult::SUCCESS:
break;
case SnapshotDeployResult::REACHED_SERVER_ID_LIMIT:
return command_result{error::server_max_vs_reached, "You cant create anymore virtual servers. (Server ID limit reached)"};
case SnapshotDeployResult::REACHED_SOFTWARE_SERVER_LIMIT:
return command_result{error::server_max_vs_reached, "You cant create anymore virtual servers. (Software limit reached)"};
case SnapshotDeployResult::REACHED_CONFIG_SERVER_LIMIT:
return command_result{error::server_max_vs_reached, "You reached the via config.yml enabled virtual server limit."};
if(instances.size() >= 65535)
return command_result{error::server_max_vs_reached, "You cant create anymore virtual servers. (Software limit reached)"};
case SnapshotDeployResult::CUSTOM_ERROR:
return command_result{error::vs_critical, error};
}
server_create_lock.unlock();
//TODO: Stop the server completely
if(!serverInstance->getVoiceServerManager()->deploy_snapshot(error, 111, command)) {
//TODO: Delete server is it was new
return command_result{error::vs_critical, error};
}
return command_result{error::ok};
}