Changed for new deploy algorithm

This commit is contained in:
WolverinDEV 2020-04-14 11:49:07 +02:00
parent 483e188c37
commit f205075d97
13 changed files with 415 additions and 99 deletions

@ -1 +1 @@
Subproject commit cc874a443ac40fabf0342b410dae5ae46045fa4f
Subproject commit df91da75149777e774da60e948439ef426a690dc

2
music

@ -1 +1 @@
Subproject commit 7ef7ea785aebc26d3f9c6e396270e7b03eccf587
Subproject commit 8e1ce32ae0b03f54efc54e76cd118cf01057159c

View File

@ -137,6 +137,13 @@ set(SERVER_SOURCE_FILES
src/weblist/WebListManager.cpp
src/weblist/TeamSpeakWebClient.cpp
src/snapshots/permission.cpp
src/snapshots/client.cpp
src/snapshots/channel.cpp
src/snapshots/server.cpp
src/snapshots/groups.cpp
src/snapshots/deploy.cpp
src/manager/ConversationManager.cpp
src/client/SpeakingClientHandshake.cpp
src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
@ -308,4 +315,25 @@ if (NOT DISABLE_JEMALLOC)
jemalloc
)
add_definitions(-DHAVE_JEMALLOC)
endif ()
endif ()
add_executable(Snapshots-Permissions-Test src/snapshots/permission.cpp tests/snapshots/permission.cpp)
target_link_libraries(Snapshots-Permissions-Test PUBLIC
TeaSpeak
CXXTerminal::static #Static
${StringVariable_LIBRARIES_STATIC}
${YAML_CPP_LIBRARIES}
pthread
stdc++fs
libevent::core libevent::pthreads
#Require a so
sqlite3
DataPipes::rtc::shared
tomcrypt::static
tommath::static
${glib20_DIR}/lib/x86_64-linux-gnu/libffi.so.7 ${nice_DIR}/lib/libnice.so.10
)
target_include_directories(Snapshots-Permissions-Test PUBLIC ${CMAKE_SOURCE_DIR}/server/src/)

View File

@ -37,7 +37,7 @@ void DatabaseHelper::tick() {
{
threads::MutexLock l(this->propsLock);
auto pcpy = this->cachedProperties;
for(const auto& mgr : pcpy){
for(const auto& mgr : pcpy) {
if(mgr->ownLock && system_clock::now() - mgr->lastAccess > minutes(5))
mgr->ownLock.reset();
if(mgr->properties.expired()) {
@ -573,7 +573,9 @@ bool DatabaseHelper::assignDatabaseId(sql::SqlManager *sql, ServerId id, std::sh
if(!res) return false;
auto insertTemplate = sql::model(sql, "INSERT INTO `clients` (`serverId`, `cldbId`, `clientUid`, `lastName`,`firstConnect`,`lastConnect`, `connections`) VALUES (:serverId, :cldbid, :cluid, :name, :fconnect, :lconnect, :connections)",
variable{":cluid", cl->getUid()}, variable{":name", cl->getDisplayName()}, variable{":fconnect", duration_cast<seconds>(system_clock::now().time_since_epoch()).count()}, variable{":lconnect", 0}, variable{":connections", 0});
variable{":cluid", cl->getUid()}, variable{":name", cl->getDisplayName()},
variable{":fconnect", duration_cast<seconds>(system_clock::now().time_since_epoch()).count()}, variable{":lconnect", 0},
variable{":connections", 0});
if(cldbid == 0){ //Completly new user
res = sql::command(sql, "SELECT `cldbid` FROM `clients` WHERE `serverId` = 0 ORDER BY `cldbid` DESC LIMIT 1").query([](ClientDbId* ptr, int length, char** values, char** names){
*ptr = static_cast<ClientDbId>(stoll(values[0]));

View File

@ -215,7 +215,6 @@ namespace ts {
bool isClientCached(const ClientDbId& /* client database id */);
void clearCache();
bool isLocalGroup(std::shared_ptr<Group>);
protected:
void handleChannelDeleted(const ChannelId& /* channel id */);

View File

@ -394,21 +394,8 @@ bool VirtualServerManager::deleteServer(shared_ptr<VirtualServer> server) {
}
this->handle->properties()[property::SERVERINSTANCE_SPOKEN_TIME_DELETED] += server->properties()[property::VIRTUALSERVER_SPOKEN_TIME].as<uint64_t>();
sql::command(this->handle->getSql(), "DELETE FROM `tokens` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `properties` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `permissions` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `groups` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `clients` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `channels` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `bannedClients` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `servers` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `musicbots` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `bannedClients` WHERE `serverId` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
sql::command(this->handle->getSql(), "DELETE FROM `ban_trigger` WHERE `server_id` = :sid", variable{":sid", server->getServerId()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
this->delete_server_in_db(server->serverId);
this->handle->getFileServer()->deleteServer(server);
return true;
}
@ -447,4 +434,32 @@ void VirtualServerManager::tickHandshakeClients() {
if(vserver)
vserver->tickHandshakingClients();
}
}
void VirtualServerManager::delete_server_in_db(ts::ServerId server_id) {
#define execute_delete(statement) \
result = sql::command(this->handle->getSql(), statement, variable{":sid", server_id}).execute(); \
if(!result) { \
logWarning(LOG_INSTANCE, "Failed to execute SQL command {}: {}", statement, result.fmtStr()); \
result = sql::result{}; \
}
sql::result result{};
execute_delete("DELETE FROM `tokens` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `properties` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `permissions` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `clients` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `channels` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `bannedClients` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `ban_trigger` WHERE `server_id` = :sid");
execute_delete("DELETE FROM `assignedGroups` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `servers` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `musicbots` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `conversations` WHERE `server_id` = :sid");
execute_delete("DELETE FROM `conversation_blocks` WHERE `server_id` = :sid");
execute_delete("DELETE FROM `playlists` WHERE `serverId` = :sid");
execute_delete("DELETE FROM `playlist_songs` WHERE `serverId` = :sid");
}

View File

@ -5,95 +5,104 @@
#include "client/voice/PrecomputedPuzzles.h"
#include "server/VoiceIOManager.h"
#include "VirtualServer.h"
#include <query/command3.h>
#include "snapshots/snapshot.h"
namespace ts {
namespace server {
class InstanceHandler;
namespace ts::server {
class InstanceHandler;
struct ServerReport {
size_t avariable;
size_t online;
struct ServerReport {
size_t avariable;
size_t online;
size_t slots;
size_t onlineClients;
size_t onlineChannels;
};
class VirtualServerManager {
public:
enum State {
STOPPED,
STARTING,
STARTED,
STOPPING
};
size_t slots;
size_t onlineClients;
size_t onlineChannels;
};
class VirtualServerManager {
public:
enum State {
STOPPED,
STARTING,
STARTED,
STOPPING
};
explicit VirtualServerManager(InstanceHandler*);
~VirtualServerManager();
explicit VirtualServerManager(InstanceHandler*);
~VirtualServerManager();
bool initialize(bool execute_autostart = true);
bool initialize(bool execute_autostart = true);
std::shared_ptr<VirtualServer> create_server(std::string hosts, uint16_t port);
bool deleteServer(std::shared_ptr<VirtualServer>);
std::shared_ptr<VirtualServer> create_server(std::string hosts, uint16_t port);
bool deleteServer(std::shared_ptr<VirtualServer>);
std::shared_ptr<VirtualServer> findServerById(ServerId);
std::shared_ptr<VirtualServer> findServerByPort(uint16_t);
uint16_t next_available_port();
ServerId next_available_server_id(bool& /* success */);
std::deque<std::shared_ptr<VirtualServer>> serverInstances(){
threads::MutexLock l(this->instanceLock);
return instances;
}
std::shared_ptr<VirtualServer> findServerById(ServerId);
std::shared_ptr<VirtualServer> findServerByPort(uint16_t);
uint16_t next_available_port();
ServerId next_available_server_id(bool& /* success */);
ServerReport report();
OnlineClientReport clientReport();
size_t runningServers();
size_t usedSlots();
std::deque<std::shared_ptr<VirtualServer>> serverInstances(){
threads::MutexLock l(this->instanceLock);
return instances;
}
void executeAutostart();
void shutdownAll(const std::string&);
ServerReport report();
OnlineClientReport clientReport();
size_t runningServers();
size_t usedSlots();
//Dotn use shared_ptr references to keep sure that they be hold in memory
bool createServerSnapshot(Command &cmd, std::shared_ptr<VirtualServer> server, int version, std::string &error);
std::shared_ptr<VirtualServer> createServerFromSnapshot(std::shared_ptr<VirtualServer> old, std::string, uint16_t, const ts::Command &, std::string &);
void executeAutostart();
void shutdownAll(const std::string&);
udp::PuzzleManager* rsaPuzzles() { return this->puzzles; }
//Dotn use shared_ptr references to keep sure that they be hold in memory
bool createServerSnapshot(Command &cmd, std::shared_ptr<VirtualServer> server, int version, std::string &error);
std::shared_ptr<VirtualServer> createServerFromSnapshot(std::shared_ptr<VirtualServer> old, std::string, uint16_t, const ts::Command &, std::string &);
bool deploy_snapshot(std::string& /* error */, ServerId /* target server id */, const command_parser& /* source */);
event::EventExecutor* get_join_loop() { return this->join_loop; }
event::EventExecutor* get_executor_loop() { return this->execute_loop; }
udp::PuzzleManager* rsaPuzzles() { return this->puzzles; }
inline void adjust_executor_threads() {
std::unique_lock instance_lock(this->instanceLock);
auto instance_count = this->instances.size();
instance_lock.unlock();
event::EventExecutor* get_join_loop() { return this->join_loop; }
event::EventExecutor* get_executor_loop() { return this->execute_loop; }
auto threads = std::min(config::threads::voice::execute_per_server * instance_count, config::threads::voice::execute_limit);
this->execute_loop->threads(threads);
}
io::VoiceIOManager* ioManager(){ return this->_ioManager; }
inline void adjust_executor_threads() {
std::unique_lock instance_lock(this->instanceLock);
auto instance_count = this->instances.size();
instance_lock.unlock();
threads::Mutex server_create_lock;
auto threads = std::min(config::threads::voice::execute_per_server * instance_count, config::threads::voice::execute_limit);
this->execute_loop->threads(threads);
}
io::VoiceIOManager* ioManager(){ return this->_ioManager; }
State getState() { return this->state; }
private:
State state = State::STOPPED;
InstanceHandler* handle;
threads::Mutex instanceLock;
std::deque<std::shared_ptr<VirtualServer>> instances;
udp::PuzzleManager* puzzles{nullptr};
threads::Mutex server_create_lock;
event::EventExecutor* execute_loop = nullptr;
event::EventExecutor* join_loop = nullptr;
threads::Scheduler* handshakeTickers = nullptr;
io::VoiceIOManager* _ioManager = nullptr;
State getState() { return this->state; }
private:
State state = State::STOPPED;
InstanceHandler* handle;
threads::Mutex instanceLock;
std::deque<std::shared_ptr<VirtualServer>> instances;
udp::PuzzleManager* puzzles{nullptr};
struct {
std::thread executor{};
std::condition_variable condition;
std::mutex lock;
} acknowledge;
event::EventExecutor* execute_loop = nullptr;
event::EventExecutor* join_loop = nullptr;
threads::Scheduler* handshakeTickers = nullptr;
io::VoiceIOManager* _ioManager = nullptr;
void tickHandshakeClients();
};
}
struct {
std::thread executor{};
std::condition_variable condition;
std::mutex lock;
} acknowledge;
void tickHandshakeClients();
void delete_server_in_db(ServerId /* server id */);
/* methods used to preprocess a snapshot */
bool deploy_ts3_snapshot(std::string& /* error */, ServerId /* target server id */, const command_parser& /* source */);
bool deploy_teaspeak_snapshot(std::string& /* error */, ServerId /* target server id */, const command_parser& /* source */);
/* actual deploy method */
bool deploy_raw_snapshot(std::string& /* error */, ServerId /* target server id */, const command_parser& /* source */, const std::string& /* hash */, size_t /* offset */, snapshots::type /* type */, snapshots::version_t /* version */);
};
}

View File

@ -171,6 +171,7 @@ namespace ts::server {
command_result handleCommandServerIdGetByPort(Command&);
command_result handleCommandServerSnapshotDeploy(Command&);
command_result handleCommandServerSnapshotDeployNew(const command_parser&);
command_result handleCommandServerSnapshotCreate(Command&);
command_result handleCommandServerProcessStop(Command&);

View File

@ -100,9 +100,14 @@ command_result QueryClient::handleCommand(Command& cmd) {
return this->handleCommandHostInfo(cmd);
case string_hash("bindinglist"):
return this->handleCommandBindingList(cmd);
case string_hash("serversnapshotdeploy"):
return this->handleCommandServerSnapshotDeploy(cmd);
case string_hash("serversnapshotdeploy"): {
//return this->handleCommandServerSnapshotDeploy(cmd);
auto cmd_str = cmd.build();
ts::command_parser parser{cmd_str};
if(!parser.parse(true)) return command_result{error::vs_critical};
return this->handleCommandServerSnapshotDeployNew(parser);
}
case string_hash("serversnapshotcreate"):
return this->handleCommandServerSnapshotCreate(cmd);
case string_hash("serverprocessstop"):
@ -869,6 +874,32 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
return command_result{error::ok};
}
command_result QueryClient::handleCommandServerSnapshotDeployNew(const ts::command_parser &command) {
CMD_RESET_IDLE;
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
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};
}
command_result QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_create, 1);
CMD_RESET_IDLE;

View File

@ -44,7 +44,7 @@ if(!result && result.msg().find(ignore) == string::npos){
#define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")");
#define CURRENT_DATABASE_VERSION 11
#define CURRENT_DATABASE_VERSION 12
#define CURRENT_PERMISSION_VERSION 3
#define CLIENT_UID_LENGTH "64"
@ -144,7 +144,7 @@ bool SqlDataManager::initialize(std::string& error) {
//Advanced locked test
{
bool property_exists = false;
sql::command(this->sql(), "SELECT * FORM `general` WHERE `key` = :key", variable{":key", "lock_test"}).query([](bool& flag, int, string*, string*) { flag = true; }, property_exists);
sql::command(this->sql(), "SELECT * FORM `general` WHERE `key` = :key", variable{":key", "lock_test"}).query([&](int, string*, string*) { property_exists = true; });
sql::result res;
if(!property_exists) {
res = sql::command(this->sql(), "INSERT INTO `general` (`key`, `value`) VALUES (:key, :value);", variable{":key", "lock_test"}, variable{":value", "UPDATE ME!"}).execute();
@ -411,6 +411,65 @@ ROLLBACK;
CREATE_INDEX("conversations", "server_id");
CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id");
db_version(11);
case 11:
/* update the group table */
{
result = sql::command(this->sql(), "CREATE TABLE `groups_v2` (`serverId` INT NOT NULL, `groupId` INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY, `target` INT, `type` INT, `displayName` VARCHAR(128));").execute();
if(!result) {
error = "failed to create new groups table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "INSERT INTO `groups_v2`(`serverId`, `groupId`, `target`, `type`, `displayName`) SELECT `serverId`, `groupId`, `target`, `type`, `displayName` FROM `groups`;").execute();
if(!result) {
sql::command(this->sql(), "DROP TABLE `groups_v2`;").execute();
error = "failed to insert data into the new groups table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "DROP TABLE `groups`;").execute();
if(!result) {
error = "failed to delete old groups table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "ALTER TABLE `groups_v2` RENAME TO groups;").execute();
if(!result) {
error = "failed to rename new groups table to the old groups table (" + result.fmtStr() + ")";
return false;
}
CREATE_INDEX2R("groups", "serverId", "groupId");
CREATE_INDEX("groups", "serverId");
result = sql::command(this->sql(), "ALTER TABLE `groups` ADD COLUMN `original_id` INTEGER DEFAULT 0;").execute();
if(!result) {
error = "Failed to alter groups table";
return false;
}
}
/* update the client table */
{
result = sql::command(this->sql(), "CREATE TABLE `clients_v2` (`serverId` INT NOT NULL, `cldbid` INTEGER, `original_client_id` INTEGER DEFAULT 0, `clientUid` VARCHAR(64) NOT NULL, `firstConnect` BIGINT DEFAULT 0, `lastConnect` BIGINT DEFAULT 0, `connections` INT DEFAULT 0, `lastName` VARCHAR(128) DEFAULT '', UNIQUE(`serverId`, `clientUid`));").execute();
if(!result) {
error = "failed to create new clients table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "INSERT INTO `clients_v2` (`serverId`, `cldbid`, `clientUid`, `firstConnect`, `lastConnect`, `connections`, `lastName`) SELECT `serverId`, `cldbid`, `clientUid`, `firstConnect`, `lastConnect`, `connections`, `lastName` FROM `clients`;").execute();
if(!result) {
sql::command(this->sql(), "DROP TABLE `groups_v2`;").execute();
error = "failed to insert data into the new clients table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "DROP TABLE `clients`;").execute();
if(!result) {
error = "failed to delete old clients table (" + result.fmtStr() + ")";
return false;
}
result = sql::command(this->sql(), "ALTER TABLE `clients_v2` RENAME TO clients;").execute();
if(!result) {
error = "failed to rename new clients table to the old clients table (" + result.fmtStr() + ")";
return false;
}
}
db_version(12);
default:
break;
}

View File

@ -8,6 +8,8 @@
#include "./client.h"
#include "./groups.h"
#include "../VirtualServerManager.h"
#include "../InstanceHandler.h"
#include <sql/insert.h>
#include <log/LogUtils.h>
using namespace ts;
@ -297,6 +299,74 @@ bool VirtualServerManager::deploy_raw_snapshot(std::string &error, ts::ServerId
/* lets start inserting data to the database */
{
/* cleanup all old data */
this->delete_server_in_db(server_id);
/* register clients */
{
//`original_client_id` INTEGER DEFAULT 0
//CREATE TABLE `clients_v2` (`serverId` INT NOT NULL, `cldbid` INTEGER, `clientUid` VARCHAR(64) NOT NULL, `firstConnect` BIGINT DEFAULT 0, `lastConnect` BIGINT DEFAULT 0, `connections` INT DEFAULT 0, `lastName` VARCHAR(128) DEFAULT '', UNIQUE(`serverId`, `clientUid`));
sql::InsertQuery insert_general_query{"clients",
sql::Column<ServerId>("serverId"),
sql::Column<ClientDbId>("original_client_id"),
sql::Column<std::string>("clientUid"),
sql::Column<int64_t>("firstConnect"),
sql::Column<int64_t>("lastConnect"),
sql::Column<uint64_t>("connections"),
sql::Column<std::string>("lastName")
};
sql::InsertQuery insert_server_query{"clients",
sql::Column<ServerId>("serverId"),
sql::Column<ClientDbId>("original_client_id"),
sql::Column<std::string>("clientUid"),
sql::Column<int64_t>("firstConnect"),
sql::Column<int64_t>("lastConnect"),
sql::Column<uint64_t>("connections"),
sql::Column<std::string>("lastName")
};
for(const auto& client : parsed_clients) {
/*
insert_general_query.add_entry(
server_id,
client.parsed_data.database_id,
client.parsed_data.unique_id,
std::chrono::floor<std::chrono::seconds>(client.parsed_data.timestamp_created.time_since_epoch()).count(),
std::chrono::floor<std::chrono::seconds>(client.parsed_data.timestamp_last_connected.time_since_epoch()).count(),
client.parsed_data.client_total_connections,
client.parsed_data.nickname
);
*/
insert_general_query.add_entry(
server_id,
client.parsed_data.database_id,
client.parsed_data.unique_id,
std::chrono::floor<std::chrono::seconds>(client.parsed_data.timestamp_created.time_since_epoch()).count()
);
}
auto result = insert_general_query.execute(this->handle->getSql(), true);
for(const auto& fail : result.failed_entries)
logWarning(server_id, "Failed to insert client {} into the database: {}", parsed_clients[std::get<0>(fail)], std::get<1>(fail).fmtStr());
sql::command{this->handle->getSql(), "SELECT `original_client_id`,`cldbid` FROM `clients` WHERE `serverId` = :sid;"}
.value(":serverId", server_id)
.query([&](int length, std::string* values, std::string* names) {
ClientDbId original_id{0}, new_id{0};
try {
original_id = std::stoull(values[0]);
new_id = std::stoull(values[1]);
} catch (std::exception& ex) {
logWarning(server_id, "Failed to parse client database entry mapping for group id {} (New ID: {})", values[1], values[0]);
return;
}
server_group_id_mapping[original_id] = new_id;
});
}
/* channels */
{
/* Assign each channel a new id */
@ -338,18 +408,77 @@ bool VirtualServerManager::deploy_raw_snapshot(std::string &error, ts::ServerId
/* server groups */
{
/* TODO: Insert to the database & load result */
sql::model insert_model{this->handle->getSql(), "INSERT INTO `groups` (`serverId`, `target`, `type`, `displayName`, `original_id`) VALUES (:serverId, :target, :type, :name, :id)"};
insert_model.value(":serverId", server_id).value(":target", GroupTarget::GROUPTARGET_SERVER).value(":type", GroupType::GROUP_TYPE_NORMAL);
for(auto& group : parsed_server_groups) {
auto result = insert_model.command().value(":name", group.parsed_data.name).value(":id", group.parsed_data.group_id).execute();
if(!result)
logWarning(server_id, "Failed to insert server group \"{}\" into the database", group.parsed_data.name);
}
sql::command{this->handle->getSql(), "SELECT `original_id`,`groupId` FROM `groups` WHERE `serverId` = :sid AND `target` = :target AND `type` = :type"}
.value(":serverId", server_id).value(":target", GroupTarget::GROUPTARGET_SERVER).value(":type", GroupType::GROUP_TYPE_NORMAL)
.query([&](int length, std::string* values, std::string* names) {
GroupId original_id{0}, new_id{0};
try {
original_id = std::stoull(values[0]);
new_id = std::stoull(values[1]);
} catch (std::exception& ex) {
logWarning(server_id, "Failed to parse server group mapping for group id {} (New ID: {})", values[1], values[0]);
return;
}
server_group_id_mapping[original_id] = new_id;
});
}
/* channel groups */
{
/* TODO: Insert to the database & load the result into the mapping */
sql::model insert_model{this->handle->getSql(), "INSERT INTO `groups` (`serverId`, `target`, `type`, `displayName`, `original_id`) VALUES (:serverId, :target, :type, :name, :id)"};
insert_model.value(":serverId", server_id).value(":target", GroupTarget::GROUPTARGET_CHANNEL).value(":type", GroupType::GROUP_TYPE_NORMAL);
for(auto& group : parsed_server_groups) {
auto result = insert_model.command().value(":name", group.parsed_data.name).value(":id", group.parsed_data.group_id).execute();
if(!result)
logWarning(server_id, "Failed to insert channel group \"{}\" into the database", group.parsed_data.name);
}
sql::command{this->handle->getSql(), "SELECT `original_id`,`groupId` FROM `groups` WHERE `serverId` = :sid AND `target` = :target AND `type` = :type"}
.value(":serverId", server_id).value(":target", GroupTarget::GROUPTARGET_CHANNEL).value(":type", GroupType::GROUP_TYPE_NORMAL)
.query([&](int length, std::string* values, std::string* names) {
GroupId original_id{0}, new_id{0};
try {
original_id = std::stoull(values[0]);
new_id = std::stoull(values[1]);
} catch (std::exception& ex) {
logWarning(server_id, "Failed to parse channel group mapping for group id {} (New ID: {})", values[1], values[0]);
return;
}
channel_group_id_mapping[original_id] = new_id;
});
}
#define INSERT_PERMISSION_COMMAND "INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate`) VALUES (:serverId, :type, :id, :chId, :permId, :value, :grant, :flag_skip, :flag_negate)"
/* client permissions */
{
sql::InsertQuery insert_query{"permissions",
sql::Column<ServerId>("serverId"),
sql::Column<permission::PermissionSqlType>("type"),
sql::Column<uint64_t>("id"),
sql::Column<ChannelId>("channelId"),
sql::Column<std::string>("permId"),
sql::Column<permission::PermissionValue>("value"),
sql::Column<permission::PermissionValue>("grant"),
sql::Column<bool>("flag_skip"),
sql::Column<bool>("flag_negate"),
};
for(auto& permission : client_permissions) {
}
auto result = insert_query.execute(this->handle->getSql(), true);
}
/* register clients in the database */

View File

@ -0,0 +1,43 @@
//
// Created by WolverinDEV on 11/04/2020.
//
#include <snapshots/permission.h>
using namespace ts::server::snapshots;
void test_write() {
std::string error{};
size_t offset{0};
ts::command_builder result{""};
permission_writer writer{type::TEAMSPEAK, 0, result, ts::permission::teamspeak::GroupType::GENERAL};
std::deque<permission_entry> entries{};
{
{
auto& entry = entries.emplace_back();
entry.type = ts::permission::resolvePermissionData("b_virtualserver_modify_host");
entry.granted = {2, true};
entry.value = {4, true};
}
{
auto& entry = entries.emplace_back();
entry.type = ts::permission::resolvePermissionData("i_icon_id");
entry.granted = {0, false};
entry.value = {4, true};
entry.flag_skip = true;
}
}
if(!writer.write(error, offset, entries)) {
std::cerr << error << "\n";
assert(false);
return;
}
std::cout << "Offset: " << offset << ". Command: " << result.build() << "\n";
}
int main() {
test_write();
}

2
shared

@ -1 +1 @@
Subproject commit ee7f26b7ed883027f0a81ece1c2aacd41053ce1e
Subproject commit 707736d896f46489133e6da6b7543238274c37e6