Changed for new deploy algorithm
This commit is contained in:
parent
483e188c37
commit
f205075d97
@ -1 +1 @@
|
||||
Subproject commit cc874a443ac40fabf0342b410dae5ae46045fa4f
|
||||
Subproject commit df91da75149777e774da60e948439ef426a690dc
|
2
music
2
music
@ -1 +1 @@
|
||||
Subproject commit 7ef7ea785aebc26d3f9c6e396270e7b03eccf587
|
||||
Subproject commit 8e1ce32ae0b03f54efc54e76cd118cf01057159c
|
@ -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/)
|
@ -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]));
|
||||
|
@ -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 */);
|
||||
|
@ -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");
|
||||
}
|
@ -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 */);
|
||||
};
|
||||
}
|
@ -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&);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
43
server/tests/snapshots/permission.cpp
Normal file
43
server/tests/snapshots/permission.cpp
Normal 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
2
shared
@ -1 +1 @@
|
||||
Subproject commit ee7f26b7ed883027f0a81ece1c2aacd41053ce1e
|
||||
Subproject commit 707736d896f46489133e6da6b7543238274c37e6
|
Loading…
Reference in New Issue
Block a user