#pragma once #include #include #include #include #include #include #include #include #include "Group.h" #include "Properties.h" #include "query/Command.h" #include "channel/ServerChannel.h" #include "manager/BanManager.h" #include "Definitions.h" #include "ConnectionStatistics.h" #include "manager/TokeManager.h" #include "manager/ComplainManager.h" #include "DatabaseHelper.h" #include "manager/LetterManager.h" #include "Configuration.h" #include "protocol/ringbuffer.h" #include #undef byte #ifdef COMPILE_WEB_CLIENT #include "server/WebServer.h" #endif template inline bool operator==(T* elm, const std::shared_ptr<_Tp>& __a) noexcept { return elm == __a.get(); } template inline bool operator==(const std::shared_ptr<_Tp>& __a, T* elm) noexcept { return elm == __a.get(); } template inline bool operator!=(T* elm, const std::shared_ptr<_Tp>& __a) noexcept { return elm != __a.get(); } template inline bool operator!=(const std::shared_ptr<_Tp>& __a, T* elm) noexcept { return elm != __a.get(); } namespace ts { class ServerChannelTree; namespace music { class MusicBotManager; } namespace server { class ConnectedClient; class VoiceClient; class QueryClient; class WebClient; class InternalClient; class InstanceHandler; class VoiceServer; class QueryServer; class FileServer; class SpeakingClient; class WebControlServer; namespace conversation { class ConversationManager; } struct ServerState { enum value { OFFLINE, BOOTING, ONLINE, SUSPENDING, DELETING }; inline static std::string string(value state) { switch (state) { case ServerState::OFFLINE: return "offline"; case ServerState::BOOTING: return "booting"; case ServerState::ONLINE: return "online"; case ServerState::SUSPENDING: return "suspending"; case ServerState::DELETING: return "deleting"; default: return "unknown"; } } }; struct OnlineClientReport { uint16_t clients_ts = 0; uint16_t clients_web = 0; uint16_t queries = 0; uint16_t bots = 0; }; struct CalculateCache { bool global_skip = false; bool global_skip_set = false; std::shared_ptr client_permissions; std::vector> assignment_server_groups; bool assignment_server_groups_set = false; ChannelId assignment_channel_group_channel; std::shared_ptr assignment_channel_group; bool assignment_channel_group_set = false; std::shared_ptr server_channel; ChannelId last_server_channel = 0; inline std::vector> getGroupAssignments(VirtualServer* server, ClientDbId cldbid, ClientType type); inline std::shared_ptr getChannelAssignment(VirtualServer* server, ClientDbId client_dbid, ChannelId channel); inline std::shared_ptr getServerChannel(VirtualServer*, ChannelId); }; class VirtualServer { friend class WebClient; friend class DataClient; friend class VoiceClient; friend class MusicClient; friend class ConnectedClient; friend class InternalClient; friend class QueryServer; friend class QueryClient; friend class SpeakingClient; friend class music::MusicBotManager; friend class InstanceHandler; friend class VirtualServerManager; public: VirtualServer(ServerId serverId, sql::SqlManager*); ~VirtualServer(); bool initialize(bool test_properties); bool start(std::string& error); bool running(); void preStop(const std::string&); void stop(const std::string& reason = ts::config::messages::serverStopped); size_t onlineClients(); OnlineClientReport onlineStats(); size_t onlineChannels(){ return this->channelTree->channel_count(); } std::shared_ptr find_client_by_id(ClientId /* client id */); std::deque> findClientsByCldbId(ClientDbId cldbId); std::deque> findClientsByUid(ClientUid uid); std::shared_ptr findClient(std::string name, bool ignoreCase = true); bool forEachClient(std::function)>); //bool forEachClient(std::function>, bool executeLaterIfLocked = true); std::vector> getClients(); std::deque> getClientsByChannel(std::shared_ptr); std::deque> getClientsByChannelRoot(const std::shared_ptr &, bool lock_channel_tree); template std::vector> getClientsByChannel(const std::shared_ptr& ch) { std::vector> result; for(const auto& cl : this->getClientsByChannel(ch)) if(std::dynamic_pointer_cast(cl)) result.push_back(std::dynamic_pointer_cast(cl)); return result; } ecc_key* serverKey(){ return _serverKey; } std::string publicServerKey(); Properties& properties(){ return *this->_properties; } inline sql::SqlManager * getSql(){ return this->sql; } sql::AsyncSqlPool* getSqlPool(){ return this->sql->pool; } inline ServerId getServerId(){ return this->serverId; } inline ServerChannelTree* getChannelTree(){ return this->channelTree; } inline GroupManager* getGroupManager() { return this->groups; } bool notifyServerEdited(std::shared_ptr, std::deque keys); bool notifyClientPropertyUpdates(std::shared_ptr, const std::deque>& keys, bool selfNotify = true); /* execute only with at least channel tree read lock! */ inline bool notifyClientPropertyUpdates(const std::shared_ptr& client, const std::deque& keys, bool selfNotify = true) { if(keys.empty()) return false; std::deque> _keys; for(const auto& key : keys) _keys.push_back(property::impl::info(key)); return this->notifyClientPropertyUpdates(client, _keys, selfNotify); }; void broadcastMessage(std::shared_ptr, std::string message); #ifndef __deprecated #define __deprecated __attribute__((deprecated)) #endif __deprecated void registerInternalClient(std::shared_ptr); __deprecated void unregisterInternalClient(std::shared_ptr); std::shared_ptr getServerRoot(){ return this->serverRoot; } std::string getDisplayName(){ return properties()[property::VIRTUALSERVER_NAME]; } std::shared_ptr getServerStatistics(){ return serverStatistics; } std::shared_ptr getVoiceServer(){ return this->udpVoiceServer; } WebControlServer* getWebServer(){ return this->webControlServer; } /* calculate permissions for an client in this server */ permission::v2::PermissionFlaggedValue calculate_permission( permission::PermissionType, ClientDbId, ClientType type, ChannelId channel, bool granted = false, std::shared_ptr cache = nullptr ); std::vector> calculate_permissions( const std::deque&, ClientDbId, ClientType type, ChannelId channel, bool granted = false, std::shared_ptr cache = nullptr ); bool verifyServerPassword(std::string, bool hashed = false); void testBanStateChange(const std::shared_ptr& invoker); float averagePing(); float averagePacketLoss(); bool resetPermissions(std::string&); void ensureValidDefaultGroups(); ServerState::value getState() { return this->state; } bool could_default_create_channel(); inline std::shared_ptr ref() { return this->self.lock(); } inline bool disable_ip_saving() { return this->_disable_ip_saving; } inline std::chrono::system_clock::time_point start_timestamp() { return this->startTimestamp; }; /* Note: Use only this method to disconnect the client and notify everybody else that he has been banned! */ void notify_client_ban(const std::shared_ptr& /* client */, const std::shared_ptr& /* invoker */, const std::string& /* reason */, size_t /* length */); void notify_client_kick( const std::shared_ptr& /* client */, const std::shared_ptr& /* invoker */, const std::string& /* reason */, const std::shared_ptr& /* target channel */ ); void client_move( const std::shared_ptr& /* client */, std::shared_ptr /* target channel */, const std::shared_ptr& /* invoker */, const std::string& /* reason */, ViewReasonId /* reason id */, bool /* notify the client */, std::unique_lock& /* tree lock */ ); void delete_channel( std::shared_ptr /* target channel */, const std::shared_ptr& /* invoker */, const std::string& /* kick message */, std::unique_lock& /* tree lock */ ); void send_text_message(const std::shared_ptr& /* channel */, const std::shared_ptr& /* sender */, const std::string& /* message */); inline int voice_encryption_mode() { return this->_voice_encryption_mode; } inline std::shared_ptr conversation_manager() { return this->_conversation_manager; } protected: bool registerClient(std::shared_ptr); bool unregisterClient(std::shared_ptr, std::string, std::unique_lock& channel_tree_lock); bool assignDefaultChannel(const std::shared_ptr&, bool join); private: std::weak_ptr self; //Locks by tick, start and stop threads::Mutex stateLock; ServerState::value state = ServerState::OFFLINE; std::chrono::system_clock::time_point lastTick; void executeServerTick(); std::shared_ptr udpVoiceServer = nullptr; WebControlServer* webControlServer = nullptr; token::TokenManager* tokenManager = nullptr; ComplainManager* complains = nullptr; letter::LetterManager* letters = nullptr; std::shared_ptr musicManager; std::shared_ptr serverStatistics; std::shared_ptr _conversation_manager; sql::SqlManager* sql; uint16_t serverId = 1; std::chrono::system_clock::time_point startTimestamp; std::chrono::system_clock::time_point fileStatisticsTimestamp; std::chrono::system_clock::time_point conversation_cache_cleanup_timestamp; //The client list struct { size_t count = 0; std::mutex lock; std::vector> clients; } clients; std::recursive_mutex client_nickname_lock; //General server properties ecc_key* _serverKey = nullptr; std::shared_ptr _properties; int _voice_encryption_mode = 2; /* */ ServerChannelTree* channelTree = nullptr; std::shared_mutex channel_tree_lock; /* lock if access channel tree! */ GroupManager* groups = nullptr; std::shared_ptr serverRoot = nullptr; std::shared_ptr serverAdmin = nullptr; threads::Mutex join_attempts_lock; std::map join_attempts; threads::Mutex join_lock; std::chrono::system_clock::time_point join_last_decrease; std::chrono::milliseconds spoken_time{0}; std::chrono::system_clock::time_point spoken_time_timestamp; bool _disable_ip_saving = false; }; } }