#pragma once #include #include #include #include #include "music/Song.h" #include "../channel/ClientChannelView.h" #include "DataClient.h" #include "query/command3.h" #define CLIENT_STR_LOG_PREFIX_(this) (std::string("[") + this->getLoggingPeerIp() + ":" + std::to_string(this->getPeerPort()) + "/" + this->getDisplayName() + " | " + std::to_string(this->getClientId()) + "]") #define CLIENT_STR_LOG_PREFIX CLIENT_STR_LOG_PREFIX_(this) #define CMD_REQ_SERVER \ do { \ if(!this->server) { \ return command_result{error::server_invalid_id}; \ } \ } while(0) /* TODO: Play lock the server here with read? So the client dosn't get kicked within that moment */ #define CMD_REF_SERVER(variable_name) \ std::shared_ptr variable_name = this->getServer(); \ if(!variable_name) return command_result{error::server_invalid_id}; #define CMD_REQ_CHANNEL \ if(!this->currentChannel) return command_result{error::channel_invalid_id}; #define CMD_RESET_IDLE \ do { \ this->resetIdleTime(); \ } while(false) #define CMD_REQ_PARM(parm) \ if(!cmd[0].has(parm)) return command_result{error::parameter_not_found}; //the message here is show to the manager! #define CMD_CHK_AND_INC_FLOOD_POINTS(num) \ do {\ this->increaseFloodPoints(num); \ if(this->shouldFloodBlock()) return command_result{error::ban_flooding}; \ } while(0) #define CMD_CHK_PARM_COUNT(count) \ if(cmd.bulkCount() != count) return command_result{error::parameter_invalid_count}; namespace ts { class GroupManager; namespace connection { class VoiceClientConnection; } namespace server { class VirtualServer; class MusicClient; class WebClient; class MusicClient; struct ConnectionInfoData { std::chrono::time_point timestamp; std::map properties; }; class ConnectedClient : public DataClient { friend class VirtualServer; friend class VoiceServer; friend class VoiceClient; friend class MusicClient; friend class WebClient; friend class WebControlServer; friend class music::MusicBotManager; friend class QueryServer; friend class DataClient; friend class SpeakingClient; friend class connection::VoiceClientConnection; friend class ts::GroupManager; friend class VirtualServerManager; public: explicit ConnectedClient(sql::SqlManager*, const std::shared_ptr& server); ~ConnectedClient() override; ConnectionState connectionState(){ return this->state; } std::string getLoggingPeerIp() { return config::server::disable_ip_saving || (this->server && this->server->disable_ip_saving()) ? "X.X.X.X" : this->getPeerIp(); } std::string getPeerIp(){ return this->isAddressV4() ? net::to_string(this->getAddressV4()->sin_addr) : this->isAddressV6() ? net::to_string(this->getAddressV6()->sin6_addr) : "localhost"; } uint16_t getPeerPort(){ return ntohs(this->isAddressV4() ? this->getAddressV4()->sin_port : this->isAddressV6() ? this->getAddressV6()->sin6_port : (uint16_t) 0); } std::string getHardwareId(){ return properties()[property::CLIENT_HARDWARE_ID]; } //General connection stuff bool isAddressV4() { return this->remote_address.ss_family == AF_INET; } const sockaddr_in* getAddressV4(){ return (sockaddr_in*) &this->remote_address; } bool isAddressV6() { return this->remote_address.ss_family == AF_INET6; } const sockaddr_in6* getAddressV6(){ return (sockaddr_in6*) &this->remote_address; } /* Note: Order is not guaranteed here! */ virtual void sendCommand(const ts::Command& command, bool low = false) = 0; virtual void sendCommand(const ts::command_builder& command, bool low = false) = 0; //General manager stuff //FIXME cache the client id for speedup virtual uint16_t getClientId() { return this->properties()[property::CLIENT_ID]; } virtual void setClientId(uint16_t clId) { properties()[property::CLIENT_ID] = clId; } inline std::shared_ptr getChannel(){ return this->currentChannel; } inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; } inline std::shared_ptr getServer(){ return this->server; } inline ServerId getServerId(){ return this->server ? this->server->getServerId() : (ServerId) 0; } //bool channelSubscribed(const std::shared_ptr&); /* if lock_channel == false then channel_lock must be write locked! */ std::deque> subscribeChannel(const std::deque>& target, bool lock_channel, bool /* enforce */); /* if lock_channel == false then channel_lock must be write locked! */ std::deque> unsubscribeChannel(const std::deque>& target, bool lock_channel); bool isClientVisible(const std::shared_ptr&, bool /* lock channel lock */); inline std::deque> getVisibleClients(bool lock_channel){ std::shared_lock lock(this->channel_lock, std::defer_lock); if(lock_channel) lock.lock(); return this->visibleClients; } /** Notifies general stuff **/ virtual bool notifyError(const command_result&, const std::string& retCode = ""); /** Notifies (after request) */ bool sendNeededPermissions(bool /* force an update */); /* invoke this because it dosn't spam the client */ virtual bool notifyClientNeededPermissions(); virtual bool notifyServerGroupList(); virtual bool notifyGroupPermList(const std::shared_ptr&, bool); virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr&, bool); virtual bool notifyChannelGroupList(); virtual bool notifyConnectionInfo(const std::shared_ptr &target, const std::shared_ptr &info); virtual bool notifyChannelSubscribed(const std::deque> &); virtual bool notifyChannelUnsubscribed(const std::deque> &); /** Notifies (without request) */ //Group server virtual bool notifyServerUpdated(std::shared_ptr); //Group manager virtual bool notifyClientPoke(std::shared_ptr invoker, std::string msg); virtual bool notifyClientUpdated( const std::shared_ptr &, const std::deque &, bool lock_channel_tree ); /* invalid client id causes error: invalid clientID */ virtual bool notifyPluginCmd(std::string name, std::string msg, std::shared_ptr); //Group manager chat virtual bool notifyClientChatComposing(const std::shared_ptr &); virtual bool notifyClientChatClosed(const std::shared_ptr &); virtual bool notifyTextMessage(ChatMessageMode mode, const std::shared_ptr &sender, uint64_t targetId, ChannelId channel_id, const std::chrono::system_clock::time_point& /* timestamp */, const std::string &textMessage); inline void sendChannelMessage(const std::shared_ptr& sender, const std::string& textMessage){ this->notifyTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, sender, this->currentChannel ? this->currentChannel->channelId() : 0, 0, std::chrono::system_clock::now(), textMessage); } //Group Client Groups virtual bool notifyServerGroupClientAdd(const std::shared_ptr &invoker, const std::shared_ptr &client, const std::shared_ptr &group); virtual bool notifyServerGroupClientRemove(std::shared_ptr invoker, std::shared_ptr client, std::shared_ptr group); /* invalid client id causes error: invalid clientID */ /* invalid channel id causes error: invalid channelID */ /* an invalid channel or not a client's channel causes: invalid channelID */ virtual bool notifyClientChannelGroupChanged( const std::shared_ptr& invoker, const std::shared_ptr& client, const std::shared_ptr& /*channel*/, const std::shared_ptr& /*inherited channel*/, const std::shared_ptr& group, bool lock_channel_tree /* server channel tree AND client tree must be at least read locked! */ ); //Group channel virtual bool notifyChannelMoved(const std::shared_ptr &channel, ChannelId order, const std::shared_ptr &invoker); virtual bool notifyChannelDescriptionChanged(std::shared_ptr channel); virtual bool notifyChannelPasswordChanged(std::shared_ptr); virtual bool notifyChannelEdited( const std::shared_ptr& /* channel */, const std::vector& /* properties */, const std::shared_ptr& /* invoker */, bool /* send channel description */ ); /* clients channel tree must be at least read locked */ virtual bool notifyChannelHide(const std::deque &channels, bool lock_channel_tree); virtual bool notifyChannelShow(const std::shared_ptr &channel, ChannelId orderId); /* client channel tree must be unique locked and server channel tree shared locked */ virtual bool notifyChannelCreate(const std::shared_ptr &channel, ChannelId orderId, const std::shared_ptr &invoker); virtual bool notifyChannelDeleted(const std::deque& /* channel_ids */, const std::shared_ptr& /* invoker */); //Client view virtual bool notifyClientEnterView( const std::shared_ptr &client, const std::shared_ptr &invoker, const std::string& /* reason */, const std::shared_ptr &to, ViewReasonId reasonId, const std::shared_ptr &from, bool lock_channel_tree ); virtual bool notifyClientEnterView(const std::deque>& /* clients */, const ViewReasonSystemT& /* mode */); /* channel lock must be write locked */ virtual bool notifyClientMoved( const std::shared_ptr &client, const std::shared_ptr &target_channel, ViewReasonId reason, std::string msg, std::shared_ptr invoker, bool lock_channel_tree ); virtual bool notifyClientLeftView( const std::shared_ptr &client, const std::shared_ptr &target_channel, ViewReasonId reasonId, const std::string& reasonMessage, std::shared_ptr invoker, bool lock_channel_tree ); virtual bool notifyClientLeftView( const std::deque>& /* clients */, const std::string& /* reason */, bool /* lock channel view */, const ViewReasonServerLeftT& /* mode */ ); virtual bool notifyClientLeftViewKicked( const std::shared_ptr &client, const std::shared_ptr &target_channel, const std::string& message, std::shared_ptr invoker, bool lock_channel_tree ); virtual bool notifyClientLeftViewBanned( const std::shared_ptr &client, const std::string& message, std::shared_ptr invoker, size_t length, bool lock_channel_tree ); virtual bool notifyMusicPlayerSongChange(const std::shared_ptr& bot, const std::shared_ptr& newEntry); virtual bool notifyMusicQueueAdd(const std::shared_ptr& bot, const std::shared_ptr& entry, int index, const std::shared_ptr& invoker); virtual bool notifyMusicQueueRemove(const std::shared_ptr& bot, const std::deque>& entry, const std::shared_ptr& invoker); virtual bool notifyMusicQueueOrderChange(const std::shared_ptr& bot, const std::shared_ptr& entry, int order, const std::shared_ptr& invoker); virtual bool notifyMusicPlayerStatusUpdate(const std::shared_ptr&); virtual bool notifyConversationMessageDelete(const ChannelId /* conversation id */, const std::chrono::system_clock::time_point& /* begin timestamp */, const std::chrono::system_clock::time_point& /* begin end */, ClientDbId /* client id */, size_t /* messages */); /* this method should be callable from everywhere; the method is non blocking! */ virtual bool close_connection(const std::chrono::system_clock::time_point &timeout) = 0; /* this method should be callable from everywhere; the method is non blocking! */ virtual bool disconnect(const std::string& reason) = 0; void resetIdleTime(); void increaseFloodPoints(uint16_t); bool shouldFloodBlock(); virtual bool ignoresFlood() { return !this->block_flood; } std::shared_ptr request_connection_info(const std::shared_ptr & /* receiver */, bool& /* send temporary (no client response yet) */); virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */); void updateTalkRights(permission::PermissionValue talk_power); virtual std::shared_ptr resolveActiveBan(const std::string& ip_address); inline std::shared_ptr getConnectionStatistics() { return this->connectionStatistics; } inline std::shared_ptr channel_view() { return this->channels; } inline std::shared_ptr ref() { return _this.lock(); } std::shared_mutex& get_channel_lock() { return this->channel_lock; } /* * permission stuff */ /* inline permission::PermissionValue cached_permission_value(permission::PermissionType type) const { std::lock_guard lock(this->cached_permissions_lock); auto index = this->cached_permissions.find(type); if(index != this->cached_permissions.end()) return index->second; We're only caching permissions which are granted to reduce memory //logError(this->getServerId(), "{} Looked up cached permission, which hasn't been cached!", CLIENT_STR_LOG_PREFIX); return permNotGranted; } */ bool update_cached_permissions(); std::shared_lock require_connected_state(bool blocking = false) { //try_to_lock_t std::shared_lock disconnect_lock{}; if(blocking) [[unlikely]] disconnect_lock = std::shared_lock{this->finalDisconnectLock}; else disconnect_lock = std::shared_lock{this->finalDisconnectLock, std::try_to_lock}; if(!disconnect_lock) [[unlikely]] return disconnect_lock; { std::lock_guard state_lock{this->state_lock}; if(this->state != ConnectionState::CONNECTED) return {}; } return disconnect_lock; } inline bool playlist_subscribed(const std::shared_ptr& playlist) const { return this->_subscribed_playlist.lock() == playlist; } protected: std::weak_ptr _this; sockaddr_storage remote_address; //General states std::mutex state_lock; ConnectionState state{ConnectionState::UNKNWON}; bool allowedToTalk = false; std::shared_mutex finalDisconnectLock; /* locked before state lock! */ std::vector cached_server_groups{}; /* variable locked with channel_lock */ GroupId cached_channel_group = 0; /* variable locked with channel_lock */ std::deque> visibleClients{}; /* variable locked with channel_lock */ std::deque> mutedClients{}; /* variable locked with channel_lock */ std::deque> openChats{}; /* variable locked with channel_lock */ std::chrono::system_clock::time_point lastNeededNotify; std::shared_ptr lastNeededPermissionNotifyChannel = nullptr; bool requireNeededPermissionResend = false; std::chrono::system_clock::time_point connectTimestamp; std::chrono::system_clock::time_point lastOnlineTimestamp; std::chrono::system_clock::time_point lastTransfareTimestamp; std::chrono::system_clock::time_point idleTimestamp; struct { std::mutex lock; std::shared_ptr data; std::chrono::system_clock::time_point data_age; std::deque> receiver; std::chrono::system_clock::time_point last_requested; } connection_info; struct { std::chrono::system_clock::time_point servergrouplist; std::chrono::system_clock::time_point channelgrouplist; std::chrono::system_clock::time_point last_notify; std::chrono::milliseconds notify_timeout = std::chrono::seconds(60); } command_times; std::shared_ptr connectionStatistics = nullptr; bool block_flood = true; FloodPoints floodPoints = 0; std::shared_ptr channels; std::shared_mutex channel_lock; std::mutex cached_permissions_lock; std::vector> cached_permissions; /* contains all needed permissions which are set */ permission::v2::PermissionFlaggedValue channels_view_power{0, false}; permission::v2::PermissionFlaggedValue channels_ignore_view{0, false}; permission::v2::PermissionFlaggedValue cpmerission_whisper_power{0, false}; permission::v2::PermissionFlaggedValue cpmerission_needed_whisper_power{0, false}; bool subscribeToAll = false; uint16_t join_state_id = 1; /* default channel value is 0 and by default we need to calculate at least once, so we use 1 */ permission::PermissionType calculate_and_get_join_state(const std::shared_ptr&); std::weak_ptr selectedBot; std::weak_ptr subscribed_bot; std::weak_ptr _subscribed_playlist{}; virtual void tick(const std::chrono::system_clock::time_point &time); //Locked by everything who has something todo with command handling threads::Mutex command_lock; /* Note: This mutex must be recursive! */ std::vector> postCommandHandler; virtual bool handleCommandFull(Command&, bool disconnectOnFail = false); virtual command_result handleCommand(Command&); command_result handleCommandServerGetVariables(Command&); command_result handleCommandServerEdit(Command&); command_result handleCommandGetConnectionInfo(Command&); command_result handleCommandSetConnectionInfo(Command&); command_result handleCommandServerRequestConnectionInfo(Command&); command_result handleCommandConnectionInfoAutoUpdate(Command&); command_result handleCommandPermissionList(Command&); command_result handleCommandPropertyList(Command&); command_result handleCommandServerGroupList(Command&); command_result handleCommandClientGetIds(Command&); command_result handleCommandClientUpdate(Command&); command_result handleCommandClientEdit(Command&); command_result handleCommandClientEdit(Command&, const std::shared_ptr& /* target */); command_result handleCommandClientMove(Command&); command_result handleCommandClientGetVariables(Command&); command_result handleCommandClientKick(Command&); command_result handleCommandClientPoke(Command&); command_result handleCommandChannelSubscribe(Command&); command_result handleCommandChannelSubscribeAll(Command&); command_result handleCommandChannelUnsubscribe(Command&); command_result handleCommandChannelUnsubscribeAll(Command&); command_result handleCommandChannelCreate(Command&); command_result handleCommandChannelDelete(Command&); command_result handleCommandChannelEdit(Command&); command_result handleCommandChannelGetDescription(Command&); command_result handleCommandChannelMove(Command&); command_result handleCommandChannelPermList(Command&); command_result handleCommandChannelAddPerm(Command&); command_result handleCommandChannelDelPerm(Command&); //Server group manager management command_result handleCommandServerGroupCopy(Command&); command_result handleCommandServerGroupAdd(Command&); command_result handleCommandServerGroupRename(Command&); command_result handleCommandServerGroupDel(Command&); command_result handleCommandServerGroupClientList(Command&); command_result handleCommandServerGroupDelClient(Command&); command_result handleCommandServerGroupAddClient(Command&); command_result handleCommandServerGroupPermList(Command&); command_result handleCommandServerGroupAddPerm(Command&); command_result handleCommandServerGroupDelPerm(Command&); command_result handleCommandServerGroupAutoAddPerm(Command&); command_result handleCommandServerGroupAutoDelPerm(Command&); command_result handleCommandClientAddPerm(Command&); command_result handleCommandClientDelPerm(Command&); command_result handleCommandClientPermList(Command&); command_result handleCommandChannelClientAddPerm(Command&); command_result handleCommandChannelClientDelPerm(Command&); command_result handleCommandChannelClientPermList(Command&); command_result handleCommandChannelGroupAdd(Command&); command_result handleCommandChannelGroupCopy(Command&); command_result handleCommandChannelGroupRename(Command&); command_result handleCommandChannelGroupDel(Command&); command_result handleCommandChannelGroupList(Command&); command_result handleCommandChannelGroupClientList(Command&); command_result handleCommandChannelGroupPermList(Command&); command_result handleCommandChannelGroupAddPerm(Command&); command_result handleCommandChannelGroupDelPerm(Command&); command_result handleCommandSetClientChannelGroup(Command&); command_result handleCommandSendTextMessage(Command&); command_result handleCommandClientChatComposing(Command&); command_result handleCommandClientChatClosed(Command&); //File transfare commands command_result handleCommandFTGetFileList(Command&); command_result handleCommandFTCreateDir(Command&); command_result handleCommandFTDeleteFile(Command&); command_result handleCommandFTInitUpload(Command&); command_result handleCommandFTInitDownload(Command&); command_result handleCommandFTGetFileInfo(Command&); command_result handleCommandFTRenameFile(Command&); command_result handleCommandFTList(Command&); command_result handleCommandFTStop(Command&); //CMD_TODO handleCommandFTStop -> 5 points //CMD_TODO handleCommandFTList -> 5 points command_result handleCommandBanList(Command&); command_result handleCommandBanAdd(Command&); command_result handleCommandBanEdit(Command&); command_result handleCommandBanClient(Command&); command_result handleCommandBanDel(Command&); command_result handleCommandBanDelAll(Command&); command_result handleCommandBanTriggerList(Command&); command_result handleCommandTokenList(Command&); command_result handleCommandTokenAdd(Command&); command_result handleCommandTokenUse(Command&); command_result handleCommandTokenDelete(Command&); command_result handleCommandClientDbList(Command&); command_result handleCommandClientDBEdit(Command&); command_result handleCommandClientDbInfo(Command&); command_result handleCommandClientDBDelete(Command&); command_result handleCommandClientDBFind(Command&); command_result handleCommandPluginCmd(Command&); command_result handleCommandClientMute(Command&); command_result handleCommandClientUnmute(Command&); command_result handleCommandComplainAdd(Command&); command_result handleCommandComplainList(Command&); command_result handleCommandComplainDel(Command&); command_result handleCommandComplainDelAll(Command&); command_result handleCommandClientGetDBIDfromUID(Command&); command_result handleCommandClientGetNameFromDBID(Command&); command_result handleCommandClientGetNameFromUid(Command&); command_result handleCommandClientGetUidFromClid(Command&); //Original from query but still reachable for all command_result handleCommandClientList(Command&); command_result handleCommandWhoAmI(Command&); command_result handleCommandServerGroupsByClientId(Command &); //Maybe not query? command_result handleCommandClientFind(Command&); command_result handleCommandClientInfo(Command&); command_result handleCommandVersion(Command&); command_result handleCommandVerifyChannelPassword(Command&); command_result handleCommandVerifyServerPassword(Command&); command_result handleCommandMessageList(Command&); command_result handleCommandMessageAdd(Command&); command_result handleCommandMessageGet(Command&); command_result handleCommandMessageUpdateFlag(Command&); command_result handleCommandMessageDel(Command&); command_result handleCommandPermGet(Command&); command_result handleCommandPermIdGetByName(Command&); command_result handleCommandPermFind(Command&); command_result handleCommandPermOverview(Command&); command_result handleCommandChannelFind(Command&); command_result handleCommandChannelInfo(Command&); command_result handleCommandMusicBotCreate(Command&); command_result handleCommandMusicBotDelete(Command&); command_result handleCommandMusicBotSetSubscription(Command&); command_result handleCommandMusicBotPlayerInfo(Command&); command_result handleCommandMusicBotPlayerAction(Command&); command_result handleCommandMusicBotQueueList(Command&); command_result handleCommandMusicBotQueueAdd(Command&); command_result handleCommandMusicBotQueueRemove(Command&); command_result handleCommandMusicBotQueueReorder(Command&); command_result handleCommandMusicBotPlaylistAssign(Command&); /* playlist management */ command_result handleCommandPlaylistList(Command&); command_result handleCommandPlaylistCreate(Command&); command_result handleCommandPlaylistDelete(Command&); command_result handleCommandPlaylistSetSubscription(Command&); command_result handleCommandPlaylistPermList(Command&); command_result handleCommandPlaylistAddPerm(Command&); command_result handleCommandPlaylistDelPerm(Command&); command_result handleCommandPlaylistClientList(Command&); command_result handleCommandPlaylistClientPermList(Command&); command_result handleCommandPlaylistClientAddPerm(Command&); command_result handleCommandPlaylistClientDelPerm(Command&); /* playlist properties */ command_result handleCommandPlaylistInfo(Command&); command_result handleCommandPlaylistEdit(Command&); command_result handleCommandPlaylistSongList(Command&); command_result handleCommandPlaylistSongSetCurrent(Command&); command_result handleCommandPlaylistSongAdd(Command&); command_result handleCommandPlaylistSongReorder(Command&); command_result handleCommandPlaylistSongRemove(Command&); command_result handleCommandPermReset(Command&); command_result handleCommandHelp(Command&); command_result handleCommandUpdateMyTsId(Command&); command_result handleCommandUpdateMyTsData(Command&); /// /// With a whisper list set a client can talk to the specified clients and channels bypassing the standard rule that voice is only transmitted to the current channel. Whisper lists can be defined for individual clients. /// /// /// To control which client is allowed to whisper to own client, the Library implements an internal whisper whitelist mechanism. When a client receives a whisper while the whispering client has not yet been added to the whisper allow list, the receiving client gets the -Event. Note that whisper voice data is not received until the sending client is added to the receivers whisper allow list. /// /// array of channels to whisper to, set to null to disable /// array of clients to whisper to, set to null to disable //CMD_TODO handleCommandSetWhisperlist //CMD_TODO handleCommandServerTempPasswordList //CMD_TODO handleCommandServerTempPasswordDel //CMD_TODO handleCommandServerTempPasswordAdd -> servertemppasswordadd pw=PWD desc=DES duration=1200 (20 min) tcid=4 tcpw=asdasd (channel password) //Legacy, for TeamSpeak 3 command_result handleCommandClientSetServerQueryLogin(Command&); command_result handleCommandQueryList(Command&); command_result handleCommandQueryRename(Command&); command_result handleCommandQueryCreate(Command&); command_result handleCommandQueryDelete(Command&); command_result handleCommandQueryChangePassword(Command&); command_result handleCommandConversationHistory(Command&); command_result handleCommandConversationFetch(Command&); command_result handleCommandConversationMessageDelete(Command&); command_result handleCommandLogView(Command&); //CMD_TODO handleCommandLogAdd //handleCommandClientSiteReport() -> return findError(0x00) //handleCommandChannelCreatePrivate() -> return findError(0x02) //handleCommandCustome_Unknown_Command() -> return findError(0x100) command_result handleCommandDummy_IpChange(Command&); //handleCommandDummy_NewIp //handleCommandDummy_ConnectFailed //handleCommandDummy_ConnectionLost //Not needed - completly useless //CMD_TODO handleCommandCustomInfo //CMD_TODO handleCommandCustomSearch //CMD_TODO serverquerycmd void sendChannelList(bool lock_channel_tree); void sendServerInit(); void sendTSPermEditorWarning(); void sendChannelDescription(const std::shared_ptr&, bool lock_tree); bool handleTextMessage(ChatMessageMode, std::string, const std::shared_ptr& /* sender target */); typedef std::function& /* sender */, const std::string& /* message */)> handle_text_command_fn_t; bool handle_text_command( ChatMessageMode, const std::string& /* key */, const std::deque& /* arguments */, const handle_text_command_fn_t& /* send function */, const std::shared_ptr& /* sender target */ ); inline std::string notify_response_command(const std::string_view& notify) { if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK) return std::string(notify); return ""; } }; template struct ConnectedLockedClient { ConnectedLockedClient() {} explicit ConnectedLockedClient(std::shared_ptr client) : client{std::move(client)} { if(this->client) this->connection_lock = this->client->require_connected_state(); } explicit ConnectedLockedClient(ConnectedLockedClient&& client) : client{std::move(client.client)}, connection_lock{std::move(client.connection_lock)} { } inline ConnectedLockedClient &operator=(const ConnectedLockedClient& other) { this->client = other.client; if(other) this->connection_lock = std::shared_lock{*other.connection_lock.mutex()}; /* if the other is true (state locked & client) than we could easily acquire a shared lock */ } inline ConnectedLockedClient &operator=(ConnectedLockedClient&& other) { this->client = std::move(other.client); this->connection_lock = std::move(other.connection_lock); } inline bool valid() const { return !!this->client && !!this->connection_lock; } inline operator bool() const { return this->valid(); } inline bool operator!() const { return !this->valid(); } template inline bool operator==(const std::shared_ptr<_T>& other) { return this->client.get() == other.get(); } T* operator->() { return &*this->client; } T &operator*() { return *this->client; } std::shared_ptr client; std::shared_lock connection_lock{}; }; } } template inline bool operator==(const std::shared_ptr& a, const ts::server::ConnectedLockedClient& b) { return a.get() == b.client.get(); }