Teaspeak-Server/server/src/VirtualServer.h

359 lines
16 KiB
C++

#pragma once
#include <deque>
#include <memory>
#include <functional>
#include <ThreadPool/ThreadPool.h>
#include <arpa/inet.h>
#include <BasicChannel.h>
#include <sqlite3.h>
#include <sql/SqlQuery.h>
#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 <tomcrypt.h>
#undef byte
#ifdef COMPILE_WEB_CLIENT
#include "server/WebServer.h"
#endif
template<typename T, typename _Tp>
inline bool operator==(T* elm, const std::shared_ptr<_Tp>& __a) noexcept { return elm == __a.get(); }
template<typename T, typename _Tp>
inline bool operator==(const std::shared_ptr<_Tp>& __a, T* elm) noexcept { return elm == __a.get(); }
template<typename T, typename _Tp>
inline bool operator!=(T* elm, const std::shared_ptr<_Tp>& __a) noexcept { return elm != __a.get(); }
template<typename T, typename _Tp>
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 rtc {
class Server;
}
namespace server {
class ConnectedClient;
class VoiceClient;
class QueryClient;
class WebClient;
class InternalClient;
class InstanceHandler;
class VoiceServer;
class QueryServer;
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<permission::v2::PermissionManager> client_permissions;
std::vector<std::shared_ptr<GroupAssignment>> assignment_server_groups;
bool assignment_server_groups_set = false;
ChannelId assignment_channel_group_channel;
std::shared_ptr<GroupAssignment> assignment_channel_group;
bool assignment_channel_group_set = false;
std::shared_ptr<BasicChannel> server_channel;
ChannelId last_server_channel = 0;
inline std::vector<std::shared_ptr<GroupAssignment>> getGroupAssignments(VirtualServer* server, ClientDbId cldbid, ClientType type);
inline std::shared_ptr<GroupAssignment> getChannelAssignment(VirtualServer* server, ClientDbId client_dbid, ChannelId channel);
inline std::shared_ptr<BasicChannel> 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:
struct NetworkReport {
float average_ping{0};
float average_loss{0};
};
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, bool /* disconnect query */);
size_t onlineClients();
OnlineClientReport onlineStats();
size_t onlineChannels(){ return this->channelTree->channel_count(); }
std::shared_ptr<ConnectedClient> find_client_by_id(ClientId /* client id */);
std::deque<std::shared_ptr<ConnectedClient>> findClientsByCldbId(ClientDbId cldbId);
std::deque<std::shared_ptr<ConnectedClient>> findClientsByUid(ClientUid uid);
std::shared_ptr<ConnectedClient> findClient(std::string name, bool ignoreCase = true);
bool forEachClient(std::function<void(std::shared_ptr<ConnectedClient>)>);
//bool forEachClient(std::function<std::shared_ptr<VoiceClient>>, bool executeLaterIfLocked = true);
std::vector<std::shared_ptr<ConnectedClient>> getClients();
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannel(std::shared_ptr<BasicChannel>);
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannelRoot(const std::shared_ptr<BasicChannel> &, bool lock_channel_tree);
template <typename ClType>
std::vector<std::shared_ptr<ClType>> getClientsByChannel(const std::shared_ptr<BasicChannel>& ch) {
std::vector<std::shared_ptr<ClType>> result;
for(const auto& cl : this->getClientsByChannel(ch))
if(std::dynamic_pointer_cast<ClType>(cl))
result.push_back(std::dynamic_pointer_cast<ClType>(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; }
inline rtc::Server& rtc_server() { return *this->rtc_server_; }
[[nodiscard]] inline auto getTokenManager() -> token::TokenManager* {
return this->tokenManager;
}
bool notifyServerEdited(std::shared_ptr<ConnectedClient>, std::deque<std::string> keys);
bool notifyClientPropertyUpdates(std::shared_ptr<ConnectedClient>, const std::deque<const property::PropertyDescription*>& keys, bool selfNotify = true); /* execute only with at least channel tree read lock! */
inline bool notifyClientPropertyUpdates(const std::shared_ptr<ConnectedClient>& client, const std::deque<property::ClientProperties>& keys, bool selfNotify = true) {
if(keys.empty()) return false;
std::deque<const property::PropertyDescription*> _keys{};
for(const auto& key : keys) _keys.push_back(&property::describe(key));
return this->notifyClientPropertyUpdates(client, _keys, selfNotify);
};
void broadcastMessage(std::shared_ptr<ConnectedClient>, std::string message);
#ifndef __deprecated
#define __deprecated __attribute__((deprecated))
#endif
__deprecated void registerInternalClient(std::shared_ptr<ConnectedClient>);
__deprecated void unregisterInternalClient(std::shared_ptr<ConnectedClient>);
std::shared_ptr<ConnectedClient> getServerRoot(){ return this->serverRoot; }
std::string getDisplayName(){ return properties()[property::VIRTUALSERVER_NAME]; }
std::shared_ptr<stats::ConnectionStatistics> getServerStatistics(){ return server_statistics_; }
std::shared_ptr<VoiceServer> 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<CalculateCache> cache = nullptr
);
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
bool verifyServerPassword(std::string, bool hashed = false);
void testBanStateChange(const std::shared_ptr<ConnectedClient>& invoker);
[[nodiscard]] NetworkReport generate_network_report();
bool resetPermissions(std::string&);
void ensureValidDefaultGroups();
ServerState::value getState() { return this->state; }
bool could_default_create_channel();
inline std::shared_ptr<VirtualServer> 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<ConnectedClient>& /* client */, const std::shared_ptr<ConnectedClient>& /* invoker */, const std::string& /* reason */, size_t /* length */);
void notify_client_kick(
const std::shared_ptr<ConnectedClient>& /* client */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* reason */,
const std::shared_ptr<BasicChannel>& /* target channel */
);
void client_move(
const std::shared_ptr<ConnectedClient>& /* client */,
std::shared_ptr<BasicChannel> /* target channel */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* reason */,
ViewReasonId /* reason id */,
bool /* notify the client */,
std::unique_lock<std::shared_mutex>& /* tree lock */
);
void delete_channel(
std::shared_ptr<ServerChannel> /* target channel */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* kick message */,
std::unique_lock<std::shared_mutex>& /* tree lock */,
bool temporary_auto_delete
);
void send_text_message(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* sender */, const std::string& /* message */);
inline int voice_encryption_mode() { return this->_voice_encryption_mode; }
inline std::shared_ptr<conversation::ConversationManager> conversation_manager() { return this->conversation_manager_; }
inline auto& get_channel_tree_lock() { return this->channel_tree_lock; }
void update_channel_from_permissions(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* issuer */);
protected:
bool registerClient(std::shared_ptr<ConnectedClient>);
bool unregisterClient(std::shared_ptr<ConnectedClient>, std::string, std::unique_lock<std::shared_mutex>& channel_tree_lock);
bool assignDefaultChannel(const std::shared_ptr<ConnectedClient>&, bool join);
private:
std::weak_ptr<VirtualServer> 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<VoiceServer> udpVoiceServer = nullptr;
WebControlServer* webControlServer = nullptr;
token::TokenManager* tokenManager = nullptr;
ComplainManager* complains = nullptr;
letter::LetterManager* letters = nullptr;
std::shared_ptr<music::MusicBotManager> music_manager_;
std::shared_ptr<stats::ConnectionStatistics> server_statistics_;
std::shared_ptr<conversation::ConversationManager> conversation_manager_;
std::unique_ptr<rtc::Server> rtc_server_;
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<std::shared_ptr<ConnectedClient>> clients;
} clients;
std::recursive_mutex client_nickname_lock;
//General server properties
ecc_key* _serverKey = nullptr;
std::shared_ptr<Properties> _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<ConnectedClient> serverRoot = nullptr;
std::shared_ptr<ConnectedClient> serverAdmin = nullptr;
threads::Mutex join_attempts_lock;
std::map<std::string, uint16_t > 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;
};
}
}