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/WebListManager.cpp
 | 
				
			||||||
        src/weblist/TeamSpeakWebClient.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/manager/ConversationManager.cpp
 | 
				
			||||||
        src/client/SpeakingClientHandshake.cpp
 | 
					        src/client/SpeakingClientHandshake.cpp
 | 
				
			||||||
        src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
 | 
					        src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
 | 
				
			||||||
@ -308,4 +315,25 @@ if (NOT DISABLE_JEMALLOC)
 | 
				
			|||||||
            jemalloc
 | 
					            jemalloc
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    add_definitions(-DHAVE_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);
 | 
					        threads::MutexLock l(this->propsLock);
 | 
				
			||||||
        auto pcpy = this->cachedProperties;
 | 
					        auto pcpy = this->cachedProperties;
 | 
				
			||||||
        for(const auto& mgr : pcpy){
 | 
					        for(const auto& mgr : pcpy) {
 | 
				
			||||||
            if(mgr->ownLock && system_clock::now() - mgr->lastAccess > minutes(5))
 | 
					            if(mgr->ownLock && system_clock::now() - mgr->lastAccess > minutes(5))
 | 
				
			||||||
                mgr->ownLock.reset();
 | 
					                mgr->ownLock.reset();
 | 
				
			||||||
            if(mgr->properties.expired()) {
 | 
					            if(mgr->properties.expired()) {
 | 
				
			||||||
@ -573,7 +573,9 @@ bool DatabaseHelper::assignDatabaseId(sql::SqlManager *sql, ServerId id, std::sh
 | 
				
			|||||||
        if(!res) return false;
 | 
					        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)",
 | 
					        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
 | 
					        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){
 | 
					            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]));
 | 
					                *ptr = static_cast<ClientDbId>(stoll(values[0]));
 | 
				
			||||||
 | 
				
			|||||||
@ -215,7 +215,6 @@ namespace ts {
 | 
				
			|||||||
            bool isClientCached(const ClientDbId& /* client database id */);
 | 
					            bool isClientCached(const ClientDbId& /* client database id */);
 | 
				
			||||||
            void clearCache();
 | 
					            void clearCache();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
            bool isLocalGroup(std::shared_ptr<Group>);
 | 
					            bool isLocalGroup(std::shared_ptr<Group>);
 | 
				
			||||||
        protected:
 | 
					        protected:
 | 
				
			||||||
            void handleChannelDeleted(const ChannelId& /* channel id */);
 | 
					            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>();
 | 
					    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"});
 | 
					    this->delete_server_in_db(server->serverId);
 | 
				
			||||||
    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->handle->getFileServer()->deleteServer(server);
 | 
					    this->handle->getFileServer()->deleteServer(server);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -447,4 +434,32 @@ void VirtualServerManager::tickHandshakeClients() {
 | 
				
			|||||||
        if(vserver)
 | 
					        if(vserver)
 | 
				
			||||||
            vserver->tickHandshakingClients();
 | 
					            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 "client/voice/PrecomputedPuzzles.h"
 | 
				
			||||||
#include "server/VoiceIOManager.h"
 | 
					#include "server/VoiceIOManager.h"
 | 
				
			||||||
#include "VirtualServer.h"
 | 
					#include "VirtualServer.h"
 | 
				
			||||||
 | 
					#include <query/command3.h>
 | 
				
			||||||
 | 
					#include "snapshots/snapshot.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ts {
 | 
					namespace ts::server {
 | 
				
			||||||
    namespace server {
 | 
					    class InstanceHandler;
 | 
				
			||||||
        class InstanceHandler;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct ServerReport {
 | 
					    struct ServerReport {
 | 
				
			||||||
            size_t avariable;
 | 
					        size_t avariable;
 | 
				
			||||||
            size_t online;
 | 
					        size_t online;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            size_t slots;
 | 
					        size_t slots;
 | 
				
			||||||
            size_t onlineClients;
 | 
					        size_t onlineClients;
 | 
				
			||||||
            size_t onlineChannels;
 | 
					        size_t onlineChannels;
 | 
				
			||||||
        };
 | 
					    };
 | 
				
			||||||
        class VirtualServerManager {
 | 
					    class VirtualServerManager {
 | 
				
			||||||
            public:
 | 
					        public:
 | 
				
			||||||
                enum State {
 | 
					            enum State {
 | 
				
			||||||
                    STOPPED,
 | 
					                STOPPED,
 | 
				
			||||||
                    STARTING,
 | 
					                STARTING,
 | 
				
			||||||
                    STARTED,
 | 
					                STARTED,
 | 
				
			||||||
                    STOPPING
 | 
					                STOPPING
 | 
				
			||||||
                };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                explicit VirtualServerManager(InstanceHandler*);
 | 
					            explicit VirtualServerManager(InstanceHandler*);
 | 
				
			||||||
                ~VirtualServerManager();
 | 
					            ~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);
 | 
					            std::shared_ptr<VirtualServer> create_server(std::string hosts, uint16_t port);
 | 
				
			||||||
                bool deleteServer(std::shared_ptr<VirtualServer>);
 | 
					            bool deleteServer(std::shared_ptr<VirtualServer>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::shared_ptr<VirtualServer> findServerById(ServerId);
 | 
					            std::shared_ptr<VirtualServer> findServerById(ServerId);
 | 
				
			||||||
                std::shared_ptr<VirtualServer> findServerByPort(uint16_t);
 | 
					            std::shared_ptr<VirtualServer> findServerByPort(uint16_t);
 | 
				
			||||||
                uint16_t next_available_port();
 | 
					            uint16_t next_available_port();
 | 
				
			||||||
                ServerId next_available_server_id(bool& /* success */);
 | 
					            ServerId next_available_server_id(bool& /* success */);
 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                std::deque<std::shared_ptr<VirtualServer>> serverInstances(){
 | 
					 | 
				
			||||||
                    threads::MutexLock l(this->instanceLock);
 | 
					 | 
				
			||||||
                    return instances;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ServerReport report();
 | 
					            std::deque<std::shared_ptr<VirtualServer>> serverInstances(){
 | 
				
			||||||
                OnlineClientReport clientReport();
 | 
					                threads::MutexLock l(this->instanceLock);
 | 
				
			||||||
                size_t runningServers();
 | 
					                return instances;
 | 
				
			||||||
                size_t usedSlots();
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                void executeAutostart();
 | 
					            ServerReport report();
 | 
				
			||||||
                void shutdownAll(const std::string&);
 | 
					            OnlineClientReport clientReport();
 | 
				
			||||||
 | 
					            size_t runningServers();
 | 
				
			||||||
 | 
					            size_t usedSlots();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                //Dotn use shared_ptr references to keep sure that they be hold in memory
 | 
					            void executeAutostart();
 | 
				
			||||||
                bool createServerSnapshot(Command &cmd, std::shared_ptr<VirtualServer> server, int version, std::string &error);
 | 
					            void shutdownAll(const std::string&);
 | 
				
			||||||
                std::shared_ptr<VirtualServer> createServerFromSnapshot(std::shared_ptr<VirtualServer> old, std::string, uint16_t, const ts::Command &, 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; }
 | 
					            udp::PuzzleManager* rsaPuzzles() { return this->puzzles; }
 | 
				
			||||||
                event::EventExecutor* get_executor_loop() { return this->execute_loop; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                inline void adjust_executor_threads() {
 | 
					            event::EventExecutor* get_join_loop() { return this->join_loop; }
 | 
				
			||||||
                    std::unique_lock instance_lock(this->instanceLock);
 | 
					            event::EventExecutor* get_executor_loop() { return this->execute_loop; }
 | 
				
			||||||
                    auto instance_count = this->instances.size();
 | 
					 | 
				
			||||||
                    instance_lock.unlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    auto threads = std::min(config::threads::voice::execute_per_server * instance_count, config::threads::voice::execute_limit);
 | 
					            inline void adjust_executor_threads() {
 | 
				
			||||||
                    this->execute_loop->threads(threads);
 | 
					                std::unique_lock instance_lock(this->instanceLock);
 | 
				
			||||||
                }
 | 
					                auto instance_count = this->instances.size();
 | 
				
			||||||
                io::VoiceIOManager* ioManager(){ return this->_ioManager; }
 | 
					                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; }
 | 
					            threads::Mutex server_create_lock;
 | 
				
			||||||
            private:
 | 
					 | 
				
			||||||
                State state = State::STOPPED;
 | 
					 | 
				
			||||||
                InstanceHandler* handle;
 | 
					 | 
				
			||||||
                threads::Mutex instanceLock;
 | 
					 | 
				
			||||||
                std::deque<std::shared_ptr<VirtualServer>> instances;
 | 
					 | 
				
			||||||
                udp::PuzzleManager* puzzles{nullptr};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                event::EventExecutor* execute_loop = nullptr;
 | 
					            State getState() { return this->state; }
 | 
				
			||||||
                event::EventExecutor* join_loop = nullptr;
 | 
					        private:
 | 
				
			||||||
                threads::Scheduler* handshakeTickers = nullptr;
 | 
					            State state = State::STOPPED;
 | 
				
			||||||
                io::VoiceIOManager* _ioManager = nullptr;
 | 
					            InstanceHandler* handle;
 | 
				
			||||||
 | 
					            threads::Mutex instanceLock;
 | 
				
			||||||
 | 
					            std::deque<std::shared_ptr<VirtualServer>> instances;
 | 
				
			||||||
 | 
					            udp::PuzzleManager* puzzles{nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                struct {
 | 
					            event::EventExecutor* execute_loop = nullptr;
 | 
				
			||||||
                    std::thread executor{};
 | 
					            event::EventExecutor* join_loop = nullptr;
 | 
				
			||||||
                    std::condition_variable condition;
 | 
					            threads::Scheduler* handshakeTickers = nullptr;
 | 
				
			||||||
                    std::mutex lock;
 | 
					            io::VoiceIOManager* _ioManager = nullptr;
 | 
				
			||||||
                } acknowledge;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                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 handleCommandServerIdGetByPort(Command&);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            command_result handleCommandServerSnapshotDeploy(Command&);
 | 
					            command_result handleCommandServerSnapshotDeploy(Command&);
 | 
				
			||||||
 | 
					            command_result handleCommandServerSnapshotDeployNew(const command_parser&);
 | 
				
			||||||
            command_result handleCommandServerSnapshotCreate(Command&);
 | 
					            command_result handleCommandServerSnapshotCreate(Command&);
 | 
				
			||||||
            command_result handleCommandServerProcessStop(Command&);
 | 
					            command_result handleCommandServerProcessStop(Command&);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -100,9 +100,14 @@ command_result QueryClient::handleCommand(Command& cmd) {
 | 
				
			|||||||
            return this->handleCommandHostInfo(cmd);
 | 
					            return this->handleCommandHostInfo(cmd);
 | 
				
			||||||
        case string_hash("bindinglist"):
 | 
					        case string_hash("bindinglist"):
 | 
				
			||||||
            return this->handleCommandBindingList(cmd);
 | 
					            return this->handleCommandBindingList(cmd);
 | 
				
			||||||
        case string_hash("serversnapshotdeploy"):
 | 
					        case string_hash("serversnapshotdeploy"): {
 | 
				
			||||||
            return this->handleCommandServerSnapshotDeploy(cmd);
 | 
					            //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"):
 | 
					        case string_hash("serversnapshotcreate"):
 | 
				
			||||||
            return this->handleCommandServerSnapshotCreate(cmd);
 | 
					            return this->handleCommandServerSnapshotCreate(cmd);
 | 
				
			||||||
        case string_hash("serverprocessstop"):
 | 
					        case string_hash("serverprocessstop"):
 | 
				
			||||||
@ -869,6 +874,32 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
 | 
				
			|||||||
    return command_result{error::ok};
 | 
					    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) {
 | 
					command_result QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
 | 
				
			||||||
    ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_create, 1);
 | 
					    ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_create, 1);
 | 
				
			||||||
    CMD_RESET_IDLE;
 | 
					    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 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 CURRENT_PERMISSION_VERSION 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CLIENT_UID_LENGTH "64"
 | 
					#define CLIENT_UID_LENGTH "64"
 | 
				
			||||||
@ -144,7 +144,7 @@ bool SqlDataManager::initialize(std::string& error) {
 | 
				
			|||||||
    //Advanced locked test
 | 
					    //Advanced locked test
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bool property_exists = false;
 | 
					        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;
 | 
					        sql::result res;
 | 
				
			||||||
        if(!property_exists) {
 | 
					        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();
 | 
					            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_INDEX("conversations", "server_id");
 | 
				
			||||||
                CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id");
 | 
					                CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id");
 | 
				
			||||||
                db_version(11);
 | 
					                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:
 | 
					            default:
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,8 @@
 | 
				
			|||||||
#include "./client.h"
 | 
					#include "./client.h"
 | 
				
			||||||
#include "./groups.h"
 | 
					#include "./groups.h"
 | 
				
			||||||
#include "../VirtualServerManager.h"
 | 
					#include "../VirtualServerManager.h"
 | 
				
			||||||
 | 
					#include "../InstanceHandler.h"
 | 
				
			||||||
 | 
					#include <sql/insert.h>
 | 
				
			||||||
#include <log/LogUtils.h>
 | 
					#include <log/LogUtils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace ts;
 | 
					using namespace ts;
 | 
				
			||||||
@ -297,6 +299,74 @@ bool VirtualServerManager::deploy_raw_snapshot(std::string &error, ts::ServerId
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* lets start inserting data to the database */
 | 
					    /* 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 */
 | 
					        /* channels */
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            /* Assign each channel a new id */
 | 
					            /* Assign each channel a new id */
 | 
				
			||||||
@ -338,18 +408,77 @@ bool VirtualServerManager::deploy_raw_snapshot(std::string &error, ts::ServerId
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* server groups */
 | 
					        /* 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 */
 | 
					        /* 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 */
 | 
					        /* 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 */
 | 
					        /* 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user