Fixed the query client view power
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include <cstring>
|
||||
#include <protocol/buffers.h>
|
||||
#include "./PermissionCalculator.h"
|
||||
#include "client/voice/VoiceClient.h"
|
||||
#include "client/InternalClient.h"
|
||||
#include "VirtualServer.h"
|
||||
@@ -111,17 +112,35 @@ bool VirtualServer::unregisterClient(shared_ptr<ConnectedClient> cl, std::string
|
||||
}
|
||||
}
|
||||
|
||||
if(cl->getType() == ClientType::CLIENT_TEAMSPEAK || cl->getType() == ClientType::CLIENT_WEB)
|
||||
this->properties()[property::VIRTUALSERVER_LAST_CLIENT_DISCONNECT] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
||||
else if(cl->getType() == ClientType::CLIENT_QUERY)
|
||||
this->properties()[property::VIRTUALSERVER_LAST_QUERY_DISCONNECT] = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
||||
auto current_time_seconds = std::chrono::duration_cast<seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
switch(cl->getType()) {
|
||||
case ClientType::CLIENT_TEAMSPEAK:
|
||||
case ClientType::CLIENT_TEASPEAK:
|
||||
case ClientType::CLIENT_WEB:
|
||||
this->properties()[property::VIRTUALSERVER_LAST_CLIENT_DISCONNECT] = current_time_seconds;
|
||||
break;
|
||||
|
||||
case ClientType::CLIENT_QUERY:
|
||||
this->properties()[property::VIRTUALSERVER_LAST_QUERY_DISCONNECT] = current_time_seconds;
|
||||
break;
|
||||
|
||||
|
||||
case ClientType::CLIENT_MUSIC:
|
||||
case ClientType::CLIENT_INTERNAL:
|
||||
case ClientType::MAX:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
if(!chan_tree_lock.owns_lock())
|
||||
if(!chan_tree_lock.owns_lock()) {
|
||||
chan_tree_lock.lock();
|
||||
}
|
||||
|
||||
if(cl->currentChannel) //We dont have to make him invisible if he hasnt even a channel
|
||||
if(cl->currentChannel) {
|
||||
//We dont have to make him invisible if he hasnt even a channel
|
||||
this->client_move(cl, nullptr, nullptr, reason, ViewReasonId::VREASON_SERVER_LEFT, false, chan_tree_lock);
|
||||
}
|
||||
}
|
||||
|
||||
serverInstance->databaseHelper()->saveClientPermissions(this->ref(), cl->getClientDatabaseId(), cl->clientPermissions);
|
||||
@@ -175,9 +194,9 @@ void VirtualServer::unregisterInternalClient(std::shared_ptr<ConnectedClient> cl
|
||||
}
|
||||
|
||||
bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& client, bool join) {
|
||||
std::shared_lock server_channel_lock{this->channel_tree_mutex};
|
||||
std::shared_ptr<BasicChannel> channel{};
|
||||
|
||||
std::unique_lock server_channel_lock{this->channel_tree_mutex};
|
||||
auto requested_channel_path = client->properties()[property::CLIENT_DEFAULT_CHANNEL].value();
|
||||
if(!requested_channel_path.empty()) {
|
||||
if (requested_channel_path[0] == '/' && requested_channel_path.find_first_not_of("0123456789", 1) == std::string::npos) {
|
||||
@@ -244,12 +263,11 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
|
||||
|
||||
debugMessage(this->getServerId(), "{} Using channel {} as default client channel.", client->getLoggingPrefix(), channel->channelId());
|
||||
if(join) {
|
||||
server_channel_lock.unlock();
|
||||
unique_lock server_channel_w_lock(this->channel_tree_mutex);
|
||||
this->client_move(client, channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
|
||||
this->client_move(client, channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_lock);
|
||||
} else {
|
||||
client->currentChannel = channel;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -412,10 +430,10 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
||||
/*
|
||||
* This method had previously owned the clients command lock but that's not really needed.
|
||||
* Everything which is related to the server channel tree or the client channel tree should be locked with
|
||||
* the appropiate mutexes.
|
||||
* the appropriate mutexes.
|
||||
*/
|
||||
void VirtualServer::client_move(
|
||||
const shared_ptr<ts::server::ConnectedClient> &target,
|
||||
const shared_ptr<ts::server::ConnectedClient> &target_client,
|
||||
shared_ptr<ts::BasicChannel> target_channel,
|
||||
const std::shared_ptr<ts::server::ConnectedClient> &invoker,
|
||||
const std::string &reason_message,
|
||||
@@ -427,15 +445,16 @@ void VirtualServer::client_move(
|
||||
if(!server_channel_write_lock.owns_lock()) {
|
||||
server_channel_write_lock.unlock();
|
||||
}
|
||||
|
||||
TIMING_STEP(timings, "chan tree l");
|
||||
if(target->currentChannel == target_channel) {
|
||||
if(target_client->currentChannel == target_channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* first step: verify thew source and target channel */
|
||||
auto s_target_channel = dynamic_pointer_cast<ServerChannel>(target_channel);
|
||||
auto s_source_channel = dynamic_pointer_cast<ServerChannel>(target->currentChannel);
|
||||
assert(!target->currentChannel || s_source_channel != nullptr);
|
||||
auto s_source_channel = dynamic_pointer_cast<ServerChannel>(target_client->currentChannel);
|
||||
assert(!target_client->currentChannel || s_source_channel != nullptr);
|
||||
|
||||
std::deque<property::ClientProperties> updated_client_properties{};
|
||||
if(target_channel) {
|
||||
@@ -449,147 +468,157 @@ void VirtualServer::client_move(
|
||||
auto l_source_channel = s_source_channel ? this->channelTree->findLinkedChannel(s_source_channel->channelId()) : nullptr;
|
||||
TIMING_STEP(timings, "channel res");
|
||||
|
||||
/* second step: show the target channel to the client if its not shown and let him subscibe to the channel */
|
||||
/* second step: show the target channel to the client if its not shown and let him subscribe to the channel */
|
||||
if(target_channel && notify_client) {
|
||||
unique_lock client_channel_lock(target->channel_tree_mutex);
|
||||
std::unique_lock client_channel_lock{target_client->channel_tree_mutex};
|
||||
|
||||
bool success = false;
|
||||
bool success{false};
|
||||
/* TODO: Use a bunk here and not a notify for every single */
|
||||
for(const auto& channel : target->channel_tree->show_channel(l_target_channel, success))
|
||||
target->notifyChannelShow(channel->channel(), channel->previous_channel);
|
||||
sassert(success);
|
||||
if(!success)
|
||||
return;
|
||||
for(const auto& channel : target_client->channel_tree->show_channel(l_target_channel, success)) {
|
||||
target_client->notifyChannelShow(channel->channel(), channel->previous_channel);
|
||||
}
|
||||
|
||||
target->subscribeChannel({target_channel}, false, true);
|
||||
sassert(success);
|
||||
if(!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
target_client->subscribeChannel({ target_channel }, false, true);
|
||||
}
|
||||
TIMING_STEP(timings, "target show");
|
||||
|
||||
if(s_source_channel) {
|
||||
s_source_channel->unregister_client(target_client);
|
||||
}
|
||||
|
||||
if(target_channel) {
|
||||
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
|
||||
if (!notify_client && client == target) return;
|
||||
ClientPermissionCalculator target_client_permissions{&*target_client, target_channel};
|
||||
auto needed_view_power = target_client_permissions.calculate_permission(permission::i_client_needed_serverquery_view_power);
|
||||
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
auto chan_target = client->channel_tree->find_channel(target_channel);
|
||||
/* ct_... is for client channel tree */
|
||||
this->forEachClient([&](const std::shared_ptr<ConnectedClient>& client) {
|
||||
if (!notify_client && client == target_client) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(chan_target) {
|
||||
auto chan_source = client->channel_tree->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);
|
||||
bool move_target_client_visible{true};
|
||||
if(target_client->getType() == ClientType::CLIENT_QUERY) {
|
||||
auto query_view_power = client->calculate_permission(permission::i_client_serverquery_view_power, target_channel->channelId());
|
||||
move_target_client_visible = permission::v2::permission_granted(needed_view_power, query_view_power);
|
||||
}
|
||||
|
||||
std::unique_lock client_channel_lock{client->channel_tree_mutex};
|
||||
auto ct_target_channel = move_target_client_visible ? client->channel_tree->find_channel(target_channel) : nullptr;
|
||||
|
||||
if(ct_target_channel) {
|
||||
auto ct_source_channel = client->channel_tree->find_channel(s_source_channel);
|
||||
if(ct_source_channel) {
|
||||
/* Source and target channel are visible for the client. Just a "normal" move. */
|
||||
if (ct_target_channel->subscribed || client == target_client) {
|
||||
if (client == target_client || client->isClientVisible(target_client, false)) {
|
||||
client->notifyClientMoved(target_client, 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);
|
||||
client->notifyClientEnterView(target_client, 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() ? string("view left") : reason_message, invoker, false);
|
||||
} else if(client->isClientVisible(target_client, false)){
|
||||
/* Client has been moved into an unsubscribed channel */
|
||||
client->notifyClientLeftView(target_client, s_target_channel, reason_id, reason_message.empty() ? string("view left") : reason_message, invoker, false);
|
||||
}
|
||||
} else {
|
||||
if(client == target && client->getType() != ClientType::CLIENT_INTERNAL && client->getType() != ClientType::CLIENT_MUSIC)
|
||||
logCritical(this->getServerId(), "{} 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 if(ct_target_channel->subscribed) {
|
||||
/* Target client entered the view from an invisible channel */
|
||||
client->notifyClientEnterView(target_client, 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->getServerId(), "{} 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(client->isClientVisible(target_client, false)) {
|
||||
/* Client has been moved out of view into an invisible channel */
|
||||
if(reason_id == ViewReasonId::VREASON_USER_ACTION) {
|
||||
client->notifyClientLeftView(target_client, nullptr, ViewReasonId::VREASON_SERVER_LEFT, reason_message.empty() ? "joined a hidden channel" : reason_message, invoker, false);
|
||||
} else {
|
||||
client->notifyClientLeftView(target_client, 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);
|
||||
if(auto client{dynamic_pointer_cast<SpeakingClient>(target)}; client) {
|
||||
s_target_channel->register_client(target_client);
|
||||
if(auto client{dynamic_pointer_cast<SpeakingClient>(target_client)}; client) {
|
||||
this->rtc_server().assign_channel(client->rtc_client_id, s_target_channel->rtc_channel_id);
|
||||
}
|
||||
if(auto client{dynamic_pointer_cast<VoiceClient>(target)}; client) {
|
||||
|
||||
if(auto client{dynamic_pointer_cast<VoiceClient>(target_client)}; client) {
|
||||
/* Start normal broadcasting, what the client expects */
|
||||
this->rtc_server().start_broadcast_audio(client->rtc_client_id, 1);
|
||||
}
|
||||
} else {
|
||||
/* client left the server */
|
||||
if(target->currentChannel) {
|
||||
if(target_client->currentChannel) {
|
||||
for(const auto& client : this->getClients()) {
|
||||
if(!client || client == target)
|
||||
if(!client || client == target_client)
|
||||
continue;
|
||||
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
if(client->isClientVisible(target, false))
|
||||
client->notifyClientLeftView(target, nullptr, reason_id, reason_message, invoker, false);
|
||||
if(client->isClientVisible(target_client, false)) {
|
||||
client->notifyClientLeftView(target_client, nullptr, reason_id, reason_message, invoker, false);
|
||||
}
|
||||
}
|
||||
|
||||
s_source_channel->unregister_client(target);
|
||||
if(auto client{dynamic_pointer_cast<SpeakingClient>(target)}; client) {
|
||||
if(auto client{dynamic_pointer_cast<SpeakingClient>(target_client)}; client) {
|
||||
this->rtc_server().assign_channel(client->rtc_client_id, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
TIMING_STEP(timings, "notify view");
|
||||
|
||||
target->currentChannel = target_channel;
|
||||
target_client->currentChannel = target_channel;
|
||||
|
||||
/* third step: update stuff for the client (remember: the client cant execute anything at the moment!) */
|
||||
unique_lock client_channel_lock{target->channel_tree_mutex};
|
||||
unique_lock client_channel_lock{target_client->channel_tree_mutex};
|
||||
TIMING_STEP(timings, "lock own tr");
|
||||
|
||||
if (s_source_channel) {
|
||||
s_source_channel->properties()[property::CHANNEL_LAST_LEFT] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
|
||||
this->group_manager()->assignments().cleanup_temporary_channel_assignment(target->getClientDatabaseId(),
|
||||
s_source_channel->channelId());
|
||||
s_source_channel->properties()[property::CHANNEL_LAST_LEFT] = std::chrono::duration_cast<chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
this->group_manager()->assignments().cleanup_temporary_channel_assignment(target_client->getClientDatabaseId(), s_source_channel->channelId());
|
||||
|
||||
auto update = target->properties()[property::CLIENT_IS_TALKER].as_or<bool>(false) ||
|
||||
target->properties()[property::CLIENT_TALK_REQUEST].as_or<int64_t>(0) > 0;
|
||||
if(update) {
|
||||
target->properties()[property::CLIENT_IS_TALKER] = 0;
|
||||
target->properties()[property::CLIENT_TALK_REQUEST] = 0;
|
||||
target->properties()[property::CLIENT_TALK_REQUEST_MSG] = "";
|
||||
if(target_client->properties()[property::CLIENT_IS_TALKER].update_value("0")) {
|
||||
updated_client_properties.push_back(property::CLIENT_IS_TALKER);
|
||||
}
|
||||
|
||||
if(target_client->properties()[property::CLIENT_TALK_REQUEST].update_value("0")) {
|
||||
updated_client_properties.push_back(property::CLIENT_TALK_REQUEST);
|
||||
}
|
||||
|
||||
if(target_client->properties()[property::CLIENT_TALK_REQUEST_MSG].update_value("")) {
|
||||
updated_client_properties.push_back(property::CLIENT_TALK_REQUEST_MSG);
|
||||
}
|
||||
TIMING_STEP(timings, "src chan up");
|
||||
}
|
||||
|
||||
if (s_target_channel) {
|
||||
target->task_update_needed_permissions.enqueue();
|
||||
target->task_update_displayed_groups.enqueue();
|
||||
target_client->task_update_needed_permissions.enqueue();
|
||||
target_client->task_update_displayed_groups.enqueue();
|
||||
TIMING_STEP(timings, "perm gr upd");
|
||||
|
||||
if(s_source_channel) {
|
||||
deque<ChannelId> deleted;
|
||||
for(const auto& channel : target->channel_tree->test_channel(l_source_channel, l_target_channel)) {
|
||||
for(const auto& channel : target_client->channel_tree->test_channel(l_source_channel, l_target_channel)) {
|
||||
deleted.push_back(channel->channelId());
|
||||
}
|
||||
|
||||
if(!deleted.empty()) {
|
||||
target->notifyChannelHide(deleted, false);
|
||||
target_client->notifyChannelHide(deleted, false);
|
||||
}
|
||||
|
||||
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);
|
||||
auto source_channel_sub_power = target_client->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);
|
||||
auto source_channel_sub_power_ignore = target_client->calculate_permission(permission::b_channel_ignore_subscribe_power, i_source_channel);
|
||||
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore)) {
|
||||
logTrace(this->serverId, "Force unsubscribing of client {} for channel {}/{}. (Channel switch and no permissions)",
|
||||
CLIENT_STR_LOG_PREFIX_(target), s_source_channel->name(),
|
||||
CLIENT_STR_LOG_PREFIX_(target_client), s_source_channel->name(),
|
||||
i_source_channel
|
||||
);
|
||||
target->unsubscribeChannel({s_source_channel}, false); //Unsubscribe last channel (hasn't permissions)
|
||||
target_client->unsubscribeChannel({ s_source_channel }, false); //Unsubscribe last channel (hasn't permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,12 +626,13 @@ void VirtualServer::client_move(
|
||||
}
|
||||
}
|
||||
client_channel_lock.unlock();
|
||||
|
||||
/* both methods lock if they require stuff */
|
||||
this->notifyClientPropertyUpdates(target, updated_client_properties, s_source_channel ? true : false);
|
||||
this->notifyClientPropertyUpdates(target_client, updated_client_properties, s_source_channel ? true : false);
|
||||
TIMING_STEP(timings, "notify cpro");
|
||||
if(s_target_channel) {
|
||||
target->updateChannelClientProperties(false, s_source_channel ? true : false);
|
||||
target_client->updateChannelClientProperties(false, s_source_channel ? true : false);
|
||||
TIMING_STEP(timings, "notify_t_pr");
|
||||
}
|
||||
debugMessage(this->getServerId(), "{} Client move timings: {}", CLIENT_STR_LOG_PREFIX_(target), TIMING_FINISH(timings));
|
||||
debugMessage(this->getServerId(), "{} Client move timings: {}", CLIENT_STR_LOG_PREFIX_(target_client), TIMING_FINISH(timings));
|
||||
}
|
||||
Reference in New Issue
Block a user