Begining with the new VS structure

This commit is contained in:
WolverinDEV 2020-03-04 16:24:36 +01:00
parent e47d38da79
commit be4a99dcd7
56 changed files with 2253 additions and 188 deletions

View File

@ -138,7 +138,16 @@ set(SERVER_SOURCE_FILES
src/manager/ConversationManager.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
src/vserver/VirtualServerBase.cpp
src/vserver/VirtualServer.cpp
src/vserver/DefaultServer.cpp
src/services/PermissionsService.cpp
src/services/ClientChannelService.cpp
)
if (COMPILE_WEB_CLIENT)
add_definitions(-DCOMPILE_WEB_CLIENT)
@ -151,7 +160,7 @@ if (COMPILE_WEB_CLIENT)
src/client/web/WSWebClient.cpp
src/client/web/SampleHandler.cpp
src/client/web/VoiceBridge.cpp
src/client/command_handler/helpers.h src/music/PlaylistPermissions.cpp src/music/PlaylistPermissions.h src/lincense/LicenseService.cpp src/lincense/LicenseService.h)
src/client/command_handler/helpers.h src/music/PlaylistPermissions.cpp src/music/PlaylistPermissions.h src/lincense/LicenseService.cpp src/lincense/LicenseService.h src/groups/GroupManager.cpp src/groups/GroupManager.h src/groups/GroupAssignmentManager.cpp src/groups/GroupAssignmentManager.h src/groups/Group.cpp src/groups/Group.h)
endif ()
add_executable(PermHelper helpers/permgen.cpp)

View File

@ -6,7 +6,7 @@
#include <functional> /* required from permission manager */
#include "log/LogUtils.h"
#include "Definitions.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
using namespace std;
using namespace ts;

View File

@ -6,7 +6,7 @@
#include <functional> /* required from permission manager */
#include "log/LogUtils.h"
#include "Definitions.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
using namespace std;
using namespace ts;

View File

@ -159,7 +159,7 @@ void DatabaseHelper::deleteClient(const std::shared_ptr<VirtualServer>& server,
//TODO delete complains
}
inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& server, v2::PermissionManager* manager, sql::command& command, bool test_channel /* only used for client permissions (client channel permissions) */) {
inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& server, v2::PermissionRegister* manager, sql::command& command, bool test_channel /* only used for client permissions (client channel permissions) */) {
auto start = system_clock::now();
auto server_id = server ? server->getServerId() : 0;
@ -229,7 +229,7 @@ inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& ser
#define INSERT_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)"
#define DELETE_COMMAND "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id AND `permId` = :permId AND `channelId` = :chId"
std::shared_ptr<v2::PermissionManager> DatabaseHelper::loadClientPermissionManager(const std::shared_ptr<VirtualServer>& server, ClientDbId cldbid) {
std::shared_ptr<v2::PermissionRegister> DatabaseHelper::loadClientPermissionManager(const std::shared_ptr<VirtualServer>& server, ClientDbId cldbid) {
auto server_id = server ? server->getServerId() : 0;
#ifndef DISABLE_CACHING
{
@ -249,7 +249,7 @@ std::shared_ptr<v2::PermissionManager> DatabaseHelper::loadClientPermissionManag
#endif
logTrace(server_id, "[Permission] Loading client permission manager for client {}", cldbid);
auto permission_manager = std::make_shared<v2::PermissionManager>();
auto permission_manager = std::make_shared<v2::PermissionRegister>();
bool loaded = false;
if(this->use_startup_cache && server) {
shared_ptr<StartupCacheEntry> entry;
@ -301,7 +301,7 @@ std::shared_ptr<v2::PermissionManager> DatabaseHelper::loadClientPermissionManag
}
void DatabaseHelper::saveClientPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::ClientDbId client_dbid, const std::shared_ptr<ts::permission::v2::PermissionManager> &permissions) {
void DatabaseHelper::saveClientPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::ClientDbId client_dbid, const std::shared_ptr<ts::permission::v2::PermissionRegister> &permissions) {
const auto updates = permissions->flush_db_updates();
if(updates.empty())
return;
@ -336,8 +336,8 @@ void DatabaseHelper::saveClientPermissions(const std::shared_ptr<ts::server::Vir
}
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadGroupPermissions(const std::shared_ptr<VirtualServer>& server, ts::GroupId group_id) {
auto result = std::make_shared<v2::PermissionManager>();
std::shared_ptr<permission::v2::PermissionRegister> DatabaseHelper::loadGroupPermissions(const std::shared_ptr<VirtualServer>& server, ts::GroupId group_id) {
auto result = std::make_shared<v2::PermissionRegister>();
if(this->use_startup_cache && server) {
shared_ptr<StartupCacheEntry> entry;
{
@ -368,7 +368,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadGroupPerm
return result;
}
void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::GroupId group_id, const std::shared_ptr<ts::permission::v2::PermissionManager> &permissions) {
void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::GroupId group_id, const std::shared_ptr<ts::permission::v2::PermissionRegister> &permissions) {
const auto updates = permissions->flush_db_updates();
if(updates.empty())
return;
@ -402,8 +402,8 @@ void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::Virt
}
}
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadPlaylistPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::PlaylistId playlist_id) {
shared_ptr<permission::v2::PermissionManager> result;
std::shared_ptr<permission::v2::PermissionRegister> DatabaseHelper::loadPlaylistPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::PlaylistId playlist_id) {
shared_ptr<permission::v2::PermissionRegister> result;
if(this->use_startup_cache && server) {
shared_ptr<StartupCacheEntry> entry;
{
@ -416,7 +416,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadPlaylistP
}
}
if(entry) {
result = std::make_shared<permission::v2::PermissionManager>();
result = std::make_shared<permission::v2::PermissionRegister>();
for(const auto& perm : entry->permissions) {
if(perm->type == permission::SQL_PERM_PLAYLIST && perm->id == playlist_id) {
@ -431,7 +431,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadPlaylistP
return result;
}
result = std::make_shared<permission::v2::PermissionManager>();
result = std::make_shared<permission::v2::PermissionRegister>();
auto command = sql::command(this->sql, "SELECT `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id",
variable{":serverId", server ? server->getServerId() : 0},
variable{":type", permission::SQL_PERM_PLAYLIST},
@ -440,7 +440,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadPlaylistP
return result;
}
void DatabaseHelper::savePlaylistPermissions(const std::shared_ptr<VirtualServer> &server, PlaylistId pid, const std::shared_ptr<permission::v2::PermissionManager> &permissions) {
void DatabaseHelper::savePlaylistPermissions(const std::shared_ptr<VirtualServer> &server, PlaylistId pid, const std::shared_ptr<permission::v2::PermissionRegister> &permissions) {
const auto updates = permissions->flush_db_updates();
if(updates.empty())
return;
@ -474,8 +474,8 @@ void DatabaseHelper::savePlaylistPermissions(const std::shared_ptr<VirtualServer
}
}
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadChannelPermissions(const std::shared_ptr<VirtualServer>& server, ts::ChannelId channel) {
auto result = std::make_shared<v2::PermissionManager>();
std::shared_ptr<permission::v2::PermissionRegister> DatabaseHelper::loadChannelPermissions(const std::shared_ptr<VirtualServer>& server, ts::ChannelId channel) {
auto result = std::make_shared<v2::PermissionRegister>();
if(this->use_startup_cache && server) {
shared_ptr<StartupCacheEntry> entry;
{
@ -506,7 +506,7 @@ std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadChannelPe
return result;
}
void DatabaseHelper::saveChannelPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::ChannelId channel_id, const std::shared_ptr<ts::permission::v2::PermissionManager> &permissions) {
void DatabaseHelper::saveChannelPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::ChannelId channel_id, const std::shared_ptr<ts::permission::v2::PermissionRegister> &permissions) {
const auto updates = permissions->flush_db_updates();
if(updates.empty())
return;

View File

@ -4,7 +4,7 @@
#include <map>
#include <vector>
#include <chrono>
#include <PermissionManager.h>
#include <PermissionRegister.h>
#include <Properties.h>
#include <cstdint>
@ -26,8 +26,8 @@ namespace ts {
struct CachedPermissionManager {
ServerId sid;
ClientDbId cldbid;
std::weak_ptr<permission::v2::PermissionManager> manager;
std::shared_ptr<permission::v2::PermissionManager> ownLock;
std::weak_ptr<permission::v2::PermissionRegister> manager;
std::shared_ptr<permission::v2::PermissionRegister> ownLock;
std::chrono::time_point<std::chrono::system_clock> lastAccess;
};
@ -91,17 +91,17 @@ namespace ts {
std::deque<std::shared_ptr<ClientDatabaseInfo>> queryDatabaseInfo(const std::shared_ptr<VirtualServer>&, const std::deque<ClientDbId>&);
std::deque<std::shared_ptr<ClientDatabaseInfo>> queryDatabaseInfoByUid(const std::shared_ptr<VirtualServer> &, std::deque<std::string>);
std::shared_ptr<permission::v2::PermissionManager> loadClientPermissionManager(const std::shared_ptr<VirtualServer>&, ClientDbId);
void saveClientPermissions(const std::shared_ptr<VirtualServer>&, ClientDbId , const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionRegister> loadClientPermissionManager(const std::shared_ptr<VirtualServer>&, ClientDbId);
void saveClientPermissions(const std::shared_ptr<VirtualServer>&, ClientDbId , const std::shared_ptr<permission::v2::PermissionRegister>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionManager> loadChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId);
void saveChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionRegister> loadChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId);
void saveChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId, const std::shared_ptr<permission::v2::PermissionRegister>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionManager> loadGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId);
void saveGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionRegister> loadGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId);
void saveGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId, const std::shared_ptr<permission::v2::PermissionRegister>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionManager> loadPlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId /* playlist id */);
void savePlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId, const std::shared_ptr<permission::v2::PermissionManager>& /* permission manager */);
std::shared_ptr<permission::v2::PermissionRegister> loadPlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId /* playlist id */);
void savePlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId, const std::shared_ptr<permission::v2::PermissionRegister>& /* permission manager */);
std::shared_ptr<Properties> loadServerProperties(const std::shared_ptr<VirtualServer>&); //Read and write
std::shared_ptr<Properties> loadPlaylistProperties(const std::shared_ptr<VirtualServer>&, PlaylistId); //Read and write

View File

@ -21,7 +21,7 @@ Group::Group(GroupManager* handle, GroupTarget target, GroupType type, GroupId g
this->_properties = new Properties();
this->_properties->register_property_type<property::GroupProperties>();
this->setPermissionManager(make_shared<permission::v2::PermissionManager>());
this->setPermissionManager(make_shared<permission::v2::PermissionRegister>());
this->properties()[property::GROUP_ID] = groupId;
this->properties()[property::GROUP_TYPE] = type;
@ -59,7 +59,7 @@ Group::Group(GroupManager* handle, GroupTarget target, GroupType type, GroupId g
});
}
void Group::setPermissionManager(const std::shared_ptr<permission::v2::PermissionManager> &manager) {
void Group::setPermissionManager(const std::shared_ptr<permission::v2::PermissionRegister> &manager) {
this->_permissions = manager;
this->apply_properties_from_permissions();
}

View File

@ -4,7 +4,7 @@
#include <chrono>
#include <BasicChannel.h>
#include <ThreadPool/Mutex.h>
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "Properties.h"
#include "channel/ServerChannel.h"
#include "Definitions.h"
@ -82,7 +82,7 @@ namespace ts {
Group(GroupManager* handle, GroupTarget target, GroupType type, GroupId groupId);
~Group();
std::shared_ptr<permission::v2::PermissionManager> permissions(){ return this->_permissions; }
std::shared_ptr<permission::v2::PermissionRegister> permissions(){ return this->_permissions; }
Properties& properties(){ return *this->_properties; }
GroupNameMode nameMode(){ return (GroupNameMode) (uint8_t) properties()[property::GROUP_NAMEMODE]; }
@ -133,10 +133,10 @@ namespace ts {
return data.has_value ? data.value : 0;
}
private:
void setPermissionManager(const std::shared_ptr<permission::v2::PermissionManager>& manager);
void setPermissionManager(const std::shared_ptr<permission::v2::PermissionRegister>& manager);
GroupManager* handle;
std::shared_ptr<permission::v2::PermissionManager> _permissions;
std::shared_ptr<permission::v2::PermissionRegister> _permissions;
Properties* _properties;
GroupTarget _target;
GroupType _type;

View File

@ -707,7 +707,7 @@ struct PermissionCommandTuple {
ChannelId channel;
};
inline bool writePermissions(const shared_ptr<permission::v2::PermissionManager>& manager, Command& cmd, int& index, int version, permission::teamspeak::GroupType type, std::string& error) {
inline bool writePermissions(const shared_ptr<permission::v2::PermissionRegister>& manager, Command& cmd, int& index, int version, permission::teamspeak::GroupType type, std::string& error) {
for(const auto& permission_container : manager->permissions()) {
auto permission = get<1>(permission_container);
SnapshotPermissionEntry{

View File

@ -259,14 +259,16 @@ void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target,
lock_guard command_lock(target->command_lock);
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
ChannelId old_channel_id{0};
if(target->currentChannel) {
old_channel_id = target->currentChannel->channelId();
for(const auto& client : this->getClients()) {
if(!client || client == target)
continue;
unique_lock client_channel_lock(client->channel_lock);
if(client->isClientVisible(target, false))
client->notifyClientLeftViewBanned(target, reason, invoker, time, false);
client->notifyClientLeftViewBanned(target, old_channel_id, invoker, time, false, reason);
}
auto s_channel = dynamic_pointer_cast<ServerChannel>(target->currentChannel);
@ -275,7 +277,7 @@ void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target,
/* now disconnect the target itself */
unique_lock client_channel_lock(target->channel_lock);
target->notifyClientLeftViewBanned(target, reason, invoker, time, false);
target->notifyClientLeftViewBanned(target, old_channel_id, invoker, time, false, reason);
target->currentChannel = nullptr;
}
@ -294,14 +296,16 @@ void VirtualServer::notify_client_kick(
lock_guard command_lock(target->command_lock);
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
ChannelId old_channel_id{0};
if(target->currentChannel) {
old_channel_id = target->currentChannel->channelId();
for(const auto& client : this->getClients()) {
if(!client || client == target)
continue;
unique_lock client_channel_lock(client->channel_lock);
if(client->isClientVisible(target, false))
client->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
client->notifyClientLeftViewKicked(target, old_channel_id, reason, invoker, false, nullptr);
}
auto s_channel = dynamic_pointer_cast<ServerChannel>(target->currentChannel);
@ -310,7 +314,7 @@ void VirtualServer::notify_client_kick(
/* now disconnect the target itself */
unique_lock client_channel_lock(target->channel_lock);
target->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
target->notifyClientLeftViewKicked(target, old_channel_id, reason, invoker, false, nullptr);
target->currentChannel = nullptr;
}
}

View File

@ -154,7 +154,7 @@ bool VirtualServer::initialize(bool test_properties) {
if(default_channel->properties()[property::CHANNEL_FLAG_PASSWORD].as<bool>())
default_channel->properties()[property::CHANNEL_FLAG_PASSWORD] = false;
this->tokenManager = new token::TokenManager(this);
this->tokenManager = new server::tokens::TokenManager(this);
this->tokenManager->loadTokens();
this->complains = new ComplainManager(this);
@ -1108,7 +1108,7 @@ bool VirtualServer::resetPermissions(std::string& token) {
this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_guest->name()).front()->groupId();
auto token_admin = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_admin->name()).front()->groupId();
auto created = this->tokenManager->createToken(token::TOKEN_SERVER, token_admin, "Default server token for the server admin.");
auto created = this->tokenManager->createToken(server::tokens::TOKEN_SERVER, token_admin, "Default server token for the server admin.");
if(!created) {
logCritical(this->serverId, "Failed to generate default serveradmin token!");
} else {

View File

@ -106,7 +106,7 @@ namespace ts {
bool global_skip = false;
bool global_skip_set = false;
std::shared_ptr<permission::v2::PermissionManager> client_permissions;
std::shared_ptr<permission::v2::PermissionRegister> client_permissions;
std::vector<std::shared_ptr<GroupAssignment>> assignment_server_groups;
bool assignment_server_groups_set = false;
@ -290,7 +290,7 @@ namespace ts {
std::shared_ptr<VoiceServer> udpVoiceServer = nullptr;
WebControlServer* webControlServer = nullptr;
token::TokenManager* tokenManager = nullptr;
server::tokens::TokenManager* tokenManager = nullptr;
ComplainManager* complains = nullptr;
letter::LetterManager* letters = nullptr;
std::shared_ptr<music::MusicBotManager> musicManager;

View File

@ -1,11 +1,11 @@
#pragma once
#include <lock/rw_mutex.h>
#include <stdint.h>
#include <cstdlib>
#include "Properties.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "BasicChannel.h"
#include "../Group.h"
#include <memory>
#include <sql/SqlQuery.h>
@ -45,7 +45,7 @@ namespace ts {
void deleteSemiPermanentChannels();
std::shared_ptr<LinkedTreeEntry> tree_head() { return this->head; }
[[nodiscard]] std::shared_ptr<LinkedTreeEntry> tree_head() { return this->head; }
protected:
virtual ChannelId generateChannelId() override;

View File

@ -21,7 +21,7 @@ using namespace std;
using namespace std::chrono;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
extern ts::server::InstanceHandler* serverInstance;
@ -451,11 +451,10 @@ bool ConnectedClient::notifyClientLeftView(
return true;
}
bool ConnectedClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client,
const std::shared_ptr<BasicChannel> &target_channel,
const std::string& message,
std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree) {
bool ConnectedClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
const std::string &message, std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree,
const std::shared_ptr<BasicChannel> &target_channel) {
assert(!lock_channel_tree); /* not supported yet! */
assert(client && client->getClientId() != 0);
assert(client->currentChannel || &*client == this);
@ -479,7 +478,7 @@ bool ConnectedClient::notifyClientLeftViewKicked(const std::shared_ptr<Connected
Command cmd("notifyclientleftview");
cmd["clid"] = client->getClientId();
cmd["cfid"] = client->currentChannel ? client->currentChannel->channelId() : 0;
cmd["cfid"] = channel_from;
cmd["ctid"] = target_channel ? target_channel->channelId() : 0;
cmd["reasonid"] = (uint8_t) (target_channel ? ViewReasonId::VREASON_CHANNEL_KICK : ViewReasonId::VREASON_SERVER_KICK);
cmd["reasonmsg"] = message;
@ -494,12 +493,10 @@ bool ConnectedClient::notifyClientLeftViewKicked(const std::shared_ptr<Connected
return true;
}
bool ConnectedClient::notifyClientLeftViewBanned(
const shared_ptr<ConnectedClient> &client,
const std::string& message,
std::shared_ptr<ConnectedClient> invoker,
size_t length,
bool lock_channel_tree) {
bool ConnectedClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
std::shared_ptr<ConnectedClient> invoker, size_t length,
bool lock_channel_tree,
const std::string &message) {
assert(!lock_channel_tree); /* not supported yet! */
assert(client && client->getClientId() != 0);
@ -508,7 +505,7 @@ bool ConnectedClient::notifyClientLeftViewBanned(
Command cmd("notifyclientleftview");
cmd["clid"] = client->getClientId();
cmd["cfid"] = client->currentChannel ? client->currentChannel->channelId() : 0;
cmd["cfid"] = channel_from;
cmd["ctid"] = 0;
cmd["reasonid"] = ViewReasonId::VREASON_BAN;
cmd["reasonmsg"] = message;

View File

@ -96,6 +96,8 @@ namespace ts {
virtual void setClientId(uint16_t clId) { properties()[property::CLIENT_ID] = clId; }
inline std::shared_ptr<BasicChannel> getChannel(){ return this->currentChannel; }
/* ATTENTION: Do this only with command_lock locked, and client_channel_tree lock lock in exclusive mode */
inline void setChannel(const std::shared_ptr<BasicChannel>& channel){ this->currentChannel = channel; }
inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; }
inline std::shared_ptr<VirtualServer> getServer(){ return this->server; }
inline ServerId getServerId(){ return this->server ? this->server->getServerId() : (ServerId) 0; }
@ -122,7 +124,7 @@ namespace ts {
virtual bool notifyClientNeededPermissions();
virtual bool notifyServerGroupList();
virtual bool notifyGroupPermList(const std::shared_ptr<Group>&, bool);
virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionManager>&, bool);
virtual bool notifyClientPermList(ClientDbId, const std::shared_ptr<permission::v2::PermissionRegister>&, bool);
virtual bool notifyChannelGroupList();
virtual bool notifyConnectionInfo(const std::shared_ptr<ConnectedClient> &target, const std::shared_ptr<ConnectionInfoData> &info);
virtual bool notifyChannelSubscribed(const std::deque<std::shared_ptr<BasicChannel>> &);
@ -210,20 +212,13 @@ namespace ts {
const ViewReasonServerLeftT& /* mode */
);
virtual bool notifyClientLeftViewKicked(
const std::shared_ptr<ConnectedClient> &client,
const std::shared_ptr<BasicChannel> &target_channel,
const std::string& message,
std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree
);
virtual bool notifyClientLeftViewBanned(
const std::shared_ptr<ConnectedClient> &client,
const std::string& message,
std::shared_ptr<ConnectedClient> invoker,
size_t length,
bool lock_channel_tree
);
virtual bool notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
const std::string &message, std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree, const std::shared_ptr<BasicChannel> &target_channel);
virtual bool notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
std::shared_ptr<ConnectedClient> invoker, size_t length,
bool lock_channel_tree,
const std::string &message);
virtual bool notifyMusicPlayerSongChange(const std::shared_ptr<MusicClient>& bot, const std::shared_ptr<music::SongInfo>& newEntry);
virtual bool notifyMusicQueueAdd(const std::shared_ptr<MusicClient>& bot, const std::shared_ptr<ts::music::SongInfo>& entry, int index, const std::shared_ptr<ConnectedClient>& invoker);
@ -299,6 +294,9 @@ namespace ts {
inline bool playlist_subscribed(const std::shared_ptr<ts::music::Playlist>& playlist) const {
return this->_subscribed_playlist.lock() == playlist;
}
[[nodiscard]] inline auto lock_command_handling() { return std::lock_guard{this->command_lock}; }
void increase_join_state() { this->join_state_id++; }
protected:
std::weak_ptr<ConnectedClient> _this;
sockaddr_storage remote_address;
@ -311,9 +309,6 @@ namespace ts {
std::shared_mutex finalDisconnectLock; /* locked before state lock! */
std::vector<GroupId> cached_server_groups{}; /* variable locked with channel_lock */
GroupId cached_channel_group = 0; /* variable locked with channel_lock */
std::deque<std::weak_ptr<ConnectedClient>> visibleClients{}; /* variable locked with channel_lock */
std::deque<std::weak_ptr<ConnectedClient>> mutedClients{}; /* variable locked with channel_lock */
std::deque<std::weak_ptr<ConnectedClient>> openChats{}; /* variable locked with channel_lock */

View File

@ -12,7 +12,7 @@
#include "../server/file/FileServer.h"
#include "../server/VoiceServer.h"
#include "voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../InstanceHandler.h"
#include "../server/QueryServer.h"
#include "file/FileClient.h"

View File

@ -19,7 +19,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
extern ts::server::InstanceHandler* serverInstance;
@ -133,7 +133,7 @@ bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<Group>& group, b
return true;
}
bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_ptr<permission::v2::PermissionManager>& mgr, bool perm_sids) {
bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_ptr<permission::v2::PermissionRegister>& mgr, bool perm_sids) {
Command res(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientpermlist" : "");
auto permissions = mgr->permissions();

View File

@ -102,7 +102,7 @@ namespace ts {
sql::SqlManager* sql;
std::shared_ptr<VirtualServer> server;
std::shared_ptr<permission::v2::PermissionManager> clientPermissions = nullptr;
std::shared_ptr<permission::v2::PermissionRegister> clientPermissions = nullptr;
std::shared_ptr<Properties> _properties;
std::shared_ptr<BasicChannel> currentChannel = nullptr;

View File

@ -8,7 +8,7 @@
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -32,7 +32,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
//{findError("parameter_invalid"), "could not resolve permission " + (cmd[index].has("permid") ? cmd[index]["permid"].as<string>() : cmd[index]["permsid"].as<string>())}; \
//TODO: Log missing permissions?

View File

@ -7,7 +7,7 @@
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -32,7 +32,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
#define QUERY_PASSWORD_LENGTH 12

View File

@ -16,7 +16,7 @@
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -48,7 +48,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
#define QUERY_PASSWORD_LENGTH 12

View File

@ -16,7 +16,7 @@
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -48,7 +48,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
#define QUERY_PASSWORD_LENGTH 12
@ -460,6 +460,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
}
}
//TODO: When using new VS model, check for a temporary assignment!
this->server->groups->setChannelGroup(target_cldbid, serverGroup, channel);
for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) {
unique_lock client_channel_lock_w(targetClient->channel_lock);

View File

@ -16,7 +16,7 @@
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -49,7 +49,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};

View File

@ -16,7 +16,7 @@
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
@ -48,7 +48,7 @@ using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
#define QUERY_PASSWORD_LENGTH 12

View File

@ -139,9 +139,15 @@ namespace ts::server {
bool notifyClientLeftView(const std::deque<std::shared_ptr<ConnectedClient>> &deque, const std::string &string, bool b, const ViewReasonServerLeftT &t) override;
bool notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, const std::string &message, std::shared_ptr<ConnectedClient> invoker, bool lock_channel_tree) override;
bool notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
const std::string &message, std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree,
const std::shared_ptr<BasicChannel> &target_channel) override;
bool notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, const std::string &message, std::shared_ptr<ConnectedClient> invoker, size_t length, bool lock_channel_tree) override;
bool notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
std::shared_ptr<ConnectedClient> invoker, size_t length,
bool lock_channel_tree,
const std::string &message) override;
private:
command_result handleCommandExit(Command&);

View File

@ -175,7 +175,10 @@ bool QueryClient::notifyClientLeftView(const std::deque<std::shared_ptr<Connecte
return ConnectedClient::notifyClientLeftView(clients, string, b, t);
}
bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, const std::string &message, std::shared_ptr<ConnectedClient> invoker, bool lock_channel_tree) {
bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
const std::string &message, std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree,
const std::shared_ptr<BasicChannel> &target_channel) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, client](const weak_ptr<ConnectedClient>& weak) {
auto c = weak.lock();
@ -187,10 +190,13 @@ bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClie
}), this->visibleClients.end());
return true;
}
return ConnectedClient::notifyClientLeftViewKicked(client, target_channel, message, invoker, lock_channel_tree);
return ConnectedClient::notifyClientLeftViewKicked(client, channel_from, message, invoker, lock_channel_tree, target_channel);
}
bool QueryClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, const std::string &message, std::shared_ptr<ConnectedClient> invoker, size_t length, bool lock_channel_tree) {
bool QueryClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, ChannelId channel_from,
std::shared_ptr<ConnectedClient> invoker, size_t length,
bool lock_channel_tree,
const std::string &message) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, client](const weak_ptr<ConnectedClient>& weak) {
auto c = weak.lock();
@ -202,7 +208,7 @@ bool QueryClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClie
}), this->visibleClients.end());
return true;
}
return ConnectedClient::notifyClientLeftViewBanned(client, message, invoker, length, lock_channel_tree);
return ConnectedClient::notifyClientLeftViewBanned(client, channel_from, invoker, length, lock_channel_tree, message);
}
bool QueryClient::notifyMusicQueueAdd(const std::shared_ptr<MusicClient> &bot, const std::shared_ptr<ts::music::SongInfo> &entry, int index, const std::shared_ptr<ConnectedClient> &invoker) {

View File

@ -629,7 +629,7 @@ bool WebClient::disconnect(const std::string &reason) {
unique_lock server_channel_lock(this->server->channel_tree_lock);
{
unique_lock own_lock(this->channel_lock);
this->notifyClientLeftViewKicked(this->ref(), nullptr, reason, this->server->serverRoot, false);
this->notifyClientLeftViewKicked(this->ref(), this->currentChannel ? this->currentChannel->channelId() : 0, reason, this->server->serverRoot, false, nullptr);
}
this->server->client_move(this->ref(), nullptr, this->server->serverRoot, reason, ViewReasonId::VREASON_SERVER_KICK, false, server_channel_lock);
this->server->unregisterClient(_this.lock(), "disconnected", server_channel_lock);

View File

@ -0,0 +1,23 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include "Group.h"
#include "./GroupManager.h"
using namespace ts::server::groups;
Group::Group(const std::shared_ptr<GroupManager> &manager, ts::GroupId id, ts::server::groups::GroupType type, std::string name,
std::shared_ptr<permission::v2::PermissionRegister> permissions) : manager_{manager}, group_id_{id}, type_{type}, name_{std::move(name)}, permissions_{std::move(permissions)} { }
void Group::set_display_name(const std::string &name) {
this->name_ = name;
auto handle = this->manager_.lock();
if(handle) handle->update_group_name(this);
}
void Group::set_permissions(const std::shared_ptr<permission::v2::PermissionRegister> &permissions) {
assert(permissions);
this->permissions_ = permissions;
}

75
server/src/groups/Group.h Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include <memory>
#include <PermissionRegister.h>
namespace ts::server::groups {
enum GroupType {
GROUP_TYPE_QUERY,
GROUP_TYPE_TEMPLATE,
GROUP_TYPE_NORMAL
};
enum GroupNameMode {
GROUP_NAME_MODE_HIDDEN,
GROUP_NAME_MODE_BEFORE,
GROUP_NAME_MODE_BEHIND
};
typedef uint32_t GroupSortId;
typedef uint32_t GroupIconId;
class GroupManager;
class Group {
friend class GroupManager;
public:
Group(const std::shared_ptr<GroupManager>& /* manager */, GroupId /* id */, GroupType /* type */, std::string /* name */, std::shared_ptr<permission::v2::PermissionRegister> /* permissions */);
~Group() = default;
/* information getters */
[[nodiscard]] inline GroupId group_id() const { return this->group_id_; }
[[nodiscard]] inline GroupType group_type() const { return this->type_; }
[[nodiscard]] inline const std::string& display_name() const { return this->name_; }
[[nodiscard]] inline std::shared_ptr<permission::v2::PermissionRegister> permissions() { return this->permissions_; }
[[nodiscard]] inline bool save_assignments() const {
assert(this->permissions_);
auto value = this->permissions_->permission_value_flagged(permission::b_group_is_permanent);
return value.has_value ? permission::v2::permission_granted(1, value) : true;
}
[[nodiscard]] inline GroupNameMode name_mode() const {
assert(this->permissions_);
auto value = this->permissions_->permission_value_flagged(permission::i_group_show_name_in_tree);
return value.has_value ? (GroupNameMode) value.value : GroupNameMode::GROUP_NAME_MODE_HIDDEN;
}
[[nodiscard]] inline GroupSortId sort_id() const {
assert(this->permissions_);
auto value = this->permissions_->permission_value_flagged(permission::i_group_sort_id);
return value.has_value ? value.value : 0;
}
[[nodiscard]] inline GroupIconId icon_id() const {
assert(this->permissions_);
auto value = this->permissions_->permission_value_flagged(permission::i_icon_id);
return value.has_value ? value.value : 0;
}
/* information setters */
void set_display_name(const std::string& name);
private:
std::weak_ptr<GroupManager> manager_;
const GroupId group_id_;
const GroupType type_;
std::string name_;
std::shared_ptr<permission::v2::PermissionRegister> permissions_;
void set_permissions(const std::shared_ptr<permission::v2::PermissionRegister>& /* permissions */);
};
class ServerGroup : public Group { };
class ChannelGroup : public Group { };
}

View File

@ -0,0 +1,533 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include <log/LogUtils.h>
#include "./GroupAssignmentManager.h"
#include "./GroupManager.h"
#include "../vserver/VirtualServer.h"
#include "../client/ConnectedClient.h"
using namespace ts::server::groups;
GroupAssignmentManager::GroupAssignmentManager(GroupManager* handle) : manager_{handle} { }
GroupAssignmentManager::~GroupAssignmentManager() = default;
bool GroupAssignmentManager::initialize(std::string &error) {
return true;
}
sql::SqlManager* GroupAssignmentManager::sql_manager() {
return this->manager_->virtual_server()->sql_manager();
}
ts::ServerId GroupAssignmentManager::server_id() {
return this->manager_->virtual_server()->server_id();
}
bool GroupAssignmentManager::load_data(std::string &error) {
if constexpr(kCacheAllClients) {
std::lock_guard cache_lock{this->client_cache_lock};
std::unique_ptr<ClientCache> current_entry{nullptr};
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `cldbid`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid ORDER BY `cldbid`", variable{":sid", this->server_id()})
.query([&](int length, std::string* value, std::string* column) {
ChannelId channel_id{0};
GroupId group_id{0};
ClientDbId client_dbid{0};
for(int index = 0; index < length; index++){
try {
if(column[index] == "groupId"){
group_id = stoll(value[index]);
} else if(column[index] == "until"){
} else if(column[index] == "channelId"){
channel_id = stoll(value[index]);
} else if(column[index] == "cldbid"){
client_dbid = stoll(value[index]);
}
} catch(std::exception& ex) {
logError(this->server_id(), "Failed to load group assignment from database. Column {} contains an invalid value: {}", column[index], value[index]);
return 0;
}
}
if(current_entry)
if(current_entry->client_database_id != client_dbid)
this->client_cache.push_back(std::move(current_entry));
if(!current_entry) {
current_entry = std::make_unique<ClientCache>();
current_entry->client_database_id = client_dbid;
}
if(channel_id)
current_entry->channel_group_assignments.emplace_back(channel_id, group_id, false);
else
current_entry->server_group_assignments.emplace_back(group_id);
return 0;
});
if(!res) {
error = "failed to query database (" + res.fmtStr() + ")";
return false;
}
if(current_entry)
this->client_cache.push_back(std::move(current_entry));
}
return true;
}
void GroupAssignmentManager::unload_data() {
std::lock_guard cache_lock{this->client_cache_lock};
this->client_cache.clear();
}
void GroupAssignmentManager::enable_cache_for_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
if constexpr(!kCacheAllClients) {
bool cache_exists{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& client : this->client_cache)
if(client->client_database_id == cldbid) {
client->use_count++;
cache_exists = true;
break;
}
}
if(!cache_exists) {
auto cache = std::make_unique<ClientCache>();
cache->client_database_id = cldbid;
cache->use_count++;
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
.query([&](int length, std::string* value, std::string* column) {
ChannelId channel_id{0};
GroupId group_id{0};
for(int index = 0; index < length; index++){
try {
if(column[index] == "groupId"){
group_id = stoll(value[index]);
} else if(column[index] == "until"){
} else if(column[index] == "channelId"){
channel_id = stoll(value[index]);
}
} catch(std::exception& ex) {
logError(this->server_id(), "Failed to load group assignment from database for client {}. Column {} contains an invalid value: {}", cldbid, column[index], value[index]);
return 0;
}
}
if(!group_id)
return 0;
if(channel_id)
cache->channel_group_assignments.emplace_back(channel_id, group_id, false);
else
cache->server_group_assignments.emplace_back(group_id);
return 0;
});
std::lock_guard cache_lock{this->client_cache_lock};
#if 0 /* lets have some performance over double entries :D */
for(auto& client : this->client_cache)
if(client->client_database_id == cldbid) {
/* somebody already inserted that client while we've loaded him */
cache_exists = true;
break;
}
if(!cache_exists)
#endif
this->client_cache.push_back(std::move(cache));
}
}
if(mode == GroupAssignmentCalculateMode::GLOBAL)
if(auto parent = this->manager_->parent_manager(); parent)
parent->assignments().enable_cache_for_client(mode, cldbid);
}
void GroupAssignmentManager::disable_cache_for_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
if constexpr(!kCacheAllClients) {
std::lock_guard cache_lock{this->client_cache_lock};
this->client_cache.erase(std::remove_if(this->client_cache.begin(), this->client_cache.end(), [cldbid](const std::unique_ptr<ClientCache>& client) {
return client->client_database_id == cldbid;
}), this->client_cache.end());
}
if(mode == GroupAssignmentCalculateMode::GLOBAL)
if(auto parent = this->manager_->parent_manager(); parent)
parent->assignments().disable_cache_for_client(mode, cldbid);
}
std::vector<ts::GroupId> GroupAssignmentManager::server_groups_of_client(ts::server::groups::GroupAssignmentCalculateMode mode,
ts::ClientDbId cldbid) {
std::vector<ts::GroupId> result{};
bool cache_found{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& entry : this->client_cache) {
if(entry->client_database_id != cldbid) continue;
result.reserve(entry->server_group_assignments.size());
for(auto& assignment : entry->server_group_assignments)
result.push_back(assignment.group_id);
cache_found = true;
break;
}
}
if(!cache_found && !kCacheAllClients) {
debugMessage(this->server_id(), "Query client groups for client {} on server {}.", cldbid, this->server_id());
result.reserve(64);
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = 0", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
.query([&](int length, std::string* value, std::string* column) {
GroupId group_id{0};
try {
for(int index = 0; index < length; index++) {
if(column[index] == "groupId") {
group_id = std::stoull(value[index]);
break;
}
}
} catch(std::exception& ex) {
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse group id.");
return 0;
}
if(!group_id) return 0;
result.push_back(group_id);
return 0;
});
LOG_SQL_CMD(res);
}
if(mode == GroupAssignmentCalculateMode::GLOBAL)
if(auto parent = this->manager_->parent_manager(); parent) {
auto parent_groups = parent->assignments().server_groups_of_client(mode, cldbid);
result.reserve(result.size() + parent_groups.size());
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
}
return result;
}
std::vector<ChannelGroupAssignment> GroupAssignmentManager::channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) {
std::vector<ChannelGroupAssignment> result{};
bool cache_found{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& entry : this->client_cache) {
if(entry->client_database_id != cldbid) continue;
result.reserve(entry->channel_group_assignments.size());
result.insert(result.begin(), entry->channel_group_assignments.begin(), entry->channel_group_assignments.end());
cache_found = true;
break;
}
}
if(!cache_found && !kCacheAllClients) {
debugMessage(this->server_id(), "Query client groups for client {} on server {}.", cldbid, this->server_id());
result.reserve(64);
auto res = sql::command(this->sql_manager(), "SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` != 0", variable{":sid", this->server_id()}, variable{":cldbid", cldbid})
.query([&](int length, std::string* value, std::string* column) {
GroupId group_id{0};
ChannelId channel_id{0};
try {
for(int index = 0; index < length; index++) {
if(column[index] == "groupId") {
group_id = std::stoull(value[index]);
} else if(column[index] == "channelId") {
channel_id = std::stoull(value[index]);
}
}
} catch(std::exception& ex) {
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse group or channel id.");
return 0;
}
if(!group_id || !channel_id) return 0;
result.emplace_back(channel_id, group_id, false);
return 0;
});
LOG_SQL_CMD(res);
}
if(mode == GroupAssignmentCalculateMode::GLOBAL)
if(auto parent = this->manager_->parent_manager(); parent) {
auto parent_groups = parent->assignments().channel_groups_of_client(mode, cldbid);
result.reserve(result.size() + parent_groups.size());
result.insert(result.begin(), parent_groups.begin(), parent_groups.end());
}
return result;
}
std::deque<ts::ClientDbId> GroupAssignmentManager::server_group_clients(GroupId group_id) {
std::deque<ts::ClientDbId> result{};
if constexpr(kCacheAllClients) {
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& client : this->client_cache) {
auto it = std::find_if(client->server_group_assignments.begin(), client->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
return assignment.group_id == group_id;
});
if(it == client->server_group_assignments.end())
continue;
result.push_back(client->client_database_id);
}
} else {
auto res = sql::command(this->sql_manager(), "SELECT `cldbid` FROM `assignedGroups` WHERE `serverId` = :sid AND `channelId` = 0 AND `groupId` = :gid", variable{":sid", this->server_id()}, variable{":gid", group_id})
.query([&](int length, std::string* value, std::string* column) {
ClientDbId cldbid{0};
try {
for(int index = 0; index < length; index++) {
if(column[index] == "cldbid") {
cldbid = std::stoull(value[index]);
break;
}
}
} catch(std::exception& ex) {
logWarning(this->server_id(), "Invalid data found in group assignment table. Failed to parse client database id.");
return 0;
}
if(!cldbid) return 0;
result.push_back(cldbid);
return 0;
});
LOG_SQL_CMD(res);
}
if(auto parent = this->manager_->parent_manager(); parent) {
auto parent_clients = parent->assignments().server_group_clients(group_id);
result.insert(result.begin(), parent_clients.begin(), parent_clients.end());
}
return result;
}
GroupAssignmentResult GroupAssignmentManager::add_server_group(ClientDbId client, GroupId group) {
bool cache_verified{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& entry : this->client_cache) {
if(entry->client_database_id != client) continue;
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
return assignment.group_id == group;
});
if(it != entry->server_group_assignments.end())
return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP;
entry->server_group_assignments.emplace_back(group);
cache_verified = true;
break;
}
if(!cache_verified && kCacheAllClients) {
/* add the client to the cache */
auto cache = std::make_unique<ClientCache>();
cache->client_database_id = client;
cache->server_group_assignments.emplace_back(group);
this->client_cache.push_back(cache);
}
}
{
auto command = sql::command(this->sql_manager(), "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)",
variable{":sid", this->server_id()},
variable{":cldbid", client},
variable{":gid", group},
variable{":chid", 0},
variable{":until", 0});
if(cache_verified)
command.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "failed to insert group assignment into the database"});
else {
auto result = command.execute();
if(!result) return GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP; //TODO: Parse error from database?
}
}
return GroupAssignmentResult::SUCCESS;
}
GroupAssignmentResult GroupAssignmentManager::remove_server_group(ClientDbId client, GroupId group) {
bool cache_verified{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& entry : this->client_cache) {
if(entry->client_database_id != client) continue;
auto it = std::find_if(entry->server_group_assignments.begin(), entry->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) {
return assignment.group_id == group;
});
if(it == entry->server_group_assignments.end())
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
entry->server_group_assignments.erase(it);
cache_verified = true;
break;
}
if(!cache_verified && kCacheAllClients)
return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP;
}
{
auto command = sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `groupId` = :gid AND `channelId` = :chid",
variable{":sid", this->server_id()},
variable{":cldbid", client},
variable{":gid", group},
variable{":chid", 0});
if(cache_verified)
command.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "failed to remove group assignment from database"});
else {
auto result = command.execute();
if(!result) return GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP; //TODO: Parse error from database?
}
}
return GroupAssignmentResult::SUCCESS;
}
GroupAssignmentResult GroupAssignmentManager::set_channel_group(ClientDbId client, GroupId group, ChannelId channel_id, bool temporary) {
bool cache_verified{false};
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& entry : this->client_cache) {
if(entry->client_database_id != client) continue;
auto it = std::find_if(entry->channel_group_assignments.begin(), entry->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
return assignment.channel_id == channel_id;
});
if(it != entry->channel_group_assignments.end()) {
if(group) {
if(it->group_id == group)
return GroupAssignmentResult::SET_ALREADY_MEMBER_OF_GROUP;
it->group_id = group;
} else {
entry->channel_group_assignments.erase(it);
}
} else {
if(group) {
entry->channel_group_assignments.emplace_back(channel_id, group, temporary);
}
}
cache_verified = true;
break;
}
if(!cache_verified && kCacheAllClients) {
if(group) {
/* add the client to the cache */
auto cache = std::make_unique<ClientCache>();
cache->client_database_id = client;
cache->channel_group_assignments.emplace_back(channel_id, group, temporary);
this->client_cache.push_back(cache);
} else {
return GroupAssignmentResult::SUCCESS;
}
}
}
if(temporary)
return GroupAssignmentResult::SUCCESS;
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid",
variable{":sid", this->server_id()},
variable{":cldbid", client},
variable{":chid", channel_id})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "failed to delete old channel group assignment"});
if(group) {
sql::command(this->sql_manager(), "INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until)",
variable{":sid", this->server_id()},
variable{":cldbid", client},
variable{":gid", group},
variable{":chid", channel_id},
variable{":until", 0})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "failed to insert channel group assignment"});
}
return GroupAssignmentResult::SUCCESS;
}
void GroupAssignmentManager::cleanup_channel_assignments(ChannelId channel_id) {
{
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& client : this->client_cache) {
client->channel_group_assignments.erase(std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
return assignment.channel_id == channel_id;
}));
}
}
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `channelId` = :cid", variable{":sid", this->server_id()}, variable{":cid", channel_id})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
}
void GroupAssignmentManager::cleanup_assignments() {
{
std::lock_guard cache_lock{this->client_cache_lock};
this->client_cache.clear();
}
sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid", variable{":sid", this->server_id()})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
}
void GroupAssignmentManager::cleanup_channel_temporary_assignment(ClientDbId client_dbid, ChannelId channel) {
std::lock_guard cache_lock{this->client_cache_lock};
for(auto& client : this->client_cache) {
if(client->client_database_id == client_dbid) {
auto assignment = std::find_if(client->channel_group_assignments.begin(), client->channel_group_assignments.end(), [&](const ChannelGroupAssignment& assignment) {
return assignment.channel_id == channel;
});
if(assignment->temporary_assignment)
client->channel_group_assignments.erase(assignment);
break;
}
}
}
std::deque<ts::property::ClientProperties> GroupAssignmentManager::update_client_group_properties(const std::shared_ptr<server::ConnectedClient> &client, ChannelId channel_id) {
std::deque<property::ClientProperties> changed;
bool increase_join_state{false};
//Server groups
{
auto server_groups = this->server_groups_of_client(GroupAssignmentCalculateMode::GLOBAL, client->getClientDatabaseId());
std::string group_string;
for(const auto& group : server_groups)
if(group_string.empty()) group_string += std::to_string(group);
else group_string += "," + std::to_string(group);
if(client->properties()[property::CLIENT_SERVERGROUPS] != group_string) {
client->properties()[property::CLIENT_SERVERGROUPS] = group_string;
changed.push_back(property::CLIENT_SERVERGROUPS);
increase_join_state = true;
}
}
//Channel group
if(channel_id) {
auto assignment = this->manager_->virtual_server()->channel_service().calculate_channel_group(channel_id, client->getClientDatabaseId(), client->getType());
if(client->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID] != assignment.inherited_channel_id) {
client->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID] = assignment.inherited_channel_id;
changed.push_back(property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID);
}
if(client->properties()[property::CLIENT_CHANNEL_GROUP_ID] != assignment.group_id) {
client->properties()[property::CLIENT_CHANNEL_GROUP_ID] = assignment.group_id;
changed.push_back(property::CLIENT_CHANNEL_GROUP_ID);
increase_join_state = true;
}
}
if(increase_join_state)
client->increase_join_state(); /* groups have changed :) */
return changed;
}

View File

@ -0,0 +1,110 @@
#pragma once
#include <mutex>
#include <deque>
#include <string>
#include <memory>
#include <utility>
#include <Definitions.h>
#include <Properties.h>
namespace sql {
class SqlManager;
}
namespace ts::server {
class ConnectedClient;
namespace vserver {
class VirtualServerBase;
}
namespace groups {
enum struct GroupAssignmentCalculateMode {
LOCAL, /* only calculate clients groups for the local server */
GLOBAL /* use the parent group manager as well, if existing */
};
class ServerGroup;
class ChannelGroup;
class GroupManager;
struct ChannelGroupAssignment {
ChannelGroupAssignment(ChannelId channel_id, GroupId group_id, bool t) : channel_id{channel_id}, group_id{group_id}, temporary_assignment{t} { }
ChannelGroupAssignment(const ChannelGroupAssignment& other) = default;
ChannelGroupAssignment(ChannelGroupAssignment&&) = default;
ChannelId channel_id;
GroupId group_id;
bool temporary_assignment;
};
struct ServerGroupAssignment {
explicit ServerGroupAssignment(GroupId group_id) : group_id{group_id} { }
ServerGroupAssignment(const ServerGroupAssignment& other) = default;
ServerGroupAssignment(ServerGroupAssignment&&) = default;
GroupId group_id;
};
enum struct GroupAssignmentResult {
SUCCESS,
ADD_ALREADY_MEMBER_OF_GROUP,
REMOVE_NOT_MEMBER_OF_GROUP,
SET_ALREADY_MEMBER_OF_GROUP
};
class GroupAssignmentManager {
constexpr static bool kCacheAllClients{true};
public:
explicit GroupAssignmentManager(GroupManager* /* manager */);
~GroupAssignmentManager();
/* general load/initialize methods */
bool initialize(std::string& /* error */);
bool load_data(std::string& /* error */);
void unload_data();
/* client specific cache methods */
void enable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
void disable_cache_for_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
/* info/query methods */
[[nodiscard]] std::vector<GroupId> server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
[[nodiscard]] std::vector<ChannelGroupAssignment> channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */);
[[nodiscard]] std::deque<ClientDbId> server_group_clients(GroupId /* group id */);
//[[nodiscard]] std::deque<ClientDbId> channel_group_clients(GroupId /* group id */, ChannelId /* channel id */);
/* change methods */
GroupAssignmentResult add_server_group(ClientDbId /* client database id */, GroupId /* group id */);
GroupAssignmentResult remove_server_group(ClientDbId /* client database id */, GroupId /* group id */);
/* Use channel group id 0 to delete any assignment */
GroupAssignmentResult set_channel_group(ClientDbId /* client database id */, GroupId /* group id */, ChannelId /* channel id */, bool /* temporary assignment */);
std::deque<property::ClientProperties> update_client_group_properties(const std::shared_ptr<server::ConnectedClient> &client, ChannelId /* target channel */);
void cleanup_assignments();
void cleanup_channel_assignments(ChannelId /* channel */);
void cleanup_channel_temporary_assignment(ClientDbId /* client database id */, ChannelId /* channel */);
private:
struct ClientCache {
ClientDbId client_database_id{0};
size_t use_count{0};
std::deque<ChannelGroupAssignment> channel_group_assignments{};
std::deque<ServerGroupAssignment> server_group_assignments{};
};
GroupManager* manager_;
std::mutex client_cache_lock;
std::deque<std::unique_ptr<ClientCache>> client_cache{};
[[nodiscard]] sql::SqlManager* sql_manager();
[[nodiscard]] ServerId server_id();
};
}
}

View File

@ -0,0 +1,5 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include "GroupManager.h"

View File

@ -0,0 +1,82 @@
#pragma once
#include <mutex>
#include <deque>
#include <string>
#include <memory>
#include <Definitions.h>
#include <sql/SqlQuery.h>
#include "./GroupAssignmentManager.h"
#include "./Group.h"
namespace ts::server {
namespace vserver {
class VirtualServerBase;
}
namespace groups {
enum struct GroupCalculateMode {
LOCAL, /* only calculate clients groups for the local server */
GLOBAL /* use the parent group manager as well, if existing */
};
enum struct ActionReturnCode {
RENAME_NAME_ALREADY_USED,
RENAME_GROUP_INVALID_ID,
DELETE_GROUP_INVALID_ID,
CUSTOM_ERROR
};
class GroupManager {
friend class Group;
public:
GroupManager(vserver::VirtualServerBase* /* virtual server */, std::shared_ptr<GroupManager> /* parent */);
~GroupManager();
bool initialize(std::string& /* error */);
bool load_data(std::string& /* error */);
void unload_data();
[[nodiscard]] inline vserver::VirtualServerBase* virtual_server() { return this->virtual_server_; }
[[nodiscard]] inline const std::shared_ptr<GroupManager>& parent_manager() { return this->parent_manager_; }
[[nodiscard]] inline GroupAssignmentManager& assignments() { return this->assignment_manager_; }
[[nodiscard]] std::deque<std::shared_ptr<ServerGroup>> server_groups(GroupCalculateMode /* mode */);
[[nodiscard]] std::deque<std::shared_ptr<ChannelGroup>> channel_groups(GroupCalculateMode /* mode */);
[[nodiscard]] std::shared_ptr<ServerGroup> default_server_group(ClientType /* client type */);
[[nodiscard]] std::shared_ptr<ChannelGroup> default_channel_group(ClientType /* client type */);
[[nodiscard]] std::shared_ptr<ServerGroup> find_server_group(GroupId /* group id */);
[[nodiscard]] std::shared_ptr<ChannelGroup> find_channel_group(GroupId /* group id */);
[[nodiscard]] std::shared_ptr<ServerGroup> create_server_group(GroupType type, const std::string& /* group name */);
[[nodiscard]] std::shared_ptr<ServerGroup> create_channel_group(GroupType type, const std::string& /* group name */);
[[nodiscard]] ActionReturnCode copy_server_group(GroupId /* group id */, GroupType /* target group type */, const std::string& /* target group name */);
[[nodiscard]] ActionReturnCode copy_channel_group(GroupId /* group id */, GroupType /* target group type */, const std::string& /* target group name */);
[[nodiscard]] ActionReturnCode copy_server_group_permissions(GroupId /* group id */, GroupId /* target group */);
[[nodiscard]] ActionReturnCode copy_channel_group_permissions(GroupId /* group id */, GroupId /* target group */);
[[nodiscard]] ActionReturnCode rename_server_group(GroupId /* group id */, const std::string& /* target group name */);
[[nodiscard]] ActionReturnCode rename_channel_group(GroupId /* group id */, const std::string& /* target group name */);
[[nodiscard]] ActionReturnCode delete_server_group(GroupId /* group id */);
[[nodiscard]] ActionReturnCode delete_channel_group(GroupId /* group id */);
private:
vserver::VirtualServerBase* virtual_server_;
std::shared_ptr<GroupManager> parent_manager_;
GroupAssignmentManager assignment_manager_;
std::mutex group_lock_{};
[[nodiscard]] sql::SqlManager* sql_manager();
void update_group_name(Group* /* group */);
};
}
}

View File

@ -9,6 +9,7 @@ using namespace std;
using namespace std::chrono;
using namespace ts;
using namespace ts::server;
using namespace ts::server::bans;
BanManager::BanManager(sql::SqlManager* handle) : sql(handle) {}

View File

@ -10,8 +10,7 @@
#include <Definitions.h>
#include <sql/SqlQuery.h>
namespace ts {
namespace server {
namespace ts::server {
enum BanStringType {
BST_WILD_V4,
BST_WILD_V6,
@ -19,91 +18,92 @@ namespace ts {
BST_REGEX
};
}
}
DEFINE_VARIABLE_TRANSFORM(ts::server::BanStringType, VARTYPE_INT, std::to_string((uint8_t) in), static_cast<ts::server::BanStringType>(in.as<uint8_t>()));
namespace ts {
namespace server {
namespace ts::server {
class VirtualServer;
class ConnectedClient;
struct BanRecord {
ServerId serverId;
BanId banId;
namespace bans {
struct BanRecord {
ServerId serverId;
BanId banId;
ClientDbId invokerDbId;
std::string invokerUid;
std::string invokerName;
ClientDbId invokerDbId;
std::string invokerUid;
std::string invokerName;
std::string hwid;
std::string uid;
std::string hwid;
std::string uid;
std::string name;
std::string ip;
BanStringType strType;
std::string name;
std::string ip;
BanStringType strType;
std::chrono::time_point<std::chrono::system_clock> created;
std::chrono::time_point<std::chrono::system_clock> until;
std::chrono::time_point<std::chrono::system_clock> created;
std::chrono::time_point<std::chrono::system_clock> until;
std::string reason;
std::string reason;
size_t triggered;
};
size_t triggered;
};
struct BanTrigger {
ServerId server_id;
BanId ban_id;
std::chrono::system_clock::time_point timestamp;
struct BanTrigger {
ServerId server_id;
BanId ban_id;
std::chrono::system_clock::time_point timestamp;
std::string unique_id;
std::string hardware_id;
std::string name;
std::string ip;
};
std::string unique_id;
std::string hardware_id;
std::string name;
std::string ip;
};
class BanManager {
public:
BanManager(sql::SqlManager*);
~BanManager();
class BanManager {
public:
BanManager(sql::SqlManager*);
BanManager(const BanManager&) = delete;
BanManager(BanManager&&) = delete;
~BanManager();
bool loadBans();
bool loadBans();
std::deque<std::shared_ptr<BanRecord>> listBans(ServerId);
std::deque<std::shared_ptr<BanRecord>> listBans(ServerId);
std::shared_ptr<BanRecord> findBanById(ServerId, uint64_t banId);
std::shared_ptr<BanRecord> findBanByHwid(ServerId, std::string hwid);
std::shared_ptr<BanRecord> findBanByUid(ServerId, std::string uid);
std::shared_ptr<BanRecord> findBanByIp(ServerId, std::string ip);
std::shared_ptr<BanRecord> findBanByName(ServerId, std::string nickName);
std::shared_ptr<BanRecord> findBanExact(ServerId,
const std::string& /* reason */,
const std::string& /* uid */,
const std::string& /* ip */,
const std::string& /* display name */,
const std::string& /* hardware id */);
std::shared_ptr<BanRecord> findBanById(ServerId, uint64_t banId);
std::shared_ptr<BanRecord> findBanByHwid(ServerId, std::string hwid);
std::shared_ptr<BanRecord> findBanByUid(ServerId, std::string uid);
std::shared_ptr<BanRecord> findBanByIp(ServerId, std::string ip);
std::shared_ptr<BanRecord> findBanByName(ServerId, std::string nickName);
std::shared_ptr<BanRecord> findBanExact(ServerId,
const std::string& /* reason */,
const std::string& /* uid */,
const std::string& /* ip */,
const std::string& /* display name */,
const std::string& /* hardware id */);
void deleteAllBans(ServerId sid);
void deleteAllBans(ServerId sid);
BanId registerBan(ServerId, ClientDbId invoker, std::string reason, std::string uid, std::string ip, std::string nickName, std::string hwid, std::chrono::time_point<std::chrono::system_clock> until);
void unban(ServerId, BanId);
void unban(std::shared_ptr<BanRecord>);
void updateBan(std::shared_ptr<BanRecord>);
BanId registerBan(ServerId, ClientDbId invoker, std::string reason, std::string uid, std::string ip, std::string nickName, std::string hwid, std::chrono::time_point<std::chrono::system_clock> until);
void unban(ServerId, BanId);
void unban(std::shared_ptr<BanRecord>);
void updateBan(std::shared_ptr<BanRecord>);
void updateBanReason(std::shared_ptr<BanRecord>, std::string);
void updateBanTimeout(std::shared_ptr<BanRecord>, std::chrono::time_point<std::chrono::system_clock>);
void updateBanReason(std::shared_ptr<BanRecord>, std::string);
void updateBanTimeout(std::shared_ptr<BanRecord>, std::chrono::time_point<std::chrono::system_clock>);
void trigger_ban(const std::shared_ptr<BanRecord>& /* record */,
ServerId /* server */,
const std::string& /* unique id */,
const std::string& /* hardware id */,
const std::string& /* nickname */,
const std::string& /* ip */
);
std::deque<std::shared_ptr<BanTrigger>> trigger_list(const std::shared_ptr<BanRecord>& /* record */, ServerId /* server id */, ssize_t /* offset */, ssize_t /* limit */);
void trigger_ban(const std::shared_ptr<BanRecord>& /* record */,
ServerId /* server */,
const std::string& /* unique id */,
const std::string& /* hardware id */,
const std::string& /* nickname */,
const std::string& /* ip */
);
std::deque<std::shared_ptr<BanTrigger>> trigger_list(const std::shared_ptr<BanRecord>& /* record */, ServerId /* server id */, ssize_t /* offset */, ssize_t /* limit */);
private:
sql::SqlManager* sql = nullptr;
std::atomic<BanId> current_ban_index;
};
}
}
private:
sql::SqlManager* sql = nullptr;
std::atomic<BanId> current_ban_index;
};
}
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <string>
#include "PermissionManager.h"
#include "PermissionRegister.h"
#include "Definitions.h"
namespace ts {

View File

@ -7,7 +7,7 @@
#include <log/LogUtils.h>
#include <Properties.h>
#include <sql/mysql/MySQL.h>
#include <PermissionManager.h>
#include <PermissionRegister.h>
#include "SqlDataManager.h"
using namespace std;
@ -412,6 +412,7 @@ ROLLBACK;
CREATE_INDEX2R("conversation_blocks", "server_id", "conversation_id");
db_version(11);
default:
//CREATE TABLE `assigned_channel_groups` (`server_id` INT NOT NULL, `cldbid` INT NOT NULL, `channel_id` INT NOT NULL, `group_id` INT, `until` BIGINT DEFAULT -1, PRIMARY KEY `server_id`, `cldbid`, `channel_id`)
break;
}

View File

@ -15,7 +15,7 @@ using namespace std;
using namespace std::chrono;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
using namespace ts::server::tokens;
TokenManager::TokenManager(server::VirtualServer* handle) : handle(handle) {
@ -30,7 +30,7 @@ bool TokenManager::loadTokens() {
}
int TokenManager::loadTokenFromDb(int length, char **values, char **columns) {
std::string token, description = "";
std::string token{}, description{};
auto type = static_cast<TokenType>(0xFF);
GroupId group = 0;
ChannelId chId = 0;

View File

@ -11,7 +11,7 @@ namespace ts {
class VirtualServer;
}
namespace token {
namespace server::tokens {
enum TokenType : uint8_t {
TOKEN_SERVER,
TOKEN_CHANNEL
@ -44,4 +44,4 @@ namespace ts {
};
}
}
DEFINE_VARIABLE_TRANSFORM(ts::token::TokenType, VARTYPE_INT, std::to_string((uint8_t) in), static_cast<ts::token::TokenType>(in.as<uint8_t>()));
DEFINE_VARIABLE_TRANSFORM(ts::server::tokens::TokenType, VARTYPE_INT, std::to_string((uint8_t) in), static_cast<ts::server::tokens::TokenType>(in.as<uint8_t>()));

View File

@ -13,7 +13,7 @@ using namespace ts::music;
using namespace std;
using namespace std::chrono;
Playlist::Playlist(const std::shared_ptr<ts::music::MusicBotManager> &manager, std::shared_ptr<ts::Properties> properties, std::shared_ptr<permission::v2::PermissionManager> permissions) :
Playlist::Playlist(const std::shared_ptr<ts::music::MusicBotManager> &manager, std::shared_ptr<ts::Properties> properties, std::shared_ptr<permission::v2::PermissionRegister> permissions) :
PlaylistPermissions{std::move(permissions)}, _properties{std::move(properties)}, manager{manager} { }
Playlist::~Playlist() {

View File

@ -90,7 +90,7 @@ namespace ts {
};
};
Playlist(const std::shared_ptr<MusicBotManager>& /* manager */, std::shared_ptr<Properties> /* properties */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
Playlist(const std::shared_ptr<MusicBotManager>& /* manager */, std::shared_ptr<Properties> /* properties */, std::shared_ptr<permission::v2::PermissionRegister> /* permissions */);
virtual ~Playlist();
virtual void load_songs();

View File

@ -11,7 +11,7 @@ using namespace ts::music;
using namespace std;
using namespace std::chrono;
PlayablePlaylist::PlayablePlaylist(const std::shared_ptr<MusicBotManager> &handle, const std::shared_ptr<Properties> &props, const std::shared_ptr<permission::v2::PermissionManager>& perms) : Playlist(handle, props, perms) { }
PlayablePlaylist::PlayablePlaylist(const std::shared_ptr<MusicBotManager> &handle, const std::shared_ptr<Properties> &props, const std::shared_ptr<permission::v2::PermissionRegister>& perms) : Playlist(handle, props, perms) { }
PlayablePlaylist::~PlayablePlaylist() {}

View File

@ -24,7 +24,7 @@ namespace ts {
SHUFFLE
};
};
PlayablePlaylist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, const std::shared_ptr<permission::v2::PermissionManager>& /* permissions */);
PlayablePlaylist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, const std::shared_ptr<permission::v2::PermissionRegister>& /* permissions */);
virtual ~PlayablePlaylist();
void load_songs() override;

View File

@ -9,7 +9,7 @@ using namespace ts;
using namespace ts::music;
PlaylistPermissions::PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> permissions) : _permissions{std::move(permissions)} {}
PlaylistPermissions::PlaylistPermissions(std::shared_ptr<permission::v2::PermissionRegister> permissions) : _permissions{std::move(permissions)} {}
permission::v2::PermissionFlaggedValue PlaylistPermissions::calculate_client_specific_permissions(ts::permission::PermissionType permission, const std::shared_ptr<server::ConnectedClient>& client) {
auto val = this->_permissions->channel_permission(permission, client->getClientDatabaseId());

View File

@ -1,6 +1,6 @@
#pragma once
#include <PermissionManager.h>
#include <PermissionRegister.h>
namespace ts::server {
class VirtualServer;
@ -14,15 +14,15 @@ namespace ts::music {
ignore_playlist_owner,
do_no_require_granted
};
PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> permissions);
PlaylistPermissions(std::shared_ptr<permission::v2::PermissionRegister> permissions);
inline const std::shared_ptr<permission::v2::PermissionManager>& permission_manager() const { return this->_permissions; }
inline const std::shared_ptr<permission::v2::PermissionRegister>& permission_manager() const { return this->_permissions; }
/* returns permission::ok if client has permissions */
permission::PermissionType client_has_permissions(const std::shared_ptr<server::ConnectedClient>& client, permission::PermissionType needed_permission, permission::PermissionType granted_permission, uint8_t /* ignore playlist owner */ = 0);
permission::v2::PermissionFlaggedValue calculate_client_specific_permissions(permission::PermissionType /* permission */, const std::shared_ptr<server::ConnectedClient>& /* client */);
protected:
const std::shared_ptr<permission::v2::PermissionManager> _permissions;
const std::shared_ptr<permission::v2::PermissionRegister> _permissions;
virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0;
private:

View File

@ -0,0 +1,379 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include <deque>
#include "./ClientChannelService.h"
#include "../client/ConnectedClient.h"
#include "../vserver/VirtualServer.h"
#include "../groups/GroupManager.h"
#include "../groups/GroupAssignmentManager.h"
#include <misc/timer.h>
#include <misc/sassert.h>
#include <log/LogUtils.h>
using namespace ts::server::channels;
ts::ServerId ClientChannelService::get_server_id() const {
return this->virtual_server_->server_id();
}
ChannelGroupInheritance ClientChannelService::calculate_channel_group(ChannelId channel_id, ClientDbId client_dbid, ClientType client_type) {
auto tree_lock = this->virtual_server_->lock_channel_clients();
tree_lock.auto_lock_shared();
auto assignments = this->virtual_server_->group_manager()->assignments().channel_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, client_dbid);
auto inheritance_channel = this->virtual_server_->server_channel_tree()->findChannel(channel_id);
while(inheritance_channel) {
auto inheritance_channel_id = inheritance_channel->channelId();
auto assignment = std::find_if(assignments.begin(), assignments.end(), [&](const groups::ChannelGroupAssignment& assignment) {
return assignment.channel_id == inheritance_channel_id;
});
if(assignment == assignments.end() || !assignment->group_id) {
auto permission = inheritance_channel->permissions()->permission_value_flagged(permission::b_channel_group_inheritance_end);
if(permission::v2::permission_granted(1, permission))
break;
inheritance_channel = inheritance_channel->parent();
} else {
return {
assignment->group_id,
inheritance_channel_id
};
}
}
auto default_group = this->virtual_server_->group_manager()->default_channel_group(client_type);
assert(default_group);
return {
default_group->group_id(),
channel_id
};
}
/*
* General notice:
* We're locking the clients command_lock, so when changing the currentChannel variable nothing gets messed up.
* As a little note: This must be done before locking the channel tree at all.
*/
ClientMoveResult ClientChannelService::client_ban(const std::shared_ptr<ConnectedClient> &target,
const std::shared_ptr<ConnectedClient> &invoker, const std::string &reason, size_t time,
ts::rwshared_lock<ts::rw_mutex> &tree_lock) {
tree_lock.auto_unlock();
auto command_lock = target->lock_command_handling();
if(auto err = tree_lock.auto_lock_exclusive(); err)
return ClientMoveResult::TREE_LOCK_FAILED;
std::unique_lock client_chan_tree_lock{target->get_channel_lock()};
auto old_channel = target->getChannel();
target->setChannel(nullptr);
client_chan_tree_lock.unlock();
ChannelId old_channel_id{0};
if(old_channel) {
old_channel_id = old_channel->channelId();
for(const auto& client : this->virtual_server_->connected_clients(false)) {
if(!client || client == target)
continue;
std::unique_lock client_channel_lock(client->get_channel_lock());
if(client->isClientVisible(target, false))
client->notifyClientLeftViewBanned(target, old_channel_id, invoker, time, false, reason);
}
auto s_channel = dynamic_pointer_cast<ServerChannel>(old_channel);
assert(s_channel);
s_channel->unregister_client(target);
}
target->notifyClientLeftViewBanned(target, old_channel_id, invoker, time, false, reason);
return ClientMoveResult::SUCCESS;
}
ClientMoveResult ClientChannelService::client_kick(const std::shared_ptr<ConnectedClient> &target,
const std::shared_ptr<ConnectedClient> &invoker, const std::string &reason,
const std::shared_ptr<ServerChannel> &target_channel,
ts::rwshared_lock<ts::rw_mutex> &tree_lock) {
if(target_channel) {
return this->client_move(target, target_channel, invoker, reason, ViewReasonId::VREASON_CHANNEL_KICK, true, tree_lock);
} else {
tree_lock.auto_unlock();
auto command_lock = target->lock_command_handling();
if(auto err = tree_lock.auto_lock_exclusive(); err)
return ClientMoveResult::TREE_LOCK_FAILED;
std::unique_lock client_chan_tree_lock{target->get_channel_lock()};
auto old_channel = target->getChannel();
target->setChannel(nullptr);
client_chan_tree_lock.unlock();
ChannelId old_channel_id{0};
if(old_channel) {
old_channel_id = old_channel->channelId();
for(const auto& client : this->virtual_server_->connected_clients(false)) {
if(!client || client == target)
continue;
std::unique_lock client_channel_lock(client->get_channel_lock());
if(client->isClientVisible(target, false))
client->notifyClientLeftViewKicked(target, old_channel_id, reason, invoker, false, nullptr);
}
auto s_channel = dynamic_pointer_cast<ServerChannel>(old_channel);
assert(s_channel);
s_channel->unregister_client(target);
}
target->notifyClientLeftViewKicked(target, old_channel_id, reason, invoker, false, nullptr);
}
return ClientMoveResult::SUCCESS;
}
ClientMoveResult ClientChannelService::client_move(const std::shared_ptr<ConnectedClient> &target,
std::shared_ptr<ServerChannel> s_target_channel,
const std::shared_ptr<ConnectedClient> &invoker,
const std::string &reason_message,
ViewReasonId reason_id,
bool notify_client,
ts::rwshared_lock<ts::rw_mutex> &tree_lock) {
TIMING_START(timings);
tree_lock.auto_unlock();
auto command_lock = target->lock_command_handling();
if(auto err = tree_lock.auto_lock_exclusive(); err)
return ClientMoveResult::TREE_LOCK_FAILED;
TIMING_STEP(timings, "tree lock setup");
if(target->getChannel() == s_target_channel)
return ClientMoveResult::SUCCESS;
/* first step: resolve the target channel / or fix missing */
auto s_source_channel = dynamic_pointer_cast<ServerChannel>(target->getChannel());
assert(!target->getChannel() || s_source_channel != nullptr);
auto server_channel_tree = this->virtual_server_->server_channel_tree();
std::deque<property::ClientProperties> client_updates;
std::deque<property::ClientProperties> changed_groups{};
if(s_target_channel) {
/* don't let the client join a deleted channel */
if(s_target_channel->deleted) {
s_target_channel = dynamic_pointer_cast<ServerChannel>(server_channel_tree->getDefaultChannel());
assert(s_target_channel);
}
/* update the group properties here already, so for all enter views we could just send the new props directly */
changed_groups = this->virtual_server_->group_manager()->assignments().update_client_group_properties(target, s_target_channel->channelId());
client_updates.insert(client_updates.end(), changed_groups.begin(), changed_groups.end()); //TODO: Only update for clients which have no enter?
}
auto l_target_channel = s_target_channel ? server_channel_tree->findLinkedChannel(s_target_channel->channelId()) : nullptr;
auto l_source_channel = s_source_channel ? server_channel_tree->findLinkedChannel(s_source_channel->channelId()) : nullptr;
TIMING_STEP(timings, "channel lookup ");
/* second step: show the target channel to the client if its not shown and let him subscibe to the channel */
if(s_target_channel && notify_client) {
std::unique_lock client_channel_lock(target->get_channel_lock());
bool success = false;
/* TODO: Use a bunk here and not a notify for every single */
for(const auto& channel : target->channel_view()->show_channel(l_target_channel, success))
target->notifyChannelShow(channel->channel(), channel->previous_channel);
sassert(success);
if(!success)
return ClientMoveResult::VIEW_INSERT_FAILED;
target->subscribeChannel({s_target_channel}, false, true);
}
TIMING_STEP(timings, "target show chan");
if(s_target_channel) {
for(const auto& client : this->virtual_server_->connected_clients(false)) {
if (!notify_client && client == target) continue;
std::unique_lock client_channel_lock{client->get_channel_lock()};
auto chan_target = client->channel_view()->find_channel(s_target_channel);
if(chan_target) {
auto chan_source = client->channel_view()->find_channel(s_source_channel);
if(chan_source) {
if (chan_target->subscribed || client == target) {
if (client == target || client->isClientVisible(target, false)) {
client->notifyClientMoved(target, s_target_channel, reason_id, reason_message, invoker, false);
} else {
client->notifyClientEnterView(target, invoker, reason_message, s_target_channel, reason_id, s_source_channel, false);
}
} else if(client->isClientVisible(target, false)){
//Client got out of view
client->notifyClientLeftView(target, s_target_channel, reason_id, reason_message.empty() ? std::string{"view left"} : reason_message, invoker, false);
}
} else {
if(client == target && client->getType() != ClientType::CLIENT_INTERNAL && client->getType() != ClientType::CLIENT_MUSIC)
logCritical(this->get_server_id(), "{} Client enters visibility twice!", CLIENT_STR_LOG_PREFIX_(client));
//Client entered view
if(chan_target->subscribed)
client->notifyClientEnterView(target, invoker, reason_message, s_target_channel, ViewReasonId::VREASON_USER_ACTION, nullptr, false);
}
} else {
/* target channel isn't visible => so client gone out of view */
if(client == target && client->getType() != ClientType::CLIENT_INTERNAL && client->getType() != ClientType::CLIENT_MUSIC)
logCritical(this->get_server_id(), "{} Moving own client into a not visible channel! This shall not happen!", CLIENT_STR_LOG_PREFIX_(client));
//Test for in view? (Notify already does but nvm)
if(client->isClientVisible(target, false)){
//Client got out of view
if(reason_id == ViewReasonId::VREASON_USER_ACTION)
client->notifyClientLeftView(target, nullptr, ViewReasonId::VREASON_SERVER_LEFT, reason_message.empty() ? "joined a hidden channel" : reason_message, invoker, false);
else
client->notifyClientLeftView(target, nullptr, ViewReasonId::VREASON_SERVER_LEFT, reason_message.empty() ? "moved to a hidden channel" : reason_message, invoker, false);
}
}
}
if(s_source_channel)
s_source_channel->unregister_client(target);
s_target_channel->register_client(target);
} else {
/* client left the server */
if(target->getChannel()) {
for(const auto& client : this->virtual_server_->connected_clients(false)) {
if(!client || client == target)
continue;
std::unique_lock client_channel_lock(client->get_channel_lock());
if(client->isClientVisible(target, false))
client->notifyClientLeftView(target, nullptr, reason_id, reason_message, invoker, false);
}
s_source_channel->unregister_client(target);
}
}
TIMING_STEP(timings, "notify viewers ");
target->setChannel(s_target_channel);
tree_lock.downgrade_lock();
std::unique_lock client_channel_lock(target->get_channel_lock());
TIMING_STEP(timings, "lock own ch tree");
if (s_source_channel) {
s_source_channel->properties()[property::CHANNEL_LAST_LEFT] = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
this->virtual_server_->group_manager()->assignments().cleanup_channel_temporary_assignment(target->getClientDatabaseId(), s_source_channel->channelId());
auto update = target->properties()[property::CLIENT_IS_TALKER].as<bool>() || target->properties()[property::CLIENT_TALK_REQUEST].as<int64_t>() > 0;
if(update) {
target->properties()[property::CLIENT_IS_TALKER] = 0;
target->properties()[property::CLIENT_TALK_REQUEST] = 0;
target->properties()[property::CLIENT_TALK_REQUEST_MSG] = "";
client_updates.push_back(property::CLIENT_IS_TALKER);
client_updates.push_back(property::CLIENT_TALK_REQUEST);
client_updates.push_back(property::CLIENT_TALK_REQUEST_MSG);
}
TIMING_STEP(timings, "src chan up");
}
if (s_target_channel) {
if(target->update_cached_permissions()) /* update cached calculated permissions */
target->sendNeededPermissions(false);
TIMING_STEP(timings, "perm gr upd");
if(s_source_channel) {
std::deque<ChannelId> deleted;
for(const auto& channel : target->channel_view()->test_channel(l_source_channel, l_target_channel))
deleted.push_back(channel->channelId());
if(!deleted.empty())
target->notifyChannelHide(deleted, false);
/* force unsubscribe from old channel */
auto i_source_channel = s_source_channel->channelId();
if(std::find(deleted.begin(), deleted.end(), i_source_channel) == deleted.end()) {
auto source_channel_sub_power = target->calculate_permission(permission::i_channel_subscribe_power, i_source_channel);
if(!s_source_channel->permission_granted(permission::i_channel_needed_subscribe_power, source_channel_sub_power, false)) {
auto source_channel_sub_power_ignore = target->calculate_permission(permission::b_channel_ignore_subscribe_power, i_source_channel);
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore, true)) {
logTrace(this->get_server_id(), "Force unsubscribing of client {} for channel {}/{}. (Channel switch and no permissions)",
CLIENT_STR_LOG_PREFIX_(target), s_source_channel->name(),
i_source_channel
);
target->unsubscribeChannel({s_source_channel}, false); //Unsubscribe last channel (hasn't permissions)
}
}
}
TIMING_STEP(timings, "src hide ts");
}
}
client_channel_lock.unlock();
/* both methods lock if they require stuff */
this->notifyClientPropertyUpdates(target, client_updates, s_source_channel ? true : false);
TIMING_STEP(timings, "notify cpro");
if(s_target_channel) {
target->updateChannelClientProperties(false, s_source_channel ? true : false);
TIMING_STEP(timings, "notify_t_pr");
}
debugMessage(this->get_server_id(), "{} Client move timings: {}", CLIENT_STR_LOG_PREFIX_(target), TIMING_FINISH(timings));
}
/*
* 1. flag channel as deleted (lock channel tree so no moves)
* 2. Gather all clients within the channel (lock their execute lock)
* 3. Unlock channel tree and lock client locks
* 4. lock channel tree again and move the clients (No new clients should be joined because channel is flagged as deleted!)
*
* Note: channel cant be a ref because the channel itself gets deleted!
*/
ChannelDeleteResult ClientChannelService::delete_channel(std::shared_ptr<ServerChannel> channel, const std::shared_ptr<ConnectedClient> &invoker, const std::string &kick_message, ts::rwshared_lock<ts::rw_mutex> &tree_lock) {
if(auto err = tree_lock.auto_lock_exclusive(); err)
return ChannelDeleteResult::TREE_LOCK_FAILED;
if(channel->deleted)
return ChannelDeleteResult::SUCCESS;
std::deque<std::shared_ptr<ConnectedClient>> clients;
{
for(const auto& sub_channel : this->virtual_server_->server_channel_tree()->channels(channel)) {
auto s_channel = dynamic_pointer_cast<ServerChannel>(sub_channel);
assert(s_channel);
auto chan_clients = this->virtual_server_->find_clients_by_channel(s_channel);
clients.insert(clients.end(), chan_clients.begin(), chan_clients.end());
s_channel->deleted = true;
}
auto chan_clients = this->virtual_server_->find_clients_by_channel(channel);
clients.insert(clients.end(), chan_clients.begin(), chan_clients.end());
channel->deleted = true;
}
auto default_channel = dynamic_pointer_cast<ServerChannel>(this->virtual_server_->server_channel_tree()->getDefaultChannel());
assert(default_channel);
tree_lock.auto_unlock();
std::deque<std::unique_lock<threads::Mutex>> command_locks;
for(const auto& client : clients)
command_locks.push_back(std::move(std::unique_lock(client->get_channel_lock())));
for(const auto& client : clients) {
auto result = this->client_move(client, default_channel, invoker, kick_message, ViewReasonId::VREASON_CHANNEL_KICK, true, tree_lock);
if(result != ClientMoveResult::SUCCESS)
return ChannelDeleteResult::CLIENT_MOVE_FAILED;
}
if(auto err = tree_lock.auto_lock_exclusive(); err)
return ChannelDeleteResult::TREE_LOCK_FAILED;
command_locks.clear();
auto channel_ids = this->virtual_server_->server_channel_tree()->delete_channel_root(channel);
tree_lock.auto_lock_shared();
for(auto& client : this->virtual_server_->connected_clients(false)) {
std::unique_lock client_channel_lock(client->get_channel_lock());
client->notifyChannelDeleted(client->channel_view()->delete_channel_root(channel), invoker);
}
return ChannelDeleteResult::SUCCESS;
}

View File

@ -0,0 +1,94 @@
#pragma once
#include <string>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <Definitions.h>
#include <lock/rw_mutex.h>
namespace ts {
class ServerChannel;
}
namespace ts::server {
class ConnectedClient;
namespace vserver {
class VirtualServerBase;
}
}
namespace ts::server::channels {
enum struct ClientMoveResult {
SUCCESS,
TREE_LOCK_FAILED,
VIEW_INSERT_FAILED
};
enum struct ChannelDeleteResult {
SUCCESS,
TREE_LOCK_FAILED,
CLIENT_MOVE_FAILED
};
struct ChannelGroupInheritance {
GroupId group_id{};
ChannelId inherited_channel_id{};
};
class ClientChannelService {
public:
explicit ClientChannelService(vserver::VirtualServerBase*);
~ClientChannelService();
bool initialize(std::string& /* error */);
/* channel group related stuff */
/* this will lock the channel tree in read mode */
[[nodiscard]] ChannelGroupInheritance calculate_channel_group(ChannelId /* channel id */, ClientDbId /* client db id */, ClientType /* fallback type */);
/*
* ATTENTION: The methods client_ban, client_kick, client_move unlock the channel tree completely.
* All channel tree related variable must be checked again before using.
*/
/* Note: Use only this method to disconnect the client and notify everybody else that he has been banned! */
/* remove a client from the channel tree because he's banned */
[[nodiscard]] ClientMoveResult client_ban(
const std::shared_ptr<ConnectedClient>& /* client */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* reason */,
size_t /* length */,
ts::rwshared_lock<ts::rw_mutex>& /* tree lock */);
/* remove/move a client from/within the channel tree because he has been kicked */
[[nodiscard]] ClientMoveResult client_kick(
const std::shared_ptr<ConnectedClient>& /* client */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* reason */,
const std::shared_ptr<ServerChannel>& /* target channel */,
ts::rwshared_lock<ts::rw_mutex>& /* tree lock */
);
/* move a client within the channel tree */
[[nodiscard]] ClientMoveResult client_move(
const std::shared_ptr<ConnectedClient>& /* client */,
std::shared_ptr<ServerChannel> /* target channel */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* reason */,
ViewReasonId /* reason id */,
bool /* notify the client */,
ts::rwshared_lock<ts::rw_mutex>& /* tree lock */
);
[[nodiscard]] ChannelDeleteResult delete_channel(
std::shared_ptr<ServerChannel> /* target channel */,
const std::shared_ptr<ConnectedClient>& /* invoker */,
const std::string& /* kick message */,
ts::rwshared_lock<ts::rw_mutex>& /* tree lock */
);
private:
vserver::VirtualServerBase* virtual_server_{nullptr};
[[nodiscard]] ServerId get_server_id() const;
};
}

View File

@ -0,0 +1,319 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include <log/LogUtils.h>
#include "./PermissionsService.h"
#include "../InstanceHandler.h"
#include "../vserver/VirtualServerBase.h"
#include "../groups/Group.h"
#include "../groups/GroupManager.h"
#include "../groups/GroupAssignmentManager.h"
using namespace ts::permission;
using namespace ts::permission::v2;
using namespace ts::server::permissions;
PermissionService::PermissionService(ts::server::vserver::VirtualServerBase *handle) : virtual_server_{handle} {}
bool PermissionService::initialize(std::string &) { return true; }
bool PermissionService::load_data(std::string &) { return true; }
void PermissionService::unload_data() {}
ts::ServerId PermissionService::get_server_id() const {
return this->virtual_server_->server_id();
}
PermissionFlaggedValue PermissionService::calculate_client_permission(
PermissionType permission,
ClientDbId cldbid,
ClientType type,
ChannelId channel,
bool granted,
std::shared_ptr<CalculateCache> cache) {
auto result = this->calculate_client_permissions({permission}, cldbid, type, channel, granted, std::move(cache));
if(result.empty()) return {0, false};
return result.front().second;
}
std::vector<std::pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlaggedValue>> PermissionService::calculate_client_permissions(
const std::deque<permission::PermissionType>& permissions,
ClientDbId client_dbid,
ClientType client_type,
ChannelId channel_id,
bool calculate_granted,
std::shared_ptr<CalculateCache> cache) {
if(permissions.empty()) return {};
std::vector<std::pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlaggedValue>> result{};
result.reserve(permissions.size());
if(cache->client_database_id && cache->client_database_id != client_dbid)
cache = nullptr;
if(!cache)
cache = std::make_shared<CalculateCache>();
cache->client_type = client_type;
cache->client_database_id = client_dbid;
if(!cache->client_permissions)
cache->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->virtual_server_->server_ref(), client_dbid);
bool have_skip_permission = false;
int skip_permission_type = -1; /* -1 := unset | 0 := skip, not explicit | 1 := skip, explicit */
bool have_skip;
/*
* server_group_data[0] := Server group id
* server_group_data[1] := Skip flag
* server_group_data[2] := Negate flag
* server_group_data[3] := Permission value
*/
typedef std::tuple<GroupId, bool, bool, permission::PermissionValue> GroupData;
bool server_group_data_initialized = false;
std::vector<GroupData> server_group_data;
GroupData* active_server_group;
/* function to calculate skip permission */
auto calculate_skip = [&]{
skip_permission_type = 0;
/* test for skip permission within the client permission manager */
{
auto skip_value = cache->client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(skip_value.has_value) {
have_skip_permission = skip_value.value == 1;
skip_permission_type = 1;
logTrace(this->get_server_id(), "[Permission] Found skip permission in client permissions. Value: {}", have_skip_permission);
}
}
/* test for skip permission within all server groups */
if(skip_permission_type != 1) {
this->load_group_assignments(cache);
assert(cache->assignment_server_groups_set);
for(const auto& assignment : cache->assignment_server_groups) {
auto group_permissions = assignment->permissions();
auto flagged_value = group_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(flagged_value.has_value) {
have_skip_permission |= flagged_value.value == 1;
if(have_skip_permission) {
logTrace(this->get_server_id(), "[Permission] Found skip permission in client server group. Group: {} ({}), Value: {}", assignment->group_id(), assignment->display_name(), have_skip_permission);
break;
}
}
}
}
};
auto initialize_group_data = [&](const permission::PermissionType& permission_type) {
server_group_data_initialized = true;
active_server_group = nullptr;
this->load_group_assignments(cache);
assert(cache->assignment_server_groups_set);
server_group_data.resize(cache->assignment_server_groups.size());
auto it = server_group_data.begin();
for(auto& group : cache->assignment_server_groups) {
auto group_permissions = group->permissions();
auto permission_flags = group_permissions->permission_flags(permission_type);
auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set;
if(!flag_set)
continue;
//TODO: Test if there is may a group channel permissions
auto value = group_permissions->permission_values(permission_type);
*it = std::make_tuple(group->group_id(), (bool) permission_flags.skip, (bool) permission_flags.negate, calculate_granted ? value.grant : value.value);
it++;
}
if(it == server_group_data.begin())
return; /* no server group has that permission */
server_group_data.erase(it, server_group_data.end()); /* remove unneeded */
auto found_negate = false;
for(auto& group : server_group_data) {
if(std::get<2>(group)) {
found_negate = true;
break;
}
}
if(found_negate) {
server_group_data.erase(remove_if(server_group_data.begin(), server_group_data.end(), [](auto data) { return !std::get<2>(data); }), server_group_data.end());
logTrace(this->get_server_id(), "[Permission] Found negate flag within server groups. Groups left: {}", server_group_data.size());
if(server_group_data.empty())
logTrace(this->get_server_id(), "[Permission] After non negated groups have been kicked out the negated groups are empty! This should not happen! Permission: {}, Client ID: {}", permission_type, client_dbid);
permission::PermissionValue current_lowest = 0;
for(auto& group : server_group_data) {
if(!active_server_group || (std::get<3>(group) < current_lowest && std::get<3>(group) != -1)) {
current_lowest = std::get<3>(group);
active_server_group = &group;
}
}
} else {
permission::PermissionValue current_highest = 0;
for(auto& group : server_group_data) {
if(!active_server_group || (std::get<3>(group) > current_highest || std::get<3>(group) == -1)) {
current_highest = std::get<3>(group);
active_server_group = &group;
}
}
}
};
for(const auto& permission : permissions) {
if(permission == permission::b_client_skip_channelgroup_permissions) {
if(skip_permission_type == -1) /* initialize skip flag */
calculate_skip();
result.push_back({permission, {have_skip_permission, skip_permission_type == 1}});
continue;
}
server_group_data_initialized = false; /* reset all group data */
auto client_permission_flags = cache->client_permissions->permission_flags(permission);
/* lets try to resolve the channel specific permission */
if(channel_id > 0 && client_permission_flags.channel_specific) {
auto data = cache->client_permissions->channel_permission(permission, channel_id);
if(calculate_granted ? data.flags.grant_set : data.flags.value_set) {
result.push_back({permission, {calculate_granted ? data.values.grant : data.values.value, true}});
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned {} (Client channel permission)", client_dbid, permission::resolvePermissionData(permission)->name, data.values.value);
continue;
}
}
have_skip = channel_id == 0;
if(!have_skip) {
/* look if somewhere is the skip permission flag set */
if(skip_permission_type == -1) /* initialize skip flag */
calculate_skip();
have_skip = have_skip_permission;
}
if(!have_skip) {
/* okey we've no global skip. Then now lookup the groups and the client permissions */
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
/* okey the client has the permission, this counts */
have_skip = client_permission_flags.skip;
} else {
if(!server_group_data_initialized)
initialize_group_data(permission);
if(active_server_group)
have_skip = std::get<1>(*active_server_group);
}
}
if(!have_skip) {
/* lookup the channel group */
{
this->load_channel_assignment(cache, channel_id);
assert(cache->assignment_channel_group_channel == channel_id);
auto channel_assignment = cache->assignment_channel_group;
if(channel_assignment) {
auto group_permissions = channel_assignment->permissions();
auto permission_flags = group_permissions->permission_flags(permission);
auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set;
if(flag_set) {
auto value = group_permissions->permission_values(permission);
result.push_back({permission, {calculate_granted ? value.grant : value.value, true}});
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned {} (Channel group permission)", client_dbid, permission::resolvePermissionData(permission)->name, calculate_granted ? value.grant : value.value);
continue;
}
}
}
/* lookup the channel permissions. Whyever? */
{
this->load_server_channel(cache, channel_id);
if(cache->server_channel) {
auto channel_permissions = cache->server_channel->permissions();
auto data = calculate_granted ? channel_permissions->permission_granted_flagged(permission) : channel_permissions->permission_value_flagged(permission);
if(data.has_value) {
result.push_back({permission, {data.value, true}});
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned {} (Channel permission)", client_dbid, permission::resolvePermissionData(permission)->name, data.value);
continue;
}
}
}
}
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
auto client_value = cache->client_permissions->permission_values(permission);
result.push_back({permission, {calculate_granted ? client_value.grant : client_value.value, true}});
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned {} (Client permission)", client_dbid, permission::resolvePermissionData(permission)->name, client_value.value);
continue;
}
if(!server_group_data_initialized)
initialize_group_data(permission);
if(active_server_group) {
result.push_back({permission, {get<3>(*active_server_group), true}});
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned {} (Server group permission of group {})", client_dbid, permission::resolvePermissionData(permission)->name, get<3>(*active_server_group), get<0>(*active_server_group));
continue;
}
logTrace(this->get_server_id(), "[Permission] Calculation for client {} of permission {} returned in no permission.", client_dbid, permission::resolvePermissionData(permission)->name);
result.push_back({permission, {permNotGranted, false}});
}
return result;
}
void PermissionService::load_group_assignments(const std::shared_ptr<CalculateCache> &cache) {
if(cache->assignment_server_groups_set) return;
cache->assignment_server_groups_set = true;
auto group_manager = this->virtual_server_->group_manager();
auto assignments = group_manager->assignments().server_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, cache->client_database_id);
cache->assignment_server_groups.reserve(assignments.size());
for(auto& entry : assignments) {
auto group = group_manager->find_server_group(entry);
if(!group) continue;
cache->assignment_server_groups.push_back(group);
}
if(cache->assignment_server_groups.empty())
cache->assignment_server_groups.push_back(group_manager->default_server_group(cache->client_type));
}
void PermissionService::load_channel_assignment(const std::shared_ptr<CalculateCache> &cache, ts::ChannelId channel_id) {
if(cache->assignment_channel_group_channel == channel_id) return;
cache->assignment_channel_group_channel = channel_id;
auto group_manager = this->virtual_server_->group_manager();
auto channel_groups = group_manager->assignments().channel_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, cache->client_database_id);
auto it = std::find_if(channel_groups.begin(), channel_groups.end(), [&](const groups::ChannelGroupAssignment& assignment) {
return assignment.channel_id == channel_id;
});
GroupId group_id{0};
if(it != channel_groups.end())
group_id = it->group_id;
if(!group_id) {
auto assignment = this->virtual_server_->channel_service().calculate_channel_group(channel_id, cache->client_database_id, cache->client_type);
group_id = assignment.group_id;
}
cache->assignment_channel_group = group_manager->find_channel_group(group_id);
if(!cache->assignment_channel_group)
cache->assignment_channel_group = group_manager->default_channel_group(cache->client_type);
}
void PermissionService::load_server_channel(const std::shared_ptr<CalculateCache> &cache, ts::ChannelId channel_id) {
if(cache->last_server_channel == channel_id) return;
cache->last_server_channel = channel_id;
auto channel_tree = this->virtual_server_->server_channel_tree();
auto tree_lock = this->virtual_server_->lock_channel_clients();
cache->server_channel = channel_tree->findChannel(channel_id);
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <string>
#include <PermissionRegister.h>
namespace ts::server {
namespace groups {
class ServerGroup;
class ChannelGroup;
}
namespace vserver {
class VirtualServerBase;
}
}
namespace ts::server::permissions {
struct CalculateCache {
ClientDbId client_database_id{0};
ClientType client_type{ClientType::UNKNOWN};
std::shared_ptr<permission::v2::PermissionRegister> client_permissions;
std::vector<std::shared_ptr<groups::ServerGroup>> assignment_server_groups;
bool assignment_server_groups_set{false};
ChannelId assignment_channel_group_channel{0};
std::shared_ptr<groups::ChannelGroup> assignment_channel_group{};
std::shared_ptr<BasicChannel> server_channel;
ChannelId last_server_channel{0};
};
class PermissionService {
public:
explicit PermissionService(vserver::VirtualServerBase*);
~PermissionService() = default;
bool initialize(std::string& /* error */);
bool load_data(std::string& /* error */);
void unload_data();
permission::v2::PermissionFlaggedValue calculate_client_permission(
permission::PermissionType,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted,
std::shared_ptr<CalculateCache> cache{nullptr}
);
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_client_permissions(
const std::deque<permission::PermissionType>&,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted,
std::shared_ptr<CalculateCache> cache{nullptr}
);
private:
vserver::VirtualServerBase* virtual_server_{nullptr};
[[nodiscard]] ServerId get_server_id() const;
void load_group_assignments(const std::shared_ptr<CalculateCache>&);
void load_channel_assignment(const std::shared_ptr<CalculateCache>&, ChannelId /* channel id */);
void load_server_channel(const std::shared_ptr<CalculateCache>&, ChannelId /* channel id */);
};
}

View File

@ -0,0 +1,33 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include <Error.h>
#include "DefaultServer.h"
using namespace ts::server::vserver;
VirtualServerStartResult DefaultServer::start_server_virtual_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &error) {
if(!lock.auto_lock_exclusive()) {
error = "failed to lock server state";
return VirtualServerStartResult::CUSTOM;
}
if(auto result = DefaultServer::start_server_virtual_(lock, error); result != VirtualServerStartResult::SUCCESS)
return result;
//TODO: Load anything
this->status_ = VirtualServerStatus::VIRTUAL;
return VirtualServerStartResult::SUCCESS;
}
VirtualServerStartResult DefaultServer::start_server_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &string) {
return VirtualServerStartResult::SERVER_IS_DEFAULT;
}
void DefaultServer::stop_server_(ts::rwshared_lock<ts::rw_mutex> &lock) {
VirtualServerBase::stop_server_(lock);
/* TODO: Save server states? Because we can't really shut down. */
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "./VirtualServerBase.h"
namespace ts::server::vserver {
class DefaultServer : public VirtualServerBase {
public:
private:
protected:
VirtualServerStartResult start_server_virtual_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &string) override;
VirtualServerStartResult start_server_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &string) override;
void stop_server_(ts::rwshared_lock<ts::rw_mutex> &lock) override;
};
}

View File

@ -0,0 +1,26 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include "VirtualServer.h"
using namespace ts::server::vserver;
//This method gets called when server is OFFLINE or DEPLOYING
VirtualServerStartResult VirtualServer::start_server_virtual_(ts::rwshared_lock<ts::rw_mutex> &lock,
std::string &error) {
//TOOD: load bans, public key, etc
return VirtualServerStartResult::SUCCESS;
}
VirtualServerStartResult VirtualServer::start_server_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &error) {
//TODO: Start voice binding etc
return VirtualServerStartResult::SUCCESS;
}
void VirtualServer::stop_server_(ts::rwshared_lock<ts::rw_mutex> &lock) {
//TODO: Stop bindings (if set) and unload everything
}

View File

@ -0,0 +1,53 @@
#pragma once
#include "./VirtualServerBase.h"
namespace ts {
namespace music {
class MusicBotManager;
}
namespace stats {
class ConnectionStatistics;
}
namespace server {
namespace tokens {
class TokenManager;
}
namespace bans {
class BanManager;
}
namespace conversation {
class ConversationManager;
}
}
}
namespace ts::server::vserver {
class VirtualServer : public VirtualServerBase {
public:
bool initialize(std::string &string) override;
/* managers */
[[nodiscard]] inline tokens::TokenManager& token_manager() { return *this->token_manager_; }
[[nodiscard]] inline bans::BanManager& ban_manager() { return *this->ban_manager_; }
[[nodiscard]] inline const std::shared_ptr<music::MusicBotManager>& music_bot_manager() { return this->music_bots_; }
[[nodiscard]] inline const std::shared_ptr<conversation::ConversationManager>& conversation_manager() { return this->conversation_manager_; }
private:
std::unique_ptr<tokens::TokenManager> token_manager_;
std::unique_ptr<bans::BanManager> ban_manager_;
std::shared_ptr<music::MusicBotManager> music_bots_;
std::shared_ptr<conversation::ConversationManager> conversation_manager_;
protected:
VirtualServerStartResult start_server_virtual_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &string) override;
VirtualServerStartResult start_server_(ts::rwshared_lock<ts::rw_mutex> &lock, std::string &string) override;
void stop_server_(ts::rwshared_lock<ts::rw_mutex> &lock) override;
void execute_tick(const std::chrono::system_clock::time_point &point) override;
};
}

View File

@ -0,0 +1,78 @@
//
// Created by WolverinDEV on 03/03/2020.
//
#include "./VirtualServerBase.h"
#include <log/LogUtils.h>
using namespace ts::server::vserver;
bool VirtualServerBase::initialize(std::string &error) {
//TODO?
return true;
}
VirtualServerStartResult VirtualServerBase::start_server_virtual(std::string &error) {
ts::rwshared_lock slock{this->status_mutex_, ts::rw_lock_exclusive};
if(this->status_ != VirtualServerStatus::STOPPED)
return VirtualServerStartResult::SERVER_IS_NOT_OFFLINE;
slock.downgrade_lock();
if(auto err = this->start_server_virtual_(slock, error); err != VirtualServerStartResult::SUCCESS)
return err;
if(auto err = slock.upgrade_lock(); err)
logCritical(this->server_id(), "Failed to lock status lock after server virtual start. Ignoring it and still setting state to virtual!");
this->status_ = VirtualServerStatus::VIRTUAL;
return VirtualServerStartResult::SUCCESS;
}
VirtualServerStartResult VirtualServerBase::start_server(std::string &error) {
ts::rwshared_lock slock{this->status_mutex_, ts::rw_lock_exclusive};
if(this->status_ != VirtualServerStatus::VIRTUAL && this->status_ == VirtualServerStatus::STOPPED)
return VirtualServerStartResult::SERVER_IS_NOT_OFFLINE;
auto full_start = this->status_ == VirtualServerStatus::STOPPED;
this->status_ = VirtualServerStatus::BOOTING;
/* even if queries could be connected, a start from virtual should not lead to a crash! */
slock.downgrade_lock();
if(full_start)
if(auto err = this->start_server_virtual_(slock, error); err != VirtualServerStartResult::SUCCESS)
return err;
if(auto err = this->start_server_(slock, error); err != VirtualServerStartResult::SUCCESS)
return err;
if(auto err = slock.upgrade_lock(); err)
logCritical(this->server_id(), "Failed to lock status lock after server start. Ignoring it and still setting state to running!");
this->status_ = VirtualServerStatus::RUNNING;
return VirtualServerStartResult::SUCCESS;
}
VirtualServerStopResult VirtualServerBase::stop_server() {
ts::rwshared_lock slock{this->status_mutex_, ts::rw_lock_shared};
if(this->status_ != VirtualServerStatus::RUNNING && this->status_ != VirtualServerStatus::VIRTUAL)
return VirtualServerStopResult::SERVER_IS_NOT_RUNNING;
if(auto err = slock.upgrade_lock(); err)
return VirtualServerStopResult::STATE_LOCK_FAILED;
this->status_ = VirtualServerStatus::STOPPING;
slock.downgrade_lock();
this->stop_server_(slock);
if(auto err = slock.upgrade_lock(); err)
logCritical(this->server_id(), "Failed to lock status lock after server stop. Ignoring it and still setting state to stopped!");
this->status_ = VirtualServerStatus::STOPPED;
return VirtualServerStopResult::SUCCESS;
}
VirtualServerStartResult VirtualServerBase::start_server_(ts::rwshared_lock<ts::rw_mutex> &slock, std::string &error) {
//TODO: Load server permissions, etc
}

View File

@ -0,0 +1,143 @@
#pragma once
#include <Definitions.h>
#include <lock/rw_mutex.h>
#include <PermissionRegister.h>
#include <sql/SqlQuery.h>
#include "../services/PermissionsService.h"
#include "../services/ClientChannelService.h"
namespace ts::server {
class ConnectedClient;
namespace groups {
class GroupManager;
}
}
namespace ts {
class Properties;
class ServerChannelTree;
namespace stats {
class ConnectionStatistics;
}
}
namespace ts::server::vserver {
struct VirtualServerStatus {
enum value {
STOPPED, /* no data has been loaded */
BOOTING, /* loading & initializing data */
VIRTUAL, /* only available for query clients */
STARTING, /* start bindings */
RUNNING, /* server is running */
STOPPING, /* server is stopping and unloading any data */
DEPLOYING /* server is in deploy modus */
};
};
enum struct VirtualServerStartResult {
SUCCESS,
BIND_FAILED,
SERVER_IS_DEFAULT,
CUSTOM,
SERVER_IS_NOT_OFFLINE
};
enum struct VirtualServerStopResult {
SUCCESS,
SERVER_IS_NOT_RUNNING,
STATE_LOCK_FAILED
};
class VirtualServerBase {
public:
//TODO: Constructor
//VirtualServerBase();
~VirtualServerBase();
[[nodiscard]] inline std::shared_ptr<VirtualServerBase> server_ref() { return this->server_ref_.lock(); }
/* basic initialize to the STOPPED state */
virtual bool initialize(std::string& /* error */);
VirtualServerStartResult start_server_virtual(std::string& /* error */);
VirtualServerStartResult start_server(std::string& /* error */);
VirtualServerStopResult stop_server();
/* basic information */
[[nodiscard]] inline ServerId server_id() const { return this->server_id_; }
[[nodiscard]] inline VirtualServerStatus::value server_status() const { return this->status_; }
[[nodiscard]] inline ts::rwshared_lock<ts::rw_mutex> lock_server_status() { return ts::rwshared_lock{this->status_mutex_, ts::rw_lock_shared}; }
[[nodiscard]] inline sql::SqlManager* sql_manager() { return this->sql_manager_; }
[[nodiscard]] inline const std::shared_ptr<stats::ConnectionStatistics>& server_connection_statistics() { return this->server_connection_statistics_; }
[[nodiscard]] inline permissions::PermissionService& permission_service() { return this->permission_service_; }
[[nodiscard]] inline channels::ClientChannelService& channel_service() { return this->channel_service_; }
[[nodiscard]] inline ts::rwshared_lock<ts::rw_mutex> lock_channel_clients() { return ts::rwshared_lock{this->channel_clients_lock_, ts::rw_lock_shared}; }
[[nodiscard]] inline std::mutex& client_nickname_lock() { return this->client_nickname_lock_; }
[[nodiscard]] inline const std::shared_ptr<Properties>& server_properties() { return this->server_properties_; }
[[nodiscard]] inline const std::shared_ptr<ServerChannelTree>& server_channel_tree() { return this->server_channel_tree_; }
[[nodiscard]] inline const std::shared_ptr<groups::GroupManager>& group_manager() { return this->group_manager_; }
/* client management */
/* this may block until the current command of the client has been finished executed */
void unregister_client(const std::shared_ptr<ConnectedClient>& /* client */);
void register_client(const std::shared_ptr<ConnectedClient>& /* client */);
/* ATTENTION: lock_channel_clients should be acquired for the following methods. Else the client might be disconnected while working with him. */
[[nodiscard]] std::vector<std::shared_ptr<ConnectedClient>> connected_clients(bool /* must be registered within the channel tree */);
[[nodiscard]] std::shared_ptr<ConnectedClient> find_client_by_id(ClientId /* id */);
[[nodiscard]] std::vector<std::shared_ptr<ConnectedClient>> find_clients_by_uid(ClientId /* id */);
[[nodiscard]] std::vector<std::shared_ptr<ConnectedClient>> find_clients_by_channel(const std::shared_ptr<ServerChannel>& /* channel */);
protected:
std::weak_ptr<VirtualServerBase> server_ref_{};
sql::SqlManager* sql_manager_{nullptr}; //TODO!
ServerId server_id_{0};
ts::rw_mutex status_mutex_{};
VirtualServerStatus::value status_{VirtualServerStatus::STOPPED};
std::shared_ptr<Properties> server_properties_{nullptr};
std::shared_ptr<ServerChannelTree> server_channel_tree_{nullptr};
/*
* Lock whenever we want to read/write from the channel tree or the clients within
* Attention: We're not allowed to do permission calculations while having the channel tree in write lock!
*/
ts::rw_mutex channel_clients_lock_{};
std::mutex client_nickname_lock_{};
/* some services */
permissions::PermissionService permission_service_;
channels::ClientChannelService channel_service_;
struct {
size_t count{0};
std::mutex mutex{};
std::vector<std::shared_ptr<ConnectedClient>> clients{};
} registered_clients;
std::shared_ptr<groups::GroupManager> group_manager_;
std::shared_ptr<stats::ConnectionStatistics> server_connection_statistics_;
/* private methods */
virtual VirtualServerStartResult start_server_virtual_(ts::rwshared_lock<ts::rw_mutex>& /* state lock */, std::string& /* error */);
virtual VirtualServerStartResult start_server_(ts::rwshared_lock<ts::rw_mutex>& /* state lock */, std::string& /* error */);
virtual void stop_server_(ts::rwshared_lock<ts::rw_mutex>& /* state lock */);
virtual void execute_tick(const std::chrono::system_clock::time_point& /* now */) = 0;
};
}

View File

@ -14,4 +14,13 @@ Web client:
IO-Thread: ??
Executor thread:
-
-
Definition Services:
Services only provide information or are helper for certain action.
They do not save any states or variables.
Definition Manager:
Unlike services managers are controlling data in memory and/or within the database.

2
shared

@ -1 +1 @@
Subproject commit ece70e4df474a5e027e3c54e8a8e1be84a2a6a72
Subproject commit ae4751ee6fcb857771ff5f4e57459a75638e2b1f