Using tasks instead of inlining certain client updates

This commit is contained in:
WolverinDEV 2021-02-21 21:56:52 +01:00
parent 71b2d734bd
commit b40e1326cc
18 changed files with 265 additions and 221 deletions

View File

@ -72,12 +72,14 @@ void ConnectionStatistics::tick() {
this->total_statistics += current; this->total_statistics += current;
auto current_second = std::chrono::floor<std::chrono::seconds>(now.time_since_epoch()).count(); auto current_second = std::chrono::floor<std::chrono::seconds>(now.time_since_epoch()).count();
if(statistics_minute_offset == 0) if(statistics_minute_offset == 0) {
statistics_minute_offset = current_second; statistics_minute_offset = current_second;
}
/* fill all "lost" with the current bandwidth as well */ /* fill all "lost" with the current bandwidth as well */
while(statistics_minute_offset <= current_second) while(statistics_minute_offset <= current_second) {
this->statistics_minute[statistics_minute_offset++ % this->statistics_minute.size()] = current_normalized; this->statistics_minute[statistics_minute_offset++ % this->statistics_minute.size()] = current_normalized;
}
this->last_second_tick = now; this->last_second_tick = now;
} }
} }

View File

@ -53,7 +53,6 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
logCritical(LOG_INSTANCE, "Instance task executor received exception: {}", message); logCritical(LOG_INSTANCE, "Instance task executor received exception: {}", message);
}); });
this->tick_manager = make_shared<threads::Scheduler>(config::threads::ticking, "tick task ");
this->statistics = make_shared<stats::ConnectionStatistics>(nullptr); this->statistics = make_shared<stats::ConnectionStatistics>(nullptr);
std::string error_message{}; std::string error_message{};
@ -122,12 +121,12 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
this->properties()[property::SERVERINSTANCE_PERMISSIONS_VERSION] = this->sql->get_permissions_version(); this->properties()[property::SERVERINSTANCE_PERMISSIONS_VERSION] = this->sql->get_permissions_version();
globalServerAdmin = std::make_shared<ts::server::InternalClient>(this->getSql(), nullptr, "serveradmin", true); this->globalServerAdmin = std::make_shared<ts::server::InternalClient>(this->getSql(), nullptr, "serveradmin", true);
globalServerAdmin->initialize_weak_reference(this->globalServerAdmin); this->globalServerAdmin->initialize_weak_reference(this->globalServerAdmin);
ts::server::DatabaseHelper::assignDatabaseId(this->getSql(), 0, globalServerAdmin); ts::server::DatabaseHelper::assignDatabaseId(this->getSql(), 0, globalServerAdmin);
this->_musicRoot = std::make_shared<InternalClient>(this->getSql(), nullptr, "Music Manager", false); this->_musicRoot = std::make_shared<InternalClient>(this->getSql(), nullptr, "Music Manager", false);
globalServerAdmin->initialize_weak_reference(this->_musicRoot); dynamic_pointer_cast<InternalClient>(this->_musicRoot)->initialize_weak_reference(this->_musicRoot);
{ {
this->groupManager = std::make_shared<GroupManager>(nullptr, this->getSql()); this->groupManager = std::make_shared<GroupManager>(nullptr, this->getSql());
@ -213,21 +212,6 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
this->web_list = make_shared<weblist::WebListManager>(); this->web_list = make_shared<weblist::WebListManager>();
} }
void InstanceHandler::executeTick(VirtualServer* server) {
auto str = "server_" + to_string(server->getServerId());
if(!this->tick_manager->schedule(str, std::bind(&VirtualServer::executeServerTick, server), milliseconds(500))) {
logCritical(LOG_INSTANCE, "Could not schedule server ticking task!");
}
}
void InstanceHandler::cancelExecute(VirtualServer* server) {
auto str = "server_" + to_string(server->getServerId());
if(!this->tick_manager->cancelTask(str)){
logError(LOG_INSTANCE, "Could not stop server tick task!");
}
}
InstanceHandler::~InstanceHandler() { InstanceHandler::~InstanceHandler() {
delete this->_properties; delete this->_properties;
delete this->banMgr; delete this->banMgr;
@ -238,7 +222,6 @@ InstanceHandler::~InstanceHandler() {
_musicRoot = nullptr; _musicRoot = nullptr;
statistics = nullptr; statistics = nullptr;
tick_manager = nullptr;
} }
inline string strip(std::string message) { inline string strip(std::string message) {
@ -417,7 +400,14 @@ FwIDAQAB
startTimestamp = system_clock::now(); startTimestamp = system_clock::now();
this->voiceServerManager->executeAutostart(); this->voiceServerManager->executeAutostart();
this->scheduler()->schedule(INSTANCE_TICK_NAME, bind(&InstanceHandler::tickInstance, this), milliseconds{500}); this->general_task_executor()->schedule_repeating(
this->tick_task_id,
"instance ticker",
std::chrono::milliseconds{500},
[&](const auto&) {
this->tickInstance();
}
);
return true; return true;
} }
@ -431,8 +421,11 @@ void InstanceHandler::stopInstance() {
this->web_list->enabled = false; this->web_list->enabled = false;
this->server_command_executor_->shutdown(); this->server_command_executor_->shutdown();
/* TODO: Block on canceling. */
this->general_task_executor()->cancel_task(this->tick_task_id);
this->tick_task_id = 0;
threads::MutexLock lock_tick(this->lock_tick); threads::MutexLock lock_tick(this->lock_tick);
this->scheduler()->cancelTask(INSTANCE_TICK_NAME);
debugMessage(LOG_INSTANCE, "Stopping all virtual servers"); debugMessage(LOG_INSTANCE, "Stopping all virtual servers");
if (this->voiceServerManager) if (this->voiceServerManager)
@ -470,7 +463,9 @@ void InstanceHandler::stopInstance() {
void InstanceHandler::tickInstance() { void InstanceHandler::tickInstance() {
threads::MutexLock lock(this->lock_tick); threads::MutexLock lock(this->lock_tick);
if(!this->active) return; if(!this->active) {
return;
}
auto now = system_clock::now(); auto now = system_clock::now();

View File

@ -63,9 +63,6 @@ namespace ts {
std::chrono::time_point<std::chrono::system_clock> getStartTimestamp(){ return startTimestamp; } std::chrono::time_point<std::chrono::system_clock> getStartTimestamp(){ return startTimestamp; }
void executeTick(VirtualServer*);
void cancelExecute(VirtualServer*);
bool reloadConfig(std::vector<std::string>& /* errors */, bool /* reload file */); bool reloadConfig(std::vector<std::string>& /* errors */, bool /* reload file */);
void setWebCertRoot(const std::string& /* key */, const std::string& /* certificate */, const std::string& /* revision */); void setWebCertRoot(const std::string& /* key */, const std::string& /* certificate */, const std::string& /* revision */);
@ -79,7 +76,6 @@ namespace ts {
[[nodiscard]] inline const auto& general_task_executor(){ return this->general_task_executor_; } [[nodiscard]] inline const auto& general_task_executor(){ return this->general_task_executor_; }
std::shared_ptr<stats::ConnectionStatistics> getStatistics(){ return statistics; } std::shared_ptr<stats::ConnectionStatistics> getStatistics(){ return statistics; }
std::shared_ptr<threads::Scheduler> scheduler(){ return this->tick_manager; }
std::shared_ptr<license::InstanceLicenseInfo> generateLicenseData(); std::shared_ptr<license::InstanceLicenseInfo> generateLicenseData();
std::shared_ptr<TeamSpeakLicense> getTeamSpeakLicense() { return this->teamspeak_license; } std::shared_ptr<TeamSpeakLicense> getTeamSpeakLicense() { return this->teamspeak_license; }
@ -116,6 +112,8 @@ namespace ts {
std::condition_variable activeCon; std::condition_variable activeCon;
bool active = false; bool active = false;
task_id tick_task_id{};
std::chrono::system_clock::time_point startTimestamp; std::chrono::system_clock::time_point startTimestamp;
std::chrono::system_clock::time_point sqlTestTimestamp; std::chrono::system_clock::time_point sqlTestTimestamp;
std::chrono::system_clock::time_point speachUpdateTimestamp; std::chrono::system_clock::time_point speachUpdateTimestamp;
@ -152,7 +150,6 @@ namespace ts {
std::shared_ptr<license::LicenseService> license_service_{nullptr}; std::shared_ptr<license::LicenseService> license_service_{nullptr};
std::shared_ptr<stats::ConnectionStatistics> statistics = nullptr; std::shared_ptr<stats::ConnectionStatistics> statistics = nullptr;
std::shared_ptr<threads::Scheduler> tick_manager = nullptr;
std::shared_ptr<task_executor> general_task_executor_{nullptr}; std::shared_ptr<task_executor> general_task_executor_{nullptr};

View File

@ -532,8 +532,7 @@ void VirtualServer::client_move(
} }
if (s_target_channel) { if (s_target_channel) {
if(target->update_client_needed_permissions()) /* update cached calculated permissions */ target->task_update_needed_permissions.enqueue();
target->sendNeededPermissions(false);
TIMING_STEP(timings, "perm gr upd"); TIMING_STEP(timings, "perm gr upd");
if(s_source_channel) { if(s_source_channel) {

View File

@ -503,8 +503,18 @@ bool VirtualServer::start(std::string& error) {
#endif #endif
} }
//Startup ticking auto weak_this = this->self;
serverInstance->executeTick(this); serverInstance->general_task_executor()->schedule_repeating(
this->tick_task_id,
"server tick " + std::to_string(this->serverId),
std::chrono::milliseconds {500},
[weak_this](const auto& scheduled){
auto ref_self = weak_this.lock();
if(ref_self) {
ref_self->executeServerTick();
}
}
);
if(this->properties()[property::VIRTUALSERVER_WEBLIST_ENABLED].as<bool>()) if(this->properties()[property::VIRTUALSERVER_WEBLIST_ENABLED].as<bool>())
serverInstance->getWebList()->enable_report(this->self.lock()); serverInstance->getWebList()->enable_report(this->self.lock());
@ -591,7 +601,8 @@ void VirtualServer::stop(const std::string& reason, bool disconnect_query) {
} }
this->music_manager_->disconnectBots(); this->music_manager_->disconnectBots();
serverInstance->cancelExecute(this); serverInstance->general_task_executor()->cancel_task(this->tick_task_id);
this->tick_task_id = 0;
if(this->udpVoiceServer) this->udpVoiceServer->stop(); if(this->udpVoiceServer) this->udpVoiceServer->stop();
this->udpVoiceServer = nullptr; this->udpVoiceServer = nullptr;
@ -1001,8 +1012,9 @@ vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlagge
bool skip_channel_permissions = channel_id == 0; bool skip_channel_permissions = channel_id == 0;
if(!skip_channel_permissions) { if(!skip_channel_permissions) {
/* look if somewhere is the skip permission flag set */ /* look if somewhere is the skip permission flag set */
if(skip_permission_type == -1) /* initialize skip flag */ if(skip_permission_type == -1) {/* initialize skip flag */
calculate_skip(); calculate_skip();
}
skip_channel_permissions = have_skip_permission; skip_channel_permissions = have_skip_permission;
} }
if(!skip_channel_permissions) { if(!skip_channel_permissions) {
@ -1213,10 +1225,9 @@ bool VirtualServer::resetPermissions(std::string& token) {
client->notifyChannelGroupList(); client->notifyChannelGroupList();
} }
if(this->notifyClientPropertyUpdates(client, this->getGroupManager()->update_server_group_property(client, true, client->getChannel()))) { if(this->notifyClientPropertyUpdates(client, this->getGroupManager()->update_server_group_property(client, true, client->getChannel()))) {
if(client->update_client_needed_permissions()) /* update cached calculated permissions */ client->task_update_needed_permissions.enqueue();
client->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
} }
client->updateChannelClientProperties(true, true); client->task_update_channel_client_properties.enqueue();
} }
return true; return true;
} }

View File

@ -21,6 +21,7 @@
#include "manager/LetterManager.h" #include "manager/LetterManager.h"
#include "Configuration.h" #include "Configuration.h"
#include "protocol/ringbuffer.h" #include "protocol/ringbuffer.h"
#include <misc/task_executor.h>
#include <tomcrypt.h> #include <tomcrypt.h>
#undef byte #undef byte
@ -302,6 +303,8 @@ namespace ts {
//Locks by tick, start and stop //Locks by tick, start and stop
threads::Mutex stateLock; threads::Mutex stateLock;
ServerState::value state = ServerState::OFFLINE; ServerState::value state = ServerState::OFFLINE;
task_id tick_task_id{};
std::chrono::system_clock::time_point lastTick; std::chrono::system_clock::time_point lastTick;
void executeServerTick(); void executeServerTick();

View File

@ -10,10 +10,7 @@
#include "src/VirtualServer.h" #include "src/VirtualServer.h"
#include "voice/VoiceClient.h" #include "voice/VoiceClient.h"
#include "../server/VoiceServer.h"
#include "../InstanceHandler.h" #include "../InstanceHandler.h"
#include "ConnectedClient.h"
#include <event.h> #include <event.h>
using namespace std; using namespace std;
@ -44,7 +41,18 @@ void ConnectedClient::initialize_weak_reference(const std::shared_ptr<ConnectedC
this->task_update_needed_permissions = multi_shot_task{serverInstance->general_task_executor(), "update permissions for " + this->getLoggingPeerIp(), [weak_self]{ this->task_update_needed_permissions = multi_shot_task{serverInstance->general_task_executor(), "update permissions for " + this->getLoggingPeerIp(), [weak_self]{
auto self = weak_self.lock(); auto self = weak_self.lock();
if(self) { if(self) {
self->update_client_needed_permissions(); auto permissions_changed = self->update_client_needed_permissions();
logTrace(self->getServerId(), "{} Updated client permissions. Permissions changed: {}", CLIENT_STR_LOG_PREFIX_(self), permissions_changed);
if(permissions_changed) {
self->sendNeededPermissions(true);
}
}
}};
this->task_update_channel_client_properties = multi_shot_task{serverInstance->general_task_executor(), "update channel properties for " + this->getLoggingPeerIp(), [weak_self]{
auto self = weak_self.lock();
if(self) {
self->updateChannelClientProperties(true, true);
} }
}}; }};
} }
@ -102,98 +110,98 @@ std::shared_ptr<ConnectionInfoData> ConnectedClient::request_connection_info(con
return info.data; return info.data;
} }
//Attention the client should be only read only locked!
void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool notify_self) { void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool notify_self) {
/* this->server may be null! */ /* The server and the current channel might change while executing this method! */
shared_ptr<VirtualServer> server_ref = this->server; auto server_ref = this->server;
auto channel = this->currentChannel;
auto permissions = this->calculate_permissions({ auto permissions = this->calculate_permissions({
permission::i_client_talk_power, permission::i_client_talk_power,
permission::b_client_ignore_antiflood, permission::b_client_ignore_antiflood,
permission::i_channel_view_power, permission::i_channel_view_power,
permission::b_channel_ignore_view_power permission::b_channel_ignore_view_power,
}, this->currentChannel ? this->currentChannel->channelId() : 0); permission::i_icon_id,
permission::b_client_is_priority_speaker,
}, channel ? channel->channelId() : 0);
permission::v2::PermissionFlaggedValue permission::v2::PermissionFlaggedValue
permission_talk_power{0, false}, permission_talk_power{0, false},
permission_ignore_antiflood{0, false}, permission_ignore_antiflood{0, false},
permission_channel_view_power{0, false}, permission_channel_view_power{0, false},
permission_channel_ignore_view_power{0, false}; permission_channel_ignore_view_power{0, false},
permission_icon_id{0, false},
permission_client_is_priority_speaker{0, false};
for(const auto& perm : permissions) { for(const auto& perm : permissions) {
if(perm.first == permission::i_client_talk_power) if(perm.first == permission::i_client_talk_power) {
permission_talk_power = perm.second; permission_talk_power = perm.second;
else if(perm.first == permission::b_client_ignore_antiflood) } else if(perm.first == permission::b_client_ignore_antiflood) {
permission_ignore_antiflood = perm.second; permission_ignore_antiflood = perm.second;
else if(perm.first == permission::i_channel_view_power) } else if(perm.first == permission::i_channel_view_power) {
permission_channel_view_power = perm.second; permission_channel_view_power = perm.second;
else if(perm.first == permission::b_channel_ignore_view_power) } else if(perm.first == permission::b_channel_ignore_view_power) {
permission_channel_ignore_view_power = perm.second; permission_channel_ignore_view_power = perm.second;
else sassert(false); } else if(perm.first == permission::i_icon_id) {
permission_icon_id = perm.second;
} else if(perm.first == permission::b_client_is_priority_speaker) {
permission_client_is_priority_speaker = perm.second;
} else {
sassert(false);
}
} }
deque<property::ClientProperties> notifyList; std::deque<property::ClientProperties> updated_client_properties;
debugMessage(this->getServerId(), "{} Got a channel talk power of {} Talk power set is {}", CLIENT_STR_LOG_PREFIX, permission_talk_power.has_value ? permission_talk_power.value : 0, this->properties()[property::CLIENT_TALK_POWER].as<uint64_t>()); {
if((permission_talk_power.has_value ? permission_talk_power.value : 0) != this->properties()[property::CLIENT_TALK_POWER].as<uint64_t>()) { //We do not have to update tp if there's no channel auto old_talk_power = this->properties()[property::CLIENT_TALK_POWER].as_save<int64_t>();
this->properties()[property::CLIENT_TALK_POWER] = (permission_talk_power.has_value ? permission_talk_power.value : 0); auto new_talk_power = permission_talk_power.has_value ? permission_talk_power.value : 0;
notifyList.emplace_back(property::CLIENT_TALK_POWER);
auto update = this->properties()[property::CLIENT_IS_TALKER].as<bool>() || this->properties()[property::CLIENT_TALK_REQUEST].as<int64_t>() > 0; debugMessage(this->getServerId(), "{} Recalculated talk power. New value: {} Old value: {}", CLIENT_STR_LOG_PREFIX, new_talk_power, old_talk_power);
if(update && this->currentChannel) { if(old_talk_power != new_talk_power) {
if(this->currentChannel->talk_power_granted(permission_talk_power)) { this->properties()[property::CLIENT_TALK_POWER] = new_talk_power;
this->properties()[property::CLIENT_IS_TALKER] = 0; updated_client_properties.emplace_back(property::CLIENT_TALK_POWER);
this->properties()[property::CLIENT_TALK_REQUEST] = 0;
this->properties()[property::CLIENT_TALK_REQUEST_MSG] = ""; auto retract_request = this->properties()[property::CLIENT_IS_TALKER].as<bool>();
notifyList.emplace_back(property::CLIENT_IS_TALKER); if(!retract_request && channel) {
notifyList.emplace_back(property::CLIENT_TALK_REQUEST); retract_request = channel->talk_power_granted(permission_talk_power);
notifyList.emplace_back(property::CLIENT_TALK_REQUEST_MSG); }
if(retract_request) {
if(this->properties()[property::CLIENT_IS_TALKER].update_value(0)) {
updated_client_properties.emplace_back(property::CLIENT_IS_TALKER);
}
if(this->properties()[property::CLIENT_TALK_REQUEST].update_value(0)) {
updated_client_properties.emplace_back(property::CLIENT_TALK_REQUEST);
}
if(this->properties()[property::CLIENT_TALK_REQUEST_MSG].update_value("")) {
updated_client_properties.emplace_back(property::CLIENT_TALK_REQUEST_MSG);
}
} }
} }
} }
IconId iconId = 0; {
auto local_permissions = this->clientPermissions; IconId current_icon_id = this->properties()[property::CLIENT_ICON_ID].as_save<IconId>();
if(local_permissions) { IconId new_icon_id{permission_icon_id.has_value ? (IconId) permission_icon_id.value : 0};
permission::v2::PermissionFlaggedValue value{0, false}; if(this->properties()[property::CLIENT_ICON_ID].update_value(new_icon_id)) {
auto permission_flags = local_permissions->permission_flags(permission::i_icon_id); logTrace(this->getServerId(), "{} Updating client icon from {} to {}", CLIENT_STR_LOG_PREFIX, current_icon_id, new_icon_id);
if(permission_flags.channel_specific && this->currentChannel) { updated_client_properties.emplace_back(property::CLIENT_ICON_ID);
auto val = local_permissions->channel_permission(permission::i_icon_id, this->currentChannel->channelId());
value = {val.values.value, val.flags.value_set};
}
if(!value.has_value)
value = local_permissions->permission_value_flagged(permission::i_icon_id);
if(value.has_value)
iconId = value.value;
}
logTrace(this->getServerId(), "[CLIENT] Updating client icon from " + to_string(this->properties()[property::CLIENT_ICON_ID].as<IconId>()) + " to " + to_string(iconId));
if(this->properties()[property::CLIENT_ICON_ID].as<IconId>() != iconId) {
#if 0
if(server_ref && iconId != 0) {
auto dir = serverInstance->getFileServer()->iconDirectory(server_ref);
if(!serverInstance->getFileServer()->iconExists(server_ref, iconId)) {
logMessage(this->getServerId(), "[FILE] Missing client icon (" + to_string(iconId) + ").");
iconId = 0;
}
}
#endif
if(this->properties()[property::CLIENT_ICON_ID].as<IconId>() != iconId) {
this->properties()[property::CLIENT_ICON_ID] = (IconId) iconId;
notifyList.emplace_back(property::CLIENT_ICON_ID);
} }
} }
auto pSpeaker = this->clientPermissions ? this->clientPermissions->channel_permission(permission::b_client_is_priority_speaker, this->getChannelId()) : permission::v2::empty_channel_permission; auto pSpeakerGranted = permission::v2::permission_granted(1, permission_client_is_priority_speaker);
auto pSpeakerGranted = permission::v2::permission_granted(1, {pSpeaker.values.value, pSpeaker.flags.value_set}); if(properties()[property::CLIENT_IS_PRIORITY_SPEAKER].update_value(pSpeakerGranted)){
if(properties()[property::CLIENT_IS_PRIORITY_SPEAKER].as<bool>() != pSpeakerGranted){ updated_client_properties.emplace_back(property::CLIENT_IS_PRIORITY_SPEAKER);
properties()[property::CLIENT_IS_PRIORITY_SPEAKER] = pSpeakerGranted;
notifyList.emplace_back(property::CLIENT_IS_PRIORITY_SPEAKER);
} }
block_flood = !permission::v2::permission_granted(1, permission_ignore_antiflood); block_flood = !permission::v2::permission_granted(1, permission_ignore_antiflood);
if(server_ref) if(server_ref) {
server_ref->notifyClientPropertyUpdates(this->ref(), notifyList, notify_self); server_ref->notifyClientPropertyUpdates(this->ref(), updated_client_properties, notify_self);
this->updateTalkRights(permission_talk_power); }
if((this->channels_view_power != permission_channel_view_power || this->channels_ignore_view != permission_channel_ignore_view_power) && notify_self && this->currentChannel && server_ref) { this->updateTalkRights(permission_talk_power);
if((this->channels_view_power != permission_channel_view_power || this->channels_ignore_view != permission_channel_ignore_view_power) && notify_self && channel && server_ref) {
this->channels_view_power = permission_channel_view_power; this->channels_view_power = permission_channel_view_power;
this->channels_ignore_view = permission_channel_ignore_view_power; this->channels_ignore_view = permission_channel_ignore_view_power;
@ -207,9 +215,9 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
} }
/* might have been changed since we locked the tree */ /* might have been changed since we locked the tree */
if(this->currentChannel) { if(channel) {
deque<ChannelId> deleted; deque<ChannelId> deleted;
for(const auto& update_entry : this->channels->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(this->currentChannel->channelId()))) { for(const auto& update_entry : this->channels->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(channel->channelId()))) {
if(update_entry.first) { if(update_entry.first) {
this->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel); this->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
} else { } else {
@ -226,8 +234,10 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
void ConnectedClient::updateTalkRights(permission::v2::PermissionFlaggedValue talk_power) { void ConnectedClient::updateTalkRights(permission::v2::PermissionFlaggedValue talk_power) {
bool flag = false; bool flag = false;
flag |= this->properties()[property::CLIENT_IS_TALKER].as<bool>(); flag |= this->properties()[property::CLIENT_IS_TALKER].as<bool>();
if(!flag && this->currentChannel) {
flag = this->currentChannel->talk_power_granted(talk_power); auto current_channel = this->currentChannel;
if(!flag && current_channel) {
flag = current_channel->talk_power_granted(talk_power);
} }
this->allowedToTalk = flag; this->allowedToTalk = flag;
} }
@ -937,10 +947,11 @@ std::shared_ptr<BanRecord> ConnectedClient::resolveActiveBan(const std::string&
} }
bool ConnectedClient::update_client_needed_permissions() { bool ConnectedClient::update_client_needed_permissions() {
auto values = this->calculate_permissions(permission::neededPermissions, this->currentChannel? this->currentChannel->channelId() : 0); /* copy the channel here so it does not change */ /* The server and/or the channel might change while we're executing this method */
auto currentChannel = this->currentChannel;
auto values = this->calculate_permissions(permission::neededPermissions, currentChannel ? currentChannel->channelId() : 0);
auto updated = false; auto updated = false;
{ {
lock_guard cached_lock(this->client_needed_permissions_lock); lock_guard cached_lock(this->client_needed_permissions_lock);

View File

@ -263,7 +263,6 @@ namespace ts {
virtual bool ignoresFlood() { return !this->block_flood; } virtual bool ignoresFlood() { return !this->block_flood; }
std::shared_ptr<ConnectionInfoData> request_connection_info(const std::shared_ptr<ConnectedClient> & /* receiver */, bool& /* send temporary (no client response yet) */); std::shared_ptr<ConnectionInfoData> request_connection_info(const std::shared_ptr<ConnectedClient> & /* receiver */, bool& /* send temporary (no client response yet) */);
virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */);
void updateTalkRights(permission::v2::PermissionFlaggedValue talk_power); void updateTalkRights(permission::v2::PermissionFlaggedValue talk_power);
virtual std::shared_ptr<BanRecord> resolveActiveBan(const std::string& ip_address); virtual std::shared_ptr<BanRecord> resolveActiveBan(const std::string& ip_address);
@ -283,9 +282,20 @@ namespace ts {
[[nodiscard]] inline std::vector<GroupId>& current_server_groups() { return this->cached_server_groups; } [[nodiscard]] inline std::vector<GroupId>& current_server_groups() { return this->cached_server_groups; }
[[nodiscard]] inline GroupId& current_channel_group() { return this->cached_channel_group; } [[nodiscard]] inline GroupId& current_channel_group() { return this->cached_channel_group; }
/**
* Attention: This method should never be called directly (except in some edge cases)!
* Use `task_update_channel_client_properties` instead to schedule an update.
*/
virtual void updateChannelClientProperties(bool /* lock channel tree */, bool /* notify our self */);
/* /*
* permission stuff * permission stuff
*/ */
/**
* Attention: This method should never be called directly!
* Use `task_update_needed_permissions` instead to schedule an update.
* @returns `true` is a permission updated happened.
*/
bool update_client_needed_permissions(); bool update_client_needed_permissions();
std::shared_lock<std::shared_mutex> require_connected_state(bool blocking = false) { std::shared_lock<std::shared_mutex> require_connected_state(bool blocking = false) {
@ -383,6 +393,7 @@ namespace ts {
std::weak_ptr<ts::music::Playlist> subscribed_playlist_{}; std::weak_ptr<ts::music::Playlist> subscribed_playlist_{};
multi_shot_task task_update_needed_permissions{}; multi_shot_task task_update_needed_permissions{};
multi_shot_task task_update_channel_client_properties{};
bool loadDataForCurrentServer() override; bool loadDataForCurrentServer() override;

View File

@ -36,18 +36,18 @@ do { \
return true; \ return true; \
} while(false) } while(false)
#define TLEN(index) if(arguments.size() < index) ERR(serverInstance->musicRoot(), "Invalid argument count"); #define TLEN(index) if(arguments.size() < index) ERR(music_root, "Invalid argument count");
#define TARG(index, type) (arguments.size() > index && arguments[index] == type) #define TARG(index, type) (arguments.size() > index && arguments[index] == type)
#define TMUSIC(bot) if(!bot->current_player()) ERR(serverInstance->musicRoot(), "Im not playing a song!"); #define TMUSIC(bot) if(!bot->current_player()) ERR(music_root, "Im not playing a song!");
#define GBOT(var, ignore_disabled) \ #define GBOT(var, ignore_disabled) \
auto var = this->selectedBot.lock(); \ auto var = this->selectedBot.lock(); \
if(!var) var = dynamic_pointer_cast<MusicClient>(target); \ if(!var) var = dynamic_pointer_cast<MusicClient>(target); \
if(!var) { \ if(!var) { \
send_message(serverInstance->musicRoot(), "Please select a music bot! (" + ts::config::music::command_prefix + "mbot select <id>)"); \ send_message(music_root, "Please select a music bot! (" + ts::config::music::command_prefix + "mbot select <id>)"); \
return true; \ return true; \
} \ } \
if(!ignore_disabled && var->properties()[property::CLIENT_DISABLED].as<bool>()) { \ if(!ignore_disabled && var->properties()[property::CLIENT_DISABLED].as<bool>()) { \
send_message(serverInstance->musicRoot(), strobf("This bot has been disabled. Upgrade your TeaSpeak license to use more bots.").string()); \ send_message(music_root, strobf("This bot has been disabled. Upgrade your TeaSpeak license to use more bots.").string()); \
return true; \ return true; \
} }
@ -100,20 +100,20 @@ bool ConnectedClient::handleTextMessage(ChatMessageMode mode, std::string text,
#define PERM_CHECK_BOT(perm, reqperm, err) \ #define PERM_CHECK_BOT(perm, reqperm, err) \
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && \ if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && \
!permission::v2::permission_granted(bot->calculate_permission(permission::reqperm, bot->getChannelId()), this->calculate_permission(permission::perm, bot->getChannelId()))) { \ !permission::v2::permission_granted(bot->calculate_permission(permission::reqperm, bot->getChannelId()), this->calculate_permission(permission::perm, bot->getChannelId()))) { \
send_message(serverInstance->musicRoot(), err); \ send_message(music_root, err); \
return true; \ return true; \
} }
//TODO: Correct error message print! //TODO: Correct error message print!
#define HANDLE_CMD_ERROR(_message) \ #define HANDLE_CMD_ERROR(_message) \
send_message(serverInstance->musicRoot(), string(_message) + ": action failed"); send_message(music_root, string(_message) + ": action failed");
/* /*
if(result.extraProperties.count("extra_msg") > 0) \ if(result.extraProperties.count("extra_msg") > 0) \
send_message(serverInstance->musicRoot(), string(_message) + ": " + result.extraProperties["extra_msg"]); \ send_message(music_root, string(_message) + ": " + result.extraProperties["extra_msg"]); \
else if(result.extraProperties.count("failed_permid") > 0) \ else if(result.extraProperties.count("failed_permid") > 0) \
send_message(serverInstance->musicRoot(), string(_message) + ". (Missing permission " + permission::resolvePermissionData((permission::PermissionType) stoull(result.extraProperties["failed_permid"]))->name + ")"); \ send_message(music_root, string(_message) + ". (Missing permission " + permission::resolvePermissionData((permission::PermissionType) stoull(result.extraProperties["failed_permid"]))->name + ")"); \
else \ else \
send_message(serverInstance->musicRoot(), string(_message) + ": " + result.error.message); send_message(music_root, string(_message) + ": " + result.error.message);
*/ */
#define JOIN_ARGS(variable, index) \ #define JOIN_ARGS(variable, index) \
@ -150,9 +150,10 @@ bool ConnectedClient::handle_text_command(
const function<void(const shared_ptr<ConnectedClient> &, const string &)> &send_message, const function<void(const shared_ptr<ConnectedClient> &, const string &)> &send_message,
const shared_ptr<ConnectedClient>& target) { const shared_ptr<ConnectedClient>& target) {
auto music_root = dynamic_pointer_cast<ConnectedClient>(serverInstance->musicRoot());
if (command == "mbot") { if (command == "mbot") {
if(!config::music::enabled) { if(!config::music::enabled) {
send_message(serverInstance->musicRoot(), "Music bots are not enabled! Enable them via the server config!"); send_message(music_root, "Music bots are not enabled! Enable them via the server config!");
return true; return true;
} }
if (TARG(0, "create")) { if (TARG(0, "create")) {
@ -163,7 +164,7 @@ bool ConnectedClient::handle_text_command(
HANDLE_CMD_ERROR("Failed to create music bot"); HANDLE_CMD_ERROR("Failed to create music bot");
return true; return true;
} }
send_message(serverInstance->musicRoot(), "Bot created"); send_message(music_root, "Bot created");
return true; return true;
} else if (TARG(0, "list")) { } else if (TARG(0, "list")) {
bool server = false; bool server = false;
@ -172,19 +173,19 @@ bool ConnectedClient::handle_text_command(
string locationStr = server ? "on this server" : "in this channel"; string locationStr = server ? "on this server" : "in this channel";
if(!permission::v2::permission_granted(1, this->calculate_permission(server ? permission::b_client_music_server_list : permission::b_client_music_channel_list, this->getChannelId()))) { if(!permission::v2::permission_granted(1, this->calculate_permission(server ? permission::b_client_music_server_list : permission::b_client_music_channel_list, this->getChannelId()))) {
send_message(serverInstance->musicRoot(), "You don't have the permission to list all music bots " + locationStr); send_message(music_root, "You don't have the permission to list all music bots " + locationStr);
return true; return true;
} }
auto mbots = this->server->getClientsByChannel<MusicClient>(server ? nullptr : this->currentChannel); auto mbots = this->server->getClientsByChannel<MusicClient>(server ? nullptr : this->currentChannel);
if (mbots.empty()) if (mbots.empty())
send_message(serverInstance->musicRoot(), "There are no music bots " + locationStr); send_message(music_root, "There are no music bots " + locationStr);
else { else {
send_message(serverInstance->musicRoot(), "There are " + to_string(mbots.size()) + " music bots " + locationStr + ":"); send_message(music_root, "There are " + to_string(mbots.size()) + " music bots " + locationStr + ":");
for (const auto &mbot : mbots) { for (const auto &mbot : mbots) {
if(mbot->properties()[property::CLIENT_DISABLED].as<bool>()) { if(mbot->properties()[property::CLIENT_DISABLED].as<bool>()) {
send_message(serverInstance->musicRoot(), " - [color=red]" + to_string(mbot->getClientDatabaseId()) + " | " + mbot->getDisplayName() + " [DISABLED][/color]"); send_message(music_root, " - [color=red]" + to_string(mbot->getClientDatabaseId()) + " | " + mbot->getDisplayName() + " [DISABLED][/color]");
} else { } else {
send_message(serverInstance->musicRoot(), " - [color=green]" + to_string(mbot->getClientDatabaseId()) + " | " + mbot->getDisplayName() + "[/color]"); send_message(music_root, " - [color=green]" + to_string(mbot->getClientDatabaseId()) + " | " + mbot->getDisplayName() + "[/color]");
} }
} }
} }
@ -192,21 +193,21 @@ bool ConnectedClient::handle_text_command(
} else if (TARG(0, "select")) { } else if (TARG(0, "select")) {
TLEN(2); TLEN(2);
if(arguments[1].find_first_not_of("0123456789") != std::string::npos) { if(arguments[1].find_first_not_of("0123456789") != std::string::npos) {
send_message(serverInstance->musicRoot(), "Invalid bot id"); send_message(music_root, "Invalid bot id");
return true; return true;
} }
auto botId = static_cast<ClientDbId>(stoll(arguments[1])); auto botId = static_cast<ClientDbId>(stoll(arguments[1]));
auto bot = this->server->music_manager_->findBotById(botId); auto bot = this->server->music_manager_->findBotById(botId);
if (!bot) ERR(serverInstance->musicRoot(), "Could not find target bot"); if (!bot) ERR(music_root, "Could not find target bot");
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() &&
!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_channel_list, this->getChannelId())) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_channel_list, this->getChannelId())) &&
!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_server_list, this->getChannelId()))) { //No perms for listing !permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_server_list, this->getChannelId()))) { //No perms for listing
send_message(serverInstance->musicRoot(), "You don't have the permission to select a music bot"); send_message(music_root, "You don't have the permission to select a music bot");
return true; return true;
} }
this->selectedBot = bot; this->selectedBot = bot;
send_message(serverInstance->musicRoot(), "You successfully select the bot " + to_string(botId) + " | " + bot->getDisplayName()); send_message(music_root, "You successfully select the bot " + to_string(botId) + " | " + bot->getDisplayName());
return true; return true;
} else if (TARG(0, "rename")) { } else if (TARG(0, "rename")) {
TLEN(2); TLEN(2);
@ -225,7 +226,7 @@ bool ConnectedClient::handle_text_command(
result.release_data(); result.release_data();
return true; return true;
} }
send_message(serverInstance->musicRoot(), "Name successfully changed!"); send_message(music_root, "Name successfully changed!");
return true; return true;
} else if (TARG(0, "delete")) { } else if (TARG(0, "delete")) {
GBOT(bot, true); GBOT(bot, true);
@ -460,7 +461,7 @@ bool ConnectedClient::handle_text_command(
for(const auto& fmt : prots) for(const auto& fmt : prots)
ss << " - " << fmt << endl; ss << " - " << fmt << endl;
} }
send_message(serverInstance->musicRoot(), ss.str()); send_message(music_root, ss.str());
return true; return true;
} else if(TARG(0, "settings")) { } else if(TARG(0, "settings")) {
GBOT(bot, false); GBOT(bot, false);
@ -513,7 +514,7 @@ bool ConnectedClient::handle_text_command(
result.release_data(); result.release_data();
return true; return true;
} }
send_message(serverInstance->musicRoot(), "Property successfully changed!"); send_message(music_root, "Property successfully changed!");
return true; return true;
} }
@ -566,7 +567,7 @@ bool ConnectedClient::handle_text_command(
return true; return true;
} }
} else if (command == "help") { } else if (command == "help") {
//send_message(serverInstance->musicRoot(), " ̶.̶̶m̶̶b̶̶o̶̶t̶̶ ̶̶f̶̶o̶̶r̶̶m̶̶a̶̶t̶̶s (Not supported yet)"); //send_message(music_root, " ̶.̶̶m̶̶b̶̶o̶̶t̶̶ ̶̶f̶̶o̶̶r̶̶m̶̶a̶̶t̶̶s (Not supported yet)");
stringstream ss; stringstream ss;
ss << "Available music bot commands: ([color=green]green[/color] = permission granted | [color=red]red[/color] = insufficient permissions)" << endl; ss << "Available music bot commands: ([color=green]green[/color] = permission granted | [color=red]red[/color] = insufficient permissions)" << endl;
@ -597,7 +598,7 @@ bool ConnectedClient::handle_text_command(
permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot <playlist|pl>", permission::i_client_music_play_power); permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot <playlist|pl>", permission::i_client_music_play_power);
permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot settings <playlist|bot> [name] [value]", permission::i_client_music_modify_power); permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot settings <playlist|bot> [name] [value]", permission::i_client_music_modify_power);
send_message(serverInstance->musicRoot(), ss.str()); send_message(music_root, ss.str());
return true; return true;
} else if (command == "dummy") { } else if (command == "dummy") {
if(TARG(0, "timerevent")) { if(TARG(0, "timerevent")) {
@ -772,8 +773,8 @@ bool ConnectedClient::handle_text_command(
} }
} }
send_message(serverInstance->musicRoot(), "Invalid channel command."); send_message(music_root, "Invalid channel command.");
send_message(serverInstance->musicRoot(), "Type " + ts::config::music::command_prefix + "help for a command overview"); send_message(music_root, "Type " + ts::config::music::command_prefix + "help for a command overview");
return false; return false;
} }

View File

@ -39,8 +39,9 @@ constexpr static std::string_view kClientLoadCommand{R"(
bool DataClient::loadDataForCurrentServer() { bool DataClient::loadDataForCurrentServer() {
auto uniqueId = this->getUid(); auto uniqueId = this->getUid();
if(uniqueId.empty()) if(uniqueId.empty()) {
return false; return false;
}
auto ref_server = this->server; auto ref_server = this->server;
auto server_id = ref_server ? ref_server->getServerId() : 0; auto server_id = ref_server ? ref_server->getServerId() : 0;
@ -100,8 +101,9 @@ bool DataClient::loadDataForCurrentServer() {
} }
if(!ref_server) { if(!ref_server) {
if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK) if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK) {
logCritical(LOG_INSTANCE, "Got a voice or web client, which is unbound to any server!"); logCritical(LOG_INSTANCE, "Got a voice or web client, which is unbound to any server!");
}
return false; return false;
} }
@ -129,8 +131,9 @@ bool DataClient::loadDataForCurrentServer() {
} }
#endif #endif
if(ref_server) if(ref_server) {
this->properties()[property::CLIENT_UNREAD_MESSAGES] = ref_server->letters->unread_letter_count(this->getUid()); this->properties()[property::CLIENT_UNREAD_MESSAGES] = ref_server->letters->unread_letter_count(this->getUid());
}
return true; return true;
} }
@ -140,20 +143,30 @@ std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlag
ChannelId channel, ChannelId channel,
bool granted, bool granted,
std::shared_ptr<CalculateCache> cache) { std::shared_ptr<CalculateCache> cache) {
if(permissions.empty()) return {}; if(permissions.empty()) {
return {};
}
if(!cache) if(!cache) {
cache = std::make_shared<CalculateCache>(); cache = std::make_shared<CalculateCache>();
if(!cache->client_permissions) /* so we don't have to load that shit later */ }
if(!cache->client_permissions) {
/* so we don't have to load that shit later */
cache->client_permissions = this->clientPermissions; cache->client_permissions = this->clientPermissions;
if(channel == -1) }
channel = this->currentChannel ? this->currentChannel->channelId() : 0;
if(channel == -1) {
auto current_channel = this->currentChannel;
channel = current_channel ? current_channel->channelId() : 0;
}
auto ref_server = this->server; auto ref_server = this->server;
if(ref_server) if(ref_server) {
return ref_server->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache); return ref_server->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
else } else {
return serverInstance->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache); return serverInstance->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
}
} }
permission::v2::PermissionFlaggedValue DataClient::calculate_permission( permission::v2::PermissionFlaggedValue DataClient::calculate_permission(

View File

@ -65,6 +65,14 @@ namespace ts {
PropertyWrapper properties(){ return { this->_properties }; } PropertyWrapper properties(){ return { this->_properties }; }
/* main permission calculate function */ /* main permission calculate function */
/**
* Calculate the given permissions.
* This method can be called from everywhere without any locking needed.
* @param channel
* @param granted
* @param cache
* @return
*/
permission::v2::PermissionFlaggedValue calculate_permission( permission::v2::PermissionFlaggedValue calculate_permission(
permission::PermissionType, permission::PermissionType,
ChannelId channel, ChannelId channel,
@ -72,6 +80,14 @@ namespace ts {
std::shared_ptr<CalculateCache> cache = nullptr std::shared_ptr<CalculateCache> cache = nullptr
); );
/**
* Calculate the given permissions.
* This method can be called from everywhere without any locking needed.
* @param channel
* @param granted
* @param cache
* @return
*/
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions( std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&, const std::deque<permission::PermissionType>&,
ChannelId channel, ChannelId channel,

View File

@ -412,8 +412,7 @@ command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) {
if (this->server) { if (this->server) {
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) { this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
if (this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) { if (this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) {
if (cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
} }
cl->notifyChannelGroupList(); cl->notifyChannelGroupList();
}); });
@ -559,15 +558,12 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) { this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */ unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */
if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) { if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) {
if (cl->update_client_needed_permissions()) { cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* update the needed permissions */
}
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }
client_channel_lock.unlock(); client_channel_lock.unlock();
/* Must be outside of the lock since updateChannelClientProperties may causes client talk power updates */ cl->task_update_channel_client_properties.enqueue();
cl->updateChannelClientProperties(true, true);
}); });
} }
@ -609,14 +605,12 @@ command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) { this->server->forEachClient([channelGroup](shared_ptr<ConnectedClient> cl) {
unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */ unique_lock client_channel_lock(cl->channel_lock); /* while we're updating groups we dont want to change anything! */
if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) { if (cl->channelGroupAssigned(channelGroup, cl->getChannel())) {
if (cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }
client_channel_lock.unlock(); client_channel_lock.unlock();
/* Must be outside of the lock since updateChannelClientProperties may causes client talk power updates */ cl->task_update_channel_client_properties.enqueue();
cl->updateChannelClientProperties(true, true);
}); });
} }
@ -1796,7 +1790,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
/* we've to change the permission as well */ /* we've to change the permission as well */
auto talk_power = converter<permission::PermissionValue>::from_string_view(value); auto talk_power = converter<permission::PermissionValue>::from_string_view(value);
channel->permissions()->set_permission(permission::i_client_talk_power, channel->permissions()->set_permission(permission::i_client_needed_talk_power,
{ talk_power, talk_power }, { talk_power, talk_power },
permission::v2::PermissionUpdateType::set_value, permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::do_nothing,
@ -1923,11 +1917,11 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
} }
if(updating_talk_power) { if(updating_talk_power) {
client->updateChannelClientProperties(false, true); client->task_update_channel_client_properties.enqueue();
} }
} }
/* Channel create was successfull. Release delete struct. */ /* Channel create was successful. Release delete struct. */
temporary_created_channel.channel = nullptr; temporary_created_channel.channel = nullptr;
return command_result{error::ok}; return command_result{error::ok};
}; };
@ -2170,7 +2164,9 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
continue; continue;
} }
return ts::command_result{error::channel_default_require_visible}; if(ppermission.permission()->type == permission::i_channel_needed_view_power) {
return ts::command_result{error::channel_default_require_visible};
}
} }
} }
@ -2198,7 +2194,7 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
if ((updateClients || update_join_permissions) && this->server) { if ((updateClients || update_join_permissions) && this->server) {
this->server->forEachClient([&](std::shared_ptr<ConnectedClient> cl) { this->server->forEachClient([&](std::shared_ptr<ConnectedClient> cl) {
if (updateClients && cl->currentChannel == channel) { if (updateClients && cl->currentChannel == channel) {
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
} }
if (update_join_permissions) { if (update_join_permissions) {
@ -2247,7 +2243,7 @@ command_result ConnectedClient::handleCommandChannelDelPerm(Command &cmd) {
if ((updateClients || update_join_permissions) && this->server) { if ((updateClients || update_join_permissions) && this->server) {
this->server->forEachClient([&](std::shared_ptr<ConnectedClient> cl) { this->server->forEachClient([&](std::shared_ptr<ConnectedClient> cl) {
if (updateClients && cl->currentChannel == channel) if (updateClients && cl->currentChannel == channel)
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
if (update_join_permissions) if (update_join_permissions)
cl->join_state_id++; cl->join_state_id++;
}); });
@ -2354,11 +2350,10 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd)
auto onlineClients = this->server->findClientsByCldbId(cldbid); auto onlineClients = this->server->findClientsByCldbId(cldbid);
if (!onlineClients.empty()) { if (!onlineClients.empty()) {
for (const auto &elm : onlineClients) { for (const auto &elm : onlineClients) {
if (elm->update_client_needed_permissions()) /* update cached calculated permissions */ elm->task_update_needed_permissions.enqueue();
elm->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if (elm->currentChannel == channel) { if (elm->currentChannel == channel) {
elm->updateChannelClientProperties(true, true); elm->task_update_channel_client_properties.enqueue();
} else if (update_view) { } else if (update_view) {
unique_lock client_channel_lock(this->channel_lock); unique_lock client_channel_lock(this->channel_lock);
@ -2423,11 +2418,10 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
auto onlineClients = this->server->findClientsByCldbId(cldbid); auto onlineClients = this->server->findClientsByCldbId(cldbid);
if (!onlineClients.empty()) if (!onlineClients.empty())
for (const auto &elm : onlineClients) { for (const auto &elm : onlineClients) {
if (elm->update_client_needed_permissions()) /* update cached calculated permissions */ elm->task_update_needed_permissions.enqueue();
elm->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if (elm->currentChannel == channel) { if (elm->currentChannel == channel) {
elm->updateChannelClientProperties(true, true); elm->task_update_channel_client_properties.enqueue();
} else if (update_view) { } else if (update_view) {
unique_lock client_channel_lock(this->channel_lock); unique_lock client_channel_lock(this->channel_lock);

View File

@ -976,10 +976,9 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) {
auto onlineClients = this->server->findClientsByCldbId(cldbid); auto onlineClients = this->server->findClientsByCldbId(cldbid);
if (!onlineClients.empty()) if (!onlineClients.empty())
for (const auto &elm : onlineClients) { for (const auto &elm : onlineClients) {
if(elm->update_client_needed_permissions()) /* update cached calculated permissions */ elm->task_update_needed_permissions.enqueue();
elm->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if(update_channels) if(update_channels)
elm->updateChannelClientProperties(true, true); elm->task_update_channel_client_properties.enqueue();
elm->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ elm->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }
@ -1019,10 +1018,9 @@ command_result ConnectedClient::handleCommandClientDelPerm(Command &cmd) {
auto onlineClients = this->server->findClientsByCldbId(cldbid); auto onlineClients = this->server->findClientsByCldbId(cldbid);
if (!onlineClients.empty()) if (!onlineClients.empty())
for (const auto &elm : onlineClients) { for (const auto &elm : onlineClients) {
if(elm->update_client_needed_permissions()) /* update cached calculated permissions */ elm->task_update_needed_permissions.enqueue();
elm->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if(update_channels) if(update_channels)
elm->updateChannelClientProperties(true, true); elm->task_update_channel_client_properties.enqueue();
elm->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ elm->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }

View File

@ -506,8 +506,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
shared_lock client_channel_lock_r(targetClient->channel_lock); shared_lock client_channel_lock_r(targetClient->channel_lock);
auto result = this->server->notifyClientPropertyUpdates(targetClient, updates); auto result = this->server->notifyClientPropertyUpdates(targetClient, updates);
if (result) { if (result) {
if(targetClient->update_client_needed_permissions()) /* update cached calculated permissions */ targetClient->task_update_needed_permissions.enqueue();
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if(targetClient->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID] == channel->channelId()) { //Only if group assigned over the channel if(targetClient->properties()[property::CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID] == channel->channelId()) { //Only if group assigned over the channel
for (const auto &viewer : this->server->getClients()) { for (const auto &viewer : this->server->getClients()) {
@ -519,7 +518,8 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
} }
} }
} }
targetClient->updateChannelClientProperties(false, true);
targetClient->task_update_channel_client_properties.enqueue();
} }
if(old_group) { if(old_group) {
@ -1103,8 +1103,7 @@ command_result ConnectedClient::handleCommandTokenUse(Command &cmd) {
} }
if (this->server->notifyClientPropertyUpdates(this->ref(), this->server->groups->update_server_group_property(this->ref(), true, this->getChannel()))) { if (this->server->notifyClientPropertyUpdates(this->ref(), this->server->groups->update_server_group_property(this->ref(), true, this->getChannel()))) {
if(this->update_client_needed_permissions()) /* update cached calculated permissions */ this->task_update_needed_permissions.enqueue();
this->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
{ {
for (auto &viewer : this->server->getClients()) { for (auto &viewer : this->server->getClients()) {

View File

@ -238,8 +238,7 @@ command_result ConnectedClient::handleCommandServerEdit(Command &cmd) {
if (group_update) if (group_update)
target_server->forEachClient([&](const shared_ptr<ConnectedClient>& client) { target_server->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
if(target_server->notifyClientPropertyUpdates(client, target_server->groups->update_server_group_property(client, true, client->getChannel()))) { if(target_server->notifyClientPropertyUpdates(client, target_server->groups->update_server_group_property(client, true, client->getChannel()))) {
if(client->update_client_needed_permissions()) /* update cached calculated permissions */ client->task_update_needed_permissions.enqueue();
client->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
} }
}); });
@ -579,8 +578,7 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) {
if(this->server) if(this->server)
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) { this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) { if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) {
if(cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
} }
cl->notifyServerGroupList(); cl->notifyServerGroupList();
}); });
@ -729,9 +727,8 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
for(const auto& group : applied_groups) for(const auto& group : applied_groups)
client->notifyServerGroupClientAdd(this->ref(), targetClient, group); client->notifyServerGroupClientAdd(this->ref(), targetClient, group);
} }
if(targetClient->update_client_needed_permissions()) /* update cached calculated permissions */ targetClient->task_update_needed_permissions.enqueue();
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ targetClient->task_update_channel_client_properties.enqueue();
targetClient->updateChannelClientProperties(true, true);
} }
} }
} }
@ -868,9 +865,8 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
for(const auto& group : applied_groups) for(const auto& group : applied_groups)
client->notifyServerGroupClientRemove(this->ref(), targetClient, group); client->notifyServerGroupClientRemove(this->ref(), targetClient, group);
} }
if(targetClient->update_client_needed_permissions()) /* update cached calculated permissions */ targetClient->task_update_needed_permissions.enqueue();
targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ targetClient->task_update_channel_client_properties.enqueue();
targetClient->updateChannelClientProperties(true, true);
} }
} }
} }
@ -954,10 +950,9 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
}); });
server->forEachClient([serverGroup, update_talk_power](shared_ptr<ConnectedClient> cl) { server->forEachClient([serverGroup, update_talk_power](shared_ptr<ConnectedClient> cl) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if (update_talk_power) if (update_talk_power)
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }
}); });
@ -1019,10 +1014,9 @@ command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) {
server->forEachClient([serverGroup, update_talk_power](shared_ptr<ConnectedClient> cl) { server->forEachClient([serverGroup, update_talk_power](shared_ptr<ConnectedClient> cl) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if (update_talk_power) if (update_talk_power)
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
} }
}); });
@ -1095,11 +1089,9 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
ref_server->forEachClient([groups, update_clients](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([groups, update_clients](shared_ptr<ConnectedClient> cl) {
for(const auto& serverGroup : groups) { for(const auto& serverGroup : groups) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_client_needed_permissions()) {/* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
}
if (update_clients) { if (update_clients) {
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
} }
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate if needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate if needed */
break; break;
@ -1175,10 +1167,9 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
ref_server->forEachClient([groups, update_clients](shared_ptr<ConnectedClient> cl) { ref_server->forEachClient([groups, update_clients](shared_ptr<ConnectedClient> cl) {
for(const auto& serverGroup : groups) { for(const auto& serverGroup : groups) {
if (cl->serverGroupAssigned(serverGroup)) { if (cl->serverGroupAssigned(serverGroup)) {
if(cl->update_client_needed_permissions()) /* update cached calculated permissions */ cl->task_update_needed_permissions.enqueue();
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
if (update_clients) if (update_clients)
cl->updateChannelClientProperties(true, true); cl->task_update_channel_client_properties.enqueue();
cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */
break; break;
} }

View File

@ -154,7 +154,7 @@ void QueryClient::postInitialize() {
} }
} }
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
} }
void QueryClient::send_message(const std::string_view& message) { void QueryClient::send_message(const std::string_view& message) {

View File

@ -286,17 +286,18 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
unique_lock tree_lock(this->server->channel_tree_lock); unique_lock tree_lock(this->server->channel_tree_lock);
if(joined_channel) if(joined_channel)
this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) } else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
this->server->assignDefaultChannel(this->ref(), true); this->server->assignDefaultChannel(this->ref(), true);
else } else {
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
}
} else { } else {
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
} }
this->properties()[property::CLIENT_TOTALCONNECTIONS]++; this->properties()[property::CLIENT_TOTALCONNECTIONS]++;
this->updateChannelClientProperties(true, true); this->task_update_channel_client_properties.enqueue();
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), username, log::QueryAuthenticateResult::SUCCESS); serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), username, log::QueryAuthenticateResult::SUCCESS);
return command_result{error::ok}; return command_result{error::ok};
@ -342,14 +343,14 @@ command_result QueryClient::handleCommandLogout(Command &) {
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) { } else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
this->server->assignDefaultChannel(this->ref(), true); this->server->assignDefaultChannel(this->ref(), true);
} else { } else {
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
} }
} else { } else {
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
} }
this->updateChannelClientProperties(true, true); this->task_update_channel_client_properties.enqueue();
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), "", log::QueryAuthenticateResult::SUCCESS); serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), "", log::QueryAuthenticateResult::SUCCESS);
return command_result{error::ok}; return command_result{error::ok};
@ -412,15 +413,17 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
} }
auto negated_enforce_join = permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1)); auto negated_enforce_join = permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1));
if(!negated_enforce_join) if(!negated_enforce_join) {
this->server->assignDefaultChannel(this->ref(), true); this->server->assignDefaultChannel(this->ref(), true);
else } else {
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
}
} else { } else {
serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId()); serverInstance->getGroupManager()->enableCache(this->getClientDatabaseId());
this->update_client_needed_permissions(); this->task_update_needed_permissions.enqueue();
} }
this->updateChannelClientProperties(true, true);
this->task_update_channel_client_properties.enqueue();
serverInstance->action_logger()->query_logger.log_query_switch(std::dynamic_pointer_cast<QueryClient>(this->ref()), this->properties()[property::CLIENT_LOGIN_NAME].value(), old_server_id, this->getServerId()); serverInstance->action_logger()->query_logger.log_query_switch(std::dynamic_pointer_cast<QueryClient>(this->ref()), this->properties()[property::CLIENT_LOGIN_NAME].value(), old_server_id, this->getServerId());
return command_result{error::ok}; return command_result{error::ok};
} }

2
shared

@ -1 +1 @@
Subproject commit 84a08c469b5fada3b4e0c9a63fcfa19d8c7b10dd Subproject commit 6e99fc1ab4934d1494c49bab83f47196deb6ad69