A lot of updates

This commit is contained in:
WolverinDEV 2020-02-01 14:32:16 +01:00
parent fe05c63882
commit 543e6b1abc
44 changed files with 714 additions and 392 deletions

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.6)
project(TeaMusic)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wno-sign-compare -Wno-reorder -static-libgcc -static-libstdc++ -Wl,--enable-new-dtags,--export-dynamic")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wno-sign-compare -Wno-reorder -static-libgcc -static-libstdc++")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/enviroment/)
@ -14,8 +14,8 @@ add_definitions(-DLTM_DESC)
#The basic library
add_library(TeaMusic SHARED src/MusicPlayer.cpp)
target_link_libraries(TeaMusic PUBLIC TeaSpeak)
target_link_libraries(TeaMusic PUBLIC TeaSpeak libevent::core libevent::pthreads)
#The test file
add_executable(TeaMusicTest ${MUSIC_SOURCE_FILES} main.cpp)
target_link_libraries(TeaMusicTest ProviderFFMpeg ProviderYT ProviderOpus TeaMusic pthread ThreadPool opus asound opusfile stdc++fs dl mpg123 avformat avcodec avutil TeaSpeak CXXTerminal event jsoncpp)
#add_executable(TeaMusicTest ${MUSIC_SOURCE_FILES} main.cpp)
#target_link_libraries(TeaMusicTest ProviderFFMpeg ProviderYT ProviderOpus TeaMusic pthread ThreadPool opus asound opusfile stdc++fs dl mpg123 avformat avcodec avutil TeaSpeak CXXTerminal event jsoncpp)

View File

@ -15,12 +15,12 @@ void log::log(const Level& lvl, const std::string& msg) {
}
void AbstractMusicPlayer::registerEventHandler(const std::string& key, const std::function<void(MusicEvent)>& function) {
threads::MutexLock lock(this->eventLock);
std::lock_guard lock(this->eventLock);
this->eventHandlers.emplace_back(key, function);
}
void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
threads::MutexLock lock(this->eventLock);
std::lock_guard lock(this->eventLock);
for(const auto& entry : this->eventHandlers){
if(entry.first == string) {
this->eventHandlers.erase(find_if(this->eventHandlers.begin(), this->eventHandlers.end(), [string](const std::pair<std::string, std::function<void(MusicEvent)>>& elm){ return elm.first == string; }));
@ -30,7 +30,7 @@ void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
}
void AbstractMusicPlayer::fireEvent(MusicEvent event) {
threads::MutexLock lock(this->eventLock);
std::lock_guard lock(this->eventLock);
auto listCopy = this->eventHandlers; //Copy for remove while fire
for(const auto& entry : listCopy)
entry.second(event);
@ -38,18 +38,18 @@ void AbstractMusicPlayer::fireEvent(MusicEvent event) {
const char* music::stateNames[] = {"uninitialised", "playing", "paused", "stopped"};
static threads::Mutex staticLock;
static std::mutex staticLock;
static std::deque<std::shared_ptr<PlayerProvider>> types;
std::deque<std::shared_ptr<PlayerProvider>> manager::registeredTypes(){ return types; }
void registerType(const std::shared_ptr<PlayerProvider>& provider) {
threads::MutexLock l(staticLock);
std::lock_guard l(staticLock);
types.push_back(provider);
}
//empty for not set
std::shared_ptr<PlayerProvider> manager::resolveProvider(const std::string& provName, const std::string& str) {
threads::MutexLock l(staticLock);
std::lock_guard l(staticLock);
vector<std::shared_ptr<PlayerProvider>> provs;
for(const auto& prov : types){
auto p = prov.get();
@ -111,11 +111,11 @@ void manager::loadProviders(const std::string& path) {
}
void manager::register_provider(const std::shared_ptr<music::manager::PlayerProvider> &provider) {
threads::MutexLock l(staticLock);
std::lock_guard l(staticLock);
types.push_back(provider);
}
void manager::finalizeProviders() {
threads::MutexLock l(staticLock);
std::lock_guard l(staticLock);
types.clear();
}

View File

@ -152,7 +152,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/client/command_handler/helpers.h src/music/PlaylistPermissions.cpp src/music/PlaylistPermissions.h)
endif ()
add_executable(PermHelper helpers/permgen.cpp)

View File

@ -232,7 +232,7 @@ inline sql::result load_permissions(const std::shared_ptr<VirtualServer>& server
auto time = end - start;
logTrace(server ? server->getServerId() : 0, "[SQL] load_permissions(\"{}\") took {}ms", command.sqlCommand(), duration_cast<milliseconds>(time).count());
}
inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& server, v2::PermissionManager* manager, sql::command& command, bool resolve_channel /* only used for client permissions (client channel permissions) */) {
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) */) {
auto start = system_clock::now();
auto server_id = server ? server->getServerId() : 0;
@ -240,9 +240,9 @@ inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& ser
permission::PermissionType key = permission::PermissionType::undefined;
permission::PermissionValue value = permNotGranted, granted = permNotGranted;
bool negated = false, skipped = false;
std::shared_ptr<BasicChannel> channel;
ChannelId channel_id{0};
int index;
try {
for(index = 0; index < length; index++) {
if(strcmp(names[index], "permId") == 0) {
@ -256,18 +256,7 @@ inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& ser
return 0;
}
} else if(strcmp(names[index], "channelId") == 0) {
if(resolve_channel) {
auto channelId = stoull(values[index]);
if(channelId > 0) {
if(!server)
logError(server_id, "[SQL] Cant find channel for channel bound permission (No server given)! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
else {
channel = server->getChannelTree()->findChannel(channelId);
if(!channel)
logError(server_id, "[SQL] Cant find channel for channel bound permission! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
}
}
}
channel_id = stoull(values[index]);
} else if(strcmp(names[index], "value") == 0) {
value = stoi(values[index]);
} else if(strcmp(names[index], "grant") == 0) {
@ -281,16 +270,26 @@ inline sql::result load_permissions_v2(const std::shared_ptr<VirtualServer>& ser
logError(server_id, "[SQL] Cant load permissions! Failed to parse value! Command: {} Message: {} Key: {} Value: {}", command.sqlCommand(), ex.what(),names[index], values[index]);
return 0;
}
if(channel_id > 0 && test_channel) {
if(!server)
logError(server_id, "[SQL] Cant find channel for channel bound permission (No server given)! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
else {
auto channel = server->getChannelTree()->findChannel(channel_id);
if(!channel)
logError(server_id, "[SQL] Cant find channel for channel bound permission! Command: {} ChannelID: {}", command.sqlCommand(), values[index]);
}
}
if(key == permission::undefined) {
debugMessage(server_id, "[SQL] Permission entry misses permission type! Command: {}", command.sqlCommand());
return 0;
}
if(!resolve_channel || !channel)
if(channel_id == 0)
manager->load_permission(key, {value, granted}, skipped, negated, value != permNotGranted, granted != permNotGranted);
else
manager->load_permission(key, {value, granted}, channel->channelId(), skipped, negated, value != permNotGranted, granted != permNotGranted);
manager->load_permission(key, {value, granted}, channel_id, skipped, negated, value != permNotGranted, granted != permNotGranted);
return 0;
});
@ -476,8 +475,8 @@ void DatabaseHelper::saveGroupPermissions(const std::shared_ptr<ts::server::Virt
}
}
std::shared_ptr<permission::PermissionManager> DatabaseHelper::loadPlaylistPermissions(const std::shared_ptr<ts::server::VirtualServer> &server, ts::PlaylistId playlist_id) {
shared_ptr<PermissionManager> result;
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;
if(this->use_startup_cache && server) {
shared_ptr<StartupCacheEntry> entry;
{
@ -490,71 +489,59 @@ std::shared_ptr<permission::PermissionManager> DatabaseHelper::loadPlaylistPermi
}
}
if(entry) {
result = std::make_shared<PermissionManager>();
result = std::make_shared<permission::v2::PermissionManager>();
for(const auto& perm : entry->permissions) {
if(perm->type == permission::SQL_PERM_PLAYLIST && perm->id == playlist_id) {
auto permission = result->registerPermission(perm->permission, perm->value, server->getChannelTree()->findChannel(perm->channelId));
permission->granted = perm->grant;
permission->value = perm->value;
permission->dbReference = true;
permission->flag_negate = perm->flag_negate;
permission->flag_skip = perm->flag_skip;
result->load_permission(perm->permission->type, {perm->value, perm->grant}, perm->flag_skip, perm->flag_negate, perm->value != permNotGranted, perm->grant != permNotGranted);
}
}
}
return result;
}
if(!result) {
result = std::make_shared<PermissionManager>();
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},
variable{":id", playlist_id});
LOG_SQL_CMD(load_permissions(server, result.get(), command));
}
result = std::make_shared<permission::v2::PermissionManager>();
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},
variable{":id", playlist_id});
LOG_SQL_CMD(load_permissions_v2(server, result.get(), command, false));
return result;
}
void DatabaseHelper::savePlaylistPermissions(const std::shared_ptr<VirtualServer> &server, PlaylistId pid, const std::shared_ptr<permission::v2::PermissionManager> &permissions) {
const auto updates = permissions->flush_db_updates();
if(updates.empty())
return;
assert(result);
weak_ptr<VirtualServer> weak_server = server;
auto server_id = server ? server->getServerId() : 0;
for(auto& update : updates) {
std::string query = update.flag_delete ? DELETE_COMMAND : (update.flag_db ? UPDATE_COMMAND : INSERT_COMMAND);
result->registerUpdateHandler([&, weak_server, server_id, playlist_id](std::shared_ptr<Permission> permission) {
auto server = weak_server.lock();
if(!server && server_id != 0) {
logError(server_id, "Tried to update a playlist permission of a expired server!");
return;
}
std::string query;
/*
if(permission->deleted){
query = "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `id` = :id AND `type`= :type AND `permId`= :permId AND `channelId` = :chId";
} else
*/
if(permission->dbReference){
query = UPDATE_COMMAND;
} else {
permission->dbReference = true;
query = INSERT_COMMAND;
}
logTrace(server ? server->getServerId() : 0, "[SQL] Executing group permission command: {}", query);
auto permission_data = permission::resolvePermissionData(update.permission);
auto value = update.update_value == v2::delete_value ? permNotGranted : update.values.value;
auto grant = update.update_grant == v2::delete_value ? permNotGranted : update.values.grant;
logTrace(server_id, "[PLAYLIST] Updating playlist permission for playlist {}: {}. New value: {}. New grant: {}. Query: {}",
pid,
permission_data->name,
value,
grant,
query
);
sql::command(this->sql, query,
variable{":serverId", server ? server->getServerId() : 0},
variable{":id", playlist_id},
variable{":id", pid},
variable{":chId", 0},
variable{":type", permission::SQL_PERM_PLAYLIST},
variable{":chId", permission->channelId()},
variable{":permId", permission->type->name},
variable{":value", permission->value},
variable{":grant", permission->granted},
variable{":flag_skip", permission->flag_skip},
variable{":flag_negate", permission->flag_negate})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "failed to save playlist permission " + to_string(playlist_id)});
});
return result;
variable{":permId", permission_data->name},
variable{":value", value},
variable{":grant", grant},
variable{":flag_skip", update.flag_skip},
variable{":flag_negate", update.flag_negate})
.executeLater().waitAndGetLater(LOG_SQL_CMD, {-1, "future error"});
}
}
std::shared_ptr<permission::v2::PermissionManager> DatabaseHelper::loadChannelPermissions(const std::shared_ptr<VirtualServer>& server, ts::ChannelId channel) {

View File

@ -91,16 +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); //Just and write
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::PermissionManager> loadChannelPermissions(const std::shared_ptr<VirtualServer>&, ChannelId); //Just read
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::PermissionManager> loadGroupPermissions(const std::shared_ptr<VirtualServer>&, GroupId); //Just read
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::PermissionManager> loadPlaylistPermissions(const std::shared_ptr<VirtualServer>&, PlaylistId /* playlist id */); //Read and write
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<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

@ -215,7 +215,7 @@ void VirtualServer::testBanStateChange(const std::shared_ptr<ConnectedClient>& i
logMessage(this->getServerId(), "Client {} was online, but had an ban whcih effect him has been registered. Disconnecting client.", CLIENT_STR_LOG_PREFIX_(client));
auto entryTime = ban->until.time_since_epoch().count() > 0 ? (uint64_t) chrono::ceil<seconds>(ban->until - system_clock::now()).count() : 0UL;
this->notify_client_ban(client, invoker, ban->reason, entryTime);
client->closeConnection(system_clock::now() + seconds(1));
client->close_connection(system_clock::now() + seconds(1));
}
});
}

View File

@ -5,6 +5,7 @@
#include "InstanceHandler.h"
#include "VirtualServer.h"
#include "./manager/ConversationManager.h"
#include "./music/MusicBotManager.h"
using namespace std;
using namespace std::chrono;
@ -12,7 +13,6 @@ using namespace ts::server;
using namespace ts::protocol;
using namespace ts::buffer;
extern InstanceHandler* serverInstance;
inline void banClientFlood(VirtualServer* server, const shared_ptr<ConnectedClient>& cl, time_point<system_clock> until){
auto time = until.time_since_epoch().count() == 0 ? 0L : chrono::ceil<chrono::seconds>(until - system_clock::now()).count();
@ -21,7 +21,7 @@ inline void banClientFlood(VirtualServer* server, const shared_ptr<ConnectedClie
for(const auto &client : server->findClientsByUid(cl->getUid())) {
server->notify_client_ban(client, server->getServerRoot(), reason, time);
client->closeConnection(system_clock::now() + seconds(1));
client->close_connection(system_clock::now() + seconds(1));
}
}
@ -56,7 +56,7 @@ void VirtualServer::executeServerTick() {
lastTick = system_clock::now();
system_clock::time_point timing_begin, timing_end;
milliseconds timing_update_states, timing_client_tick, timing_channel, timing_statistic, timing_groups, timing_ccache;
milliseconds timing_update_states, timing_client_tick, timing_channel, timing_statistic, timing_groups, timing_ccache, music_manager;
auto client_list = this->getClients();
@ -269,6 +269,12 @@ void VirtualServer::executeServerTick() {
END_TIMINGS(timing_ccache);
}
{
BEGIN_TIMINGS();
this->musicManager->execute_tick();
END_TIMINGS(music_manager);
}
if(system_clock::now() - lastTick > milliseconds(100)) {
//milliseconds timing_update_states, timing_client_tick, timing_channel, timing_statistic;
logError(this->serverId, "Server tick tooks to long ({}ms => Status updates: {}ms Client tick: {}ms, Channel tick: {}ms, Statistic tick: {}ms, Groups: {}ms, Conversation cache: {}ms)",

View File

@ -479,7 +479,7 @@ void VirtualServer::stop(const std::string& reason) {
for(const auto& cl : this->getClients()) { //start disconnecting
if(cl->getType() == CLIENT_TEAMSPEAK || cl->getType() == CLIENT_TEASPEAK || cl->getType() == CLIENT_WEB) {
cl->closeConnection(chrono::system_clock::now() + chrono::seconds(1));
cl->close_connection(chrono::system_clock::now() + chrono::seconds(1));
} else if(cl->getType() == CLIENT_QUERY){
threads::MutexLock lock(cl->command_lock);
cl->currentChannel = nullptr;
@ -575,7 +575,7 @@ OnlineClientReport VirtualServer::onlineStats() {
return response;
}
std::shared_ptr<ConnectedClient> VirtualServer::findClient(uint16_t client_id) {
std::shared_ptr<ConnectedClient> VirtualServer::find_client_by_id(uint16_t client_id) {
lock_guard lock(this->clients.lock);
if(this->clients.clients.size() > client_id)
return this->clients.clients[client_id];

View File

@ -149,7 +149,7 @@ namespace ts {
size_t onlineClients();
OnlineClientReport onlineStats();
size_t onlineChannels(){ return this->channelTree->channel_count(); }
std::shared_ptr<ConnectedClient> findClient(ClientId clientId);
std::shared_ptr<ConnectedClient> find_client_by_id(ClientId /* client id */);
std::deque<std::shared_ptr<ConnectedClient>> findClientsByCldbId(ClientDbId cldbId);
std::deque<std::shared_ptr<ConnectedClient>> findClientsByUid(ClientUid uid);
std::shared_ptr<ConnectedClient> findClient(std::string name, bool ignoreCase = true);

View File

@ -835,7 +835,7 @@ bool ConnectedClient::handleCommandFull(Command& cmd, bool disconnectOnFail) {
this->notifyError(result, cmd["return_code"].size() > 0 ? cmd["return_code"].first().as<std::string>() : "");
if(result.error_code() != error::ok && this->state == ConnectionState::INIT_HIGH)
this->closeConnection(system_clock::now()); //Disconnect now
this->close_connection(system_clock::now()); //Disconnect now
for (const auto& handler : postCommandHandler)
handler();
@ -931,8 +931,7 @@ bool ConnectedClient::update_cached_permissions() {
for(const auto& entry : values) {
if(entry.first == permission::i_client_whisper_power)
this->cpmerission_whisper_power = entry.second;
else
if(entry.first == permission::i_client_needed_whisper_power)
else if(entry.first == permission::i_client_needed_whisper_power)
this->cpmerission_needed_whisper_power = entry.second;
}

View File

@ -232,7 +232,10 @@ namespace ts {
virtual bool notifyConversationMessageDelete(const ChannelId /* conversation id */, const std::chrono::system_clock::time_point& /* begin timestamp */, const std::chrono::system_clock::time_point& /* begin end */, ClientDbId /* client id */, size_t /* messages */);
virtual bool closeConnection(const std::chrono::system_clock::time_point &timeout = std::chrono::system_clock::time_point()) = 0;
/* this method should be callable from everywhere; the method is non blocking! */
virtual bool close_connection(const std::chrono::system_clock::time_point &timeout) = 0;
/* this method should be callable from everywhere; the method is non blocking! */
virtual bool disconnect(const std::string& reason) = 0;
void resetIdleTime();
@ -255,6 +258,7 @@ namespace ts {
inline std::shared_ptr<ConnectedClient> ref() { return _this.lock(); }
std::shared_mutex& get_channel_lock() { return this->channel_lock; }
/*
* permission stuff
*/
@ -271,18 +275,36 @@ namespace ts {
}
*/
bool update_cached_permissions();
std::shared_lock<std::shared_mutex> require_connected_state(bool blocking = false) {
//try_to_lock_t
std::shared_lock<std::shared_mutex> disconnect_lock{};
if(__glibc_unlikely(blocking))
disconnect_lock = std::shared_lock{this->finalDisconnectLock};
else
disconnect_lock = std::shared_lock{this->finalDisconnectLock, std::try_to_lock};
if(__glibc_unlikely(!disconnect_lock))
return disconnect_lock;
{
std::lock_guard state_lock{this->state_lock};
if(this->state != ConnectionState::CONNECTED)
return {};
}
return disconnect_lock;
}
protected:
std::weak_ptr<ConnectedClient> _this;
sockaddr_storage remote_address;
//General states
std::mutex state_lock;
ConnectionState state = ConnectionState::UNKNWON;
sockaddr_storage remote_address;
ConnectionState state{ConnectionState::UNKNWON};
bool allowedToTalk = false;
threads::Mutex disconnectLock;
std::shared_mutex finalDisconnectLock;
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 */
@ -510,10 +532,15 @@ namespace ts {
command_result handleCommandPlaylistList(Command&);
command_result handleCommandPlaylistCreate(Command&);
command_result handleCommandPlaylistDelete(Command&);
command_result handleCommandPlaylistPermList(Command&);
command_result handleCommandPlaylistAddPerm(Command&);
command_result handleCommandPlaylistDelPerm(Command&);
command_result handleCommandPlaylistClientPermList(Command&);
command_result handleCommandPlaylistClientAddPerm(Command&);
command_result handleCommandPlaylistClientDelPerm(Command&);
/* playlist properties */
command_result handleCommandPlaylistInfo(Command&);
command_result handleCommandPlaylistEdit(Command&);
@ -595,5 +622,45 @@ namespace ts {
return "";
}
};
template <typename T>
struct ConnectedLockedClient {
explicit ConnectedLockedClient(std::shared_ptr<T> client) : client{std::move(client)} {
if(this->client)
this->connection_lock = this->client->require_connected_state();
}
inline ConnectedLockedClient<T> &operator=(const ConnectedLockedClient& other) {
this->client = other.client;
if(other)
this->connection_lock = std::shared_lock{*other.connection_lock.mutex()}; /* if the other is true (state locked & client) than we could easily acquire a shared lock */
}
inline ConnectedLockedClient<T> &operator=(ConnectedLockedClient&& other) {
this->client = std::move(other.client);
this->connection_lock = std::move(other.connection_lock);
}
inline bool valid() const { return !!this->client && !!this->connection_lock; }
inline operator bool() const { return this->valid(); }
inline bool operator!() const { return !this->valid(); }
template <typename _T>
inline bool operator==(const std::shared_ptr<_T>& other) { return this->client.get() == other.get(); }
T* operator->() { return &*this->client; }
T &operator*() { return *this->client; }
std::shared_ptr<T> client;
std::shared_lock<std::shared_mutex> connection_lock{};
};
}
}
template <typename T1, typename T2>
inline bool operator==(const std::shared_ptr<T1>& a, const ts::server::ConnectedLockedClient<T2>& b) {
return a.get() == b.client.get();
}

View File

@ -25,7 +25,7 @@ InternalClient::~InternalClient() {
void InternalClient::sendCommand(const ts::Command &command, bool low) { }
void InternalClient::sendCommand(const ts::command_builder &command, bool low) { }
bool InternalClient::closeConnection(const std::chrono::system_clock::time_point& timeout) {
bool InternalClient::close_connection(const std::chrono::system_clock::time_point& timeout) {
logError(this->getServerId(), "Internal client is force to disconnect?");
if(this->server)

View File

@ -16,7 +16,7 @@ namespace ts {
void sendCommand(const ts::Command &command, bool low) override;
void sendCommand(const ts::command_builder &command, bool low) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool close_connection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool disconnect(const std::string &reason) override;
protected:
void tick(const std::chrono::system_clock::time_point &time) override;

View File

@ -602,13 +602,12 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
this->postCommandHandler.emplace_back([&](){
auto self = dynamic_pointer_cast<SpeakingClient>(_this.lock());
std::thread([self](){
threads::MutexLock l1(self->disconnectLock);
if(self->state != ConnectionState::INIT_HIGH) return;
try {
self->processJoin();
} catch (std::exception& ex) {
logError(self->getServerId(), "Failed to proceed client join for {}. Got exception with message {}", CLIENT_STR_LOG_PREFIX_(self), ex.what());
self->closeConnection();
self->close_connection(chrono::system_clock::now() + chrono::seconds{5});
}
}).detach();
});
@ -670,7 +669,7 @@ void SpeakingClient::processJoin() {
auto result = command_result{error::vs_critical, "Could not assign default channel!"};
this->notifyError(result);
result.release_details();
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
return;
}
TIMING_STEP(timings, "assign chan");
@ -767,7 +766,7 @@ void SpeakingClient::tick(const std::chrono::system_clock::time_point &time) {
auto max_idle = this->max_idle_time.value;
if(max_idle > 0 && this->idleTimestamp.time_since_epoch().count() > 0 && duration_cast<seconds>(time - this->idleTimestamp).count() > max_idle) {
this->server->notify_client_kick(this->ref(), this->server->getServerRoot(), ts::config::messages::idle_time_exceeded, nullptr);
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
}
}
@ -792,7 +791,7 @@ command_result SpeakingClient::handleCommand(Command &command) {
if(result.error_code())
this->postCommandHandler.push_back([&]{
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
});
return result;
}

View File

@ -50,10 +50,10 @@ using namespace ts::token;
command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
CMD_REQ_SERVER;
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
shared_lock tree_lock(this->channel_lock);
if (!client || (client != this && !this->isClientVisible(client, false)))
if (!client || (client.client != this && !this->isClientVisible(client.client, false)))
return command_result{error::client_invalid_id, ""};
deque<shared_ptr<property::PropertyDescription>> props;
@ -61,7 +61,7 @@ command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
props.push_back(property::info((property::ClientProperties) prop.type().property_index));
}
this->notifyClientUpdated(client, props, false);
this->notifyClientUpdated(client.client, props, false);
return command_result{error::ok};
}
@ -69,26 +69,26 @@ command_result ConnectedClient::handleCommandClientKick(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
if (client->getType() == CLIENT_MUSIC) return command_result{error::client_invalid_type, "You cant kick a music bot!"};
std::shared_ptr<BasicChannel> targetChannel = nullptr;
auto type = cmd["reasonid"].as<ViewReasonId>();
if (type == ViewReasonId::VREASON_CHANNEL_KICK) {
auto channel = client->currentChannel;
auto channel = client->getChannel();
ACTION_REQUIRES_PERMISSION(permission::i_client_kick_from_channel_power, client->calculate_permission(permission::i_client_needed_kick_from_channel_power, client->getChannelId()), client->getChannelId());
targetChannel = this->server->channelTree->getDefaultChannel();
} else if (type == ViewReasonId::VREASON_SERVER_KICK) {
auto channel = client->currentChannel;
auto channel = client->getChannel();
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_kick_from_server_power, client->calculate_permission(permission::i_client_needed_kick_from_server_power, client->getChannelId()));
targetChannel = nullptr;
} else return command_result{error::not_implemented};
if (targetChannel) {
this->server->notify_client_kick(client, this->ref(), cmd["reasonmsg"].as<std::string>(), targetChannel);
this->server->notify_client_kick(client.client, this->ref(), cmd["reasonmsg"].as<std::string>(), targetChannel);
} else {
this->server->notify_client_kick(client, this->ref(), cmd["reasonmsg"].as<std::string>(), nullptr);
client->closeConnection(system_clock::now() + seconds(1));
this->server->notify_client_kick(client.client, this->ref(), cmd["reasonmsg"].as<std::string>(), nullptr);
client->close_connection(system_clock::now() + seconds(1));
}
return command_result{error::ok};
@ -139,13 +139,13 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
shared_lock server_channel_r_lock(this->server->channel_tree_lock);
auto target_client_id = cmd["clid"].as<ClientId>();
auto target_client = target_client_id == 0 ? this->ref() : this->server->findClient(target_client_id);
ConnectedLockedClient target_client{target_client_id == 0 ? this->ref() : this->server->find_client_by_id(target_client_id)};
if(!target_client) {
return command_result{error::client_invalid_id, "Invalid target clid"};
}
if(!target_client->currentChannel) {
if(target_client != this)
if(!target_client->getChannel()) {
if(target_client.client != this)
return command_result{error::client_invalid_id, "Invalid target clid"};
}
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
@ -188,18 +188,18 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
}
}
if (target_client != this)
if (target_client.client != this)
ACTION_REQUIRES_PERMISSION(permission::i_client_move_power, target_client->calculate_permission(permission::i_client_needed_move_power, target_client->getChannelId()), target_client->getChannelId());
server_channel_r_lock.unlock();
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
auto oldChannel = target_client->getChannel();
this->server->client_move(
target_client,
target_client.client,
channel,
target_client == this ? nullptr : _this.lock(),
target_client.client == this ? nullptr : _this.lock(),
"",
target_client == this ? ViewReasonId::VREASON_USER_ACTION : ViewReasonId::VREASON_MOVED,
target_client.client == this ? ViewReasonId::VREASON_USER_ACTION : ViewReasonId::VREASON_MOVED,
true,
server_channel_w_lock
);
@ -221,7 +221,7 @@ command_result ConnectedClient::handleCommandClientPoke(Command &cmd) {
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{ this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
if (client->getType() == CLIENT_MUSIC) return command_result{error::client_invalid_type};
ACTION_REQUIRES_PERMISSION(permission::i_client_poke_power, client->calculate_permission(permission::i_client_needed_poke_power, client->getChannelId()), client->getChannelId());
@ -235,7 +235,7 @@ command_result ConnectedClient::handleCommandClientChatComposing(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(0);
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
client->notifyClientChatComposing(_this.lock());
@ -246,16 +246,16 @@ command_result ConnectedClient::handleCommandClientChatClosed(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient<ConnectedClient> client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
this->openChats.erase(remove_if(this->openChats.begin(), this->openChats.end(), [client](const weak_ptr<ConnectedClient>& weak) {
this->openChats.erase(remove_if(this->openChats.begin(), this->openChats.end(), [&](const weak_ptr<ConnectedClient>& weak) {
return weak.lock() == client;
}), this->openChats.end());
}
{
unique_lock channel_lock(client->channel_lock);
unique_lock channel_lock(client->get_channel_lock());
client->openChats.erase(remove_if(client->openChats.begin(), client->openChats.end(), [&](const weak_ptr<ConnectedClient>& weak) {
return weak.lock().get() == this;
}), client->openChats.end());
@ -421,9 +421,9 @@ command_result ConnectedClient::handleCommandClientDBEdit(Command &cmd) {
command_result ConnectedClient::handleCommandClientEdit(ts::Command &cmd) {
CMD_REQ_SERVER;
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
return this->handleCommandClientEdit(cmd, client);
return this->handleCommandClientEdit(cmd, client.client);
}
command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std::shared_ptr<ConnectedClient>& client) {
@ -657,14 +657,14 @@ command_result ConnectedClient::handleCommandClientMute(Command &cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
for(const auto& weak : this->mutedClients)
if(weak.lock() == client) return command_result{error::ok};
this->mutedClients.push_back(client);
this->mutedClients.push_back(client.client);
}
if (config::voice::notifyMuted)
@ -677,12 +677,12 @@ command_result ConnectedClient::handleCommandClientUnmute(Command &cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
this->mutedClients.erase(std::remove_if(this->mutedClients.begin(), this->mutedClients.end(), [client](const weak_ptr<ConnectedClient>& weak) {
this->mutedClients.erase(std::remove_if(this->mutedClients.begin(), this->mutedClients.end(), [&](const weak_ptr<ConnectedClient>& weak) {
auto c = weak.lock();
return !c || c == client;
}), this->mutedClients.end());
@ -1119,7 +1119,7 @@ command_result ConnectedClient::handleCommandClientInfo(Command &cmd) {
auto client_id = cmd[index]["clid"].as<ClientId>();
if(client_id == 0) continue;
auto client = this->server->findClient(client_id);
ConnectedLockedClient client{this->server->find_client_by_id(client_id)};
if(!client) {
trigger_error = true;
continue;

View File

@ -228,6 +228,9 @@ command_result ConnectedClient::handleCommand(Command &cmd) {
else if (command == "playlistpermlist") return this->handleCommandPlaylistPermList(cmd);
else if (command == "playlistaddperm") return this->handleCommandPlaylistAddPerm(cmd);
else if (command == "playlistdelperm") return this->handleCommandPlaylistDelPerm(cmd);
else if (command == "playlistclientpermlist") return this->handleCommandPlaylistClientPermList(cmd);
else if (command == "playlistclientaddperm") return this->handleCommandPlaylistClientAddPerm(cmd);
else if (command == "playlistclientdelperm") return this->handleCommandPlaylistClientDelPerm(cmd);
else if (command == "playlistinfo") return this->handleCommandPlaylistInfo(cmd);
else if (command == "playlistedit") return this->handleCommandPlaylistEdit(cmd);
@ -256,13 +259,13 @@ command_result ConnectedClient::handleCommandGetConnectionInfo(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
bool send_temp;
auto info = client->request_connection_info(_this.lock(), send_temp);
if (info) {
this->notifyConnectionInfo(client, info);
this->notifyConnectionInfo(client.client, info);
} else if(send_temp) {
return command_result{error::no_cached_connection_info};
}
@ -489,7 +492,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
auto timestamp = system_clock::now();
if (cmd["targetmode"].as<ChatMessageMode>() == ChatMessageMode::TEXTMODE_PRIVATE) {
auto target = this->server->findClient(cmd["target"].as<ClientId>());
ConnectedLockedClient target{this->server->find_client_by_id(cmd["target"].as<ClientId>())};
if (!target) return command_result{error::client_invalid_id};
bool chat_open = false;
@ -506,24 +509,24 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
}
if(!chat_open) {
if (target == this)
if (target.client == this)
ACTION_REQUIRES_PERMISSION(permission::b_client_even_textmessage_send, 1, this->getChannelId());
if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()), false))
return command_result{permission::i_client_private_textmessage_power};
{
unique_lock channel_lock(target->channel_lock);
unique_lock channel_lock(target->get_channel_lock());
target->openChats.push_back(_this);
}
{
unique_lock channel_lock(this->channel_lock);
this->openChats.push_back(target);
this->openChats.push_back(target.client);
}
}
if(this->handleTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, cmd["msg"], target)) return command_result{error::ok};
if(this->handleTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, cmd["msg"], target.client)) return command_result{error::ok};
target->notifyTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, _this.lock(), target->getClientId(), 0, timestamp, cmd["msg"].string());
this->notifyTextMessage(ChatMessageMode::TEXTMODE_PRIVATE, _this.lock(), target->getClientId(), 0, timestamp, cmd["msg"].string());
} else if (cmd["targetmode"] == ChatMessageMode::TEXTMODE_CHANNEL) {
@ -809,7 +812,7 @@ command_result ConnectedClient::handleCommandBanClient(Command &cmd) {
if(client->getType() == ClientType::CLIENT_MUSIC)
return command_result{error::client_invalid_id, "You cant ban a music bot!"};
} else {
target_clients = {this->server->findClient(cmd["clid"].as<ClientId>())};
target_clients = {this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if(!target_clients[0]) {
return command_result{error::client_invalid_id, "Could not find target client"};
}
@ -855,7 +858,7 @@ command_result ConnectedClient::handleCommandBanClient(Command &cmd) {
if (client->getType() != CLIENT_TEAMSPEAK && client->getType() != CLIENT_QUERY) continue; //Remember if you add new type you have to change stuff here
this->server->notify_client_ban(client, this->ref(), reason, time);
client->closeConnection(system_clock::now() + seconds(2));
client->close_connection(system_clock::now() + seconds(2));
string entry_name, entry_ip, entry_hardware_id;
if(b_ban_name && !no_nickname) {
@ -1108,8 +1111,8 @@ command_result ConnectedClient::handleCommandPluginCmd(Command &cmd) {
} else if (mode == PluginTargetMode::PLUGINCMD_CLIENT) {
for (int index = 0; index < cmd.bulkCount(); index++) {
auto target = cmd[index]["target"].as<ClientId>();
auto cl = this->server->findClient(target);
if (!cl) return command_result{error::client_invalid_id, "invalid target id"};
ConnectedLockedClient cl{this->server->find_client_by_id(target)};
if (!cl) return command_result{error::client_invalid_id};
cl->notifyPluginCmd(cmd["name"], cmd["data"], _this.lock());
}
}

View File

@ -296,16 +296,11 @@ command_result ConnectedClient::handleCommandPlaylistList(ts::Command &cmd) {
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto self_dbid = this->getClientDatabaseId();
auto playlist_view_power = this->calculate_permission(permission::i_playlist_view_power, 0);
auto self_ref = this->ref();
auto playlists = this->server->musicManager->playlists();
playlists.erase(find_if(playlists.begin(), playlists.end(), [&](const shared_ptr<music::PlayablePlaylist>& playlist) {
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] == self_dbid)
return false;
auto needed_view_power = playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power);
return !permission::v2::permission_granted(needed_view_power, playlist_view_power, false);;
return playlist->client_has_permissions(self_ref, permission::i_playlist_needed_view_power, permission::i_playlist_view_power, music::PlaylistPermissions::do_no_require_granted) != permission::ok;
}), playlists.end());
if(playlists.empty())
@ -322,12 +317,25 @@ command_result ConnectedClient::handleCommandPlaylistList(ts::Command &cmd) {
notify[index]["playlist_type"] = entry->properties()[property::PLAYLIST_TYPE].value();
notify[index]["playlist_owner_dbid"] = entry->properties()[property::PLAYLIST_OWNER_DBID].value();
notify[index]["playlist_owner_name"] = entry->properties()[property::PLAYLIST_OWNER_NAME].value();
notify[index]["needed_power_modify"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_modify_power);
notify[index]["needed_power_permission_modify"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power);
notify[index]["needed_power_delete"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_delete_power);
notify[index]["needed_power_song_add"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_add_power);
notify[index]["needed_power_song_move"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_move_power);
notify[index]["needed_power_song_remove"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_remove_power);
auto permissions = entry->permission_manager();
auto permission = permissions->permission_value_flagged(permission::i_playlist_needed_modify_power);
notify[index]["needed_power_modify"] = permission.has_value ? permission.value : 0;
permission = permissions->permission_value_flagged(permission::i_playlist_needed_permission_modify_power);
notify[index]["needed_power_permission_modify"] = permission.has_value ? permission.value : 0;
permission = permissions->permission_value_flagged(permission::i_playlist_needed_delete_power);
notify[index]["needed_power_delete"] = permission.has_value ? permission.value : 0;
permission = permissions->permission_value_flagged(permission::i_playlist_song_needed_add_power);
notify[index]["needed_power_song_add"] = permission.has_value ? permission.value : 0;
permission = permissions->permission_value_flagged(permission::i_playlist_song_needed_move_power);
notify[index]["needed_power_song_move"] = permission.has_value ? permission.value : 0;
permission = permissions->permission_value_flagged(permission::i_playlist_song_needed_remove_power);
notify[index]["needed_power_song_remove"] = permission.has_value ? permission.value : 0;
index++;
}
@ -363,19 +371,19 @@ command_result ConnectedClient::handleCommandPlaylistCreate(ts::Command &cmd) {
auto power = this->calculate_permission(permission::i_playlist_song_remove_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_song_needed_remove_power, power.value, nullptr);
playlist->permission_manager()->set_permission(permission::i_playlist_song_needed_remove_power, {power.value, 0}, permission::v2::set_value, permission::v2::do_nothing);
power = this->calculate_permission(permission::i_playlist_delete_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_delete_power, power.value, nullptr);
playlist->permission_manager()->set_permission(permission::i_playlist_needed_delete_power, {power.value, 0}, permission::v2::set_value, permission::v2::do_nothing);
power = this->calculate_permission(permission::i_playlist_modify_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_modify_power, power.value, nullptr);
playlist->permission_manager()->set_permission(permission::i_playlist_needed_modify_power, {power.value, 0}, permission::v2::set_value, permission::v2::do_nothing);
power = this->calculate_permission(permission::i_playlist_permission_modify_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_permission_modify_power, power.value, nullptr);
playlist->permission_manager()->set_permission(permission::i_playlist_needed_permission_modify_power, {power.value, 0}, permission::v2::set_value, permission::v2::do_nothing);
Command notify(this->notify_response_command("notifyplaylistcreated"));
notify["playlist_id"] = playlist->playlist_id();
@ -392,8 +400,8 @@ command_result ConnectedClient::handleCommandPlaylistDelete(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_delete_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_delete_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_delete_power, permission::i_playlist_delete_power); perr)
return command_result{perr};
string error;
if(!ref_server->musicManager->delete_playlist(playlist->playlist_id(), error)) {
@ -412,8 +420,8 @@ command_result ConnectedClient::handleCommandPlaylistInfo(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power, music::PlaylistPermissions::do_no_require_granted); perr)
return command_result{perr};
Command notify(this->notify_response_command("notifyplaylistinfo"));
@ -433,8 +441,8 @@ command_result ConnectedClient::handleCommandPlaylistEdit(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_modify_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_modify_power, permission::i_playlist_modify_power); perr)
return command_result{perr};
deque<pair<shared_ptr<property::PropertyDescription>, string>> properties;
@ -491,28 +499,41 @@ command_result ConnectedClient::handleCommandPlaylistPermList(ts::Command &cmd)
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_playlist_permission_list, 1);
{
auto value = playlist->calculate_client_specific_permissions(permission::b_virtualserver_playlist_permission_list, this->ref());
if(!permission::v2::permission_granted(1, value))
return command_result{permission::b_virtualserver_playlist_permission_list};
}
auto permissions = playlist->permissions()->listPermissions(PERM_FLAG_PUBLIC);
auto permissions = playlist->permission_manager()->permissions();
if(permissions.empty())
return command_result{error::vs_critical};
return command_result{error::database_empty_result};
Command result(this->notify_response_command("notifyplaylistpermlist"));
auto permission_mapper = serverInstance->getPermissionMapper();
auto perm_sid = cmd.hasParm("permsid") || cmd.hasParm("names");
int index = 0;
result["playlist_id"] = playlist->playlist_id();
for (const auto &elm : permissions) {
if(elm->hasValue()) {
result[index]["permid"] = elm->type->type;
for (const auto &[perm, value] : permissions) {
if(value.flags.value_set) {
if (perm_sid)
result[index]["permsid"] = permission_mapper->permission_name(this->getType(), perm);
else
result[index]["permid"] = perm;
result[index]["permvalue"] = elm->value;
result[index]["permnegated"] = elm->flag_negate;
result[index]["permskip"] = elm->flag_skip;
result[index]["permvalue"] = value.values.value;
result[index]["permnegated"] = value.flags.negate;
result[index]["permskip"] = value.flags.skip;
index++;
}
if(elm->hasGrant()) {
result[index]["permid"] = (uint16_t) (elm->type->type | PERM_ID_GRANT);
result[index]["permvalue"] = elm->granted;
if(value.flags.grant_set) {
if (perm_sid)
result[index]["permsid"] = permission_mapper->permission_name_grant(this->getType(), perm);
else
result[index]["permid"] = perm | PERM_ID_GRANT;
result[index]["permvalue"] = value.values.grant;
result[index]["permnegated"] = 0;
result[index]["permskip"] = 0;
index++;
@ -531,8 +552,8 @@ command_result ConnectedClient::handleCommandPlaylistAddPerm(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_permission_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_permission_modify_power, permission::i_playlist_permission_modify_power); perr)
return command_result{perr};
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
@ -556,10 +577,9 @@ command_result ConnectedClient::handleCommandPlaylistAddPerm(ts::Command &cmd) {
}
if (grant) {
playlist->permissions()->setPermissionGranted(permType, cmd[index]["permvalue"], nullptr);
playlist->permission_manager()->set_permission(permType, {0, cmd[index]["permvalue"]}, permission::v2::do_nothing, permission::v2::set_value);
} else {
playlist->permissions()->setPermission(permType, cmd[index]["permvalue"], nullptr, cmd[index]["permskip"], cmd[index]["permnegated"]);
playlist->permission_manager()->set_permission(permType, {cmd[index]["permvalue"],0}, permission::v2::set_value, permission::v2::do_nothing, cmd[index]["permskip"].as<bool>(), cmd[index]["permnegated"].as<bool>());
}
}
@ -574,8 +594,8 @@ command_result ConnectedClient::handleCommandPlaylistDelPerm(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_permission_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_permission_modify_power, permission::i_playlist_permission_modify_power); perr)
return command_result{perr};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
bool conOnError = cmd[0].has("continueonerror");
@ -588,10 +608,154 @@ command_result ConnectedClient::handleCommandPlaylistDelPerm(ts::Command &cmd) {
return command_result{permission::i_permission_modify_power};
}
if (grant) {
playlist->permissions()->setPermissionGranted(permType, permNotGranted, nullptr);
playlist->permission_manager()->set_permission(permType, {0, 0}, permission::v2::do_nothing, permission::v2::delete_value);
} else {
playlist->permissions()->deletePermission(permType, nullptr);
playlist->permission_manager()->set_permission(permType, {0, 0}, permission::v2::delete_value, permission::v2::do_nothing);
}
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistClientPermList(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
{
auto value = playlist->calculate_client_specific_permissions(permission::b_virtualserver_playlist_permission_list, this->ref());
if(!permission::v2::permission_granted(1, value))
return command_result{permission::b_virtualserver_playlist_permission_list};
}
auto permissions = playlist->permission_manager()->channel_permissions();
if(permissions.empty())
return command_result{error::database_empty_result};
Command result(this->notify_response_command("notifyplaylistclientpermlist"));
auto client_id = cmd.hasParm("cldbid") ? cmd[0]["cldbid"].as<ClientDbId>() : 0;
auto permission_mapper = serverInstance->getPermissionMapper();
auto perm_sid = cmd.hasParm("permsid") || cmd.hasParm("names");
int index = 0;
ClientDbId last_client_id{0};
result["playlist_id"] = playlist->playlist_id();
result["cldbid"] = client_id;
for (const auto &[perm, client, value] : permissions) {
if(client_id > 0 && client != client_id) continue;
if(last_client_id != client)
result[index]["cldbid"] = client;
if(value.flags.value_set) {
if (perm_sid)
result[index]["permsid"] = permission_mapper->permission_name(this->getType(), perm);
else
result[index]["permid"] = perm;
result[index]["permvalue"] = value.values.value;
result[index]["permnegated"] = value.flags.negate;
result[index]["permskip"] = value.flags.skip;
index++;
}
if(value.flags.grant_set) {
if (perm_sid)
result[index]["permsid"] = permission_mapper->permission_name_grant(this->getType(), perm);
else
result[index]["permid"] = perm | PERM_ID_GRANT;
result[index]["permvalue"] = value.values.grant;
result[index]["permnegated"] = 0;
result[index]["permskip"] = 0;
index++;
}
}
if(index == 0)
return command_result{error::database_empty_result};
this->sendCommand(result);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistClientAddPerm(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
auto client_id = cmd[0]["cldbid"].as<ClientDbId>();
if(client_id == 0) return command_result{error::client_invalid_id};
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_permission_modify_power, permission::i_playlist_permission_modify_power); perr)
return command_result{perr};
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
bool conOnError = cmd[0].has("continueonerror");
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
auto val = cmd[index]["permvalue"].as<permission::PermissionValue>();
if(permission_require_granted_value(permType) && !permission::v2::permission_granted(val, max_value)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if(!ignore_granted_values && !permission::v2::permission_granted(val, this->calculate_permission(permType, 0, true))) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if (grant) {
playlist->permission_manager()->set_channel_permission(permType, client_id, {0, cmd[index]["permvalue"]}, permission::v2::do_nothing, permission::v2::set_value);
} else {
playlist->permission_manager()->set_channel_permission(permType, client_id, {cmd[index]["permvalue"], 0}, permission::v2::set_value, permission::v2::do_nothing, cmd[index]["permskip"].as<bool>(), cmd[index]["permnegated"].as<bool>());
}
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistClientDelPerm(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
auto client_id = cmd[0]["cldbid"].as<ClientDbId>();
if(client_id == 0) return command_result{error::client_invalid_id};
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_permission_modify_power, permission::i_playlist_permission_modify_power); perr)
return command_result{perr};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
bool conOnError = cmd[0].has("continueonerror");
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignore_granted_values && !permission::v2::permission_granted(0, this->calculate_permission(permType, 0, true))) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if (grant) {
playlist->permission_manager()->set_channel_permission(permType, client_id, {0, 0}, permission::v2::do_nothing, permission::v2::delete_value);
} else {
playlist->permission_manager()->set_channel_permission(permType, client_id, {0, 0}, permission::v2::delete_value, permission::v2::do_nothing);
}
}
@ -606,8 +770,8 @@ command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd)
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr)
return command_result{perr};
auto songs = playlist->list_songs();
if(songs.empty())
@ -640,8 +804,8 @@ command_result ConnectedClient::handleCommandPlaylistSongAdd(ts::Command &cmd) {
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_add_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_add_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_song_needed_add_power, permission::i_playlist_song_add_power); perr)
return command_result{perr};
if(!cmd[0].has("invoker"))
cmd["invoker"] = "";
@ -672,8 +836,8 @@ command_result ConnectedClient::handleCommandPlaylistSongReorder(ts::Command &cm
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_move_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_move_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_song_needed_move_power, permission::i_playlist_song_move_power); perr)
return command_result{perr};
SongId song_id = cmd["song_id"];
SongId previous_id = cmd["song_previous_song_id"];
@ -695,8 +859,8 @@ command_result ConnectedClient::handleCommandPlaylistSongRemove(ts::Command &cmd
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_remove_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_remove_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_song_needed_remove_power, permission::i_playlist_song_remove_power); perr)
return command_result{perr};
SongId song_id = cmd["song_id"];
@ -709,85 +873,63 @@ command_result ConnectedClient::handleCommandPlaylistSongRemove(ts::Command &cmd
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandMusicBotQueueList(Command& cmd) {
return command_result{error::not_implemented}; //FIXME
/*
/****** legacy ******/
command_result ConnectedClient::handleCommandMusicBotQueueList(Command& cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_info, bot->permissionValue(permission::i_client_music_needed_info, bot->currentChannel), this->currentChannel, true);
auto playlist = dynamic_pointer_cast<music::PlayablePlaylist>(bot->playlist());
if(!playlist) return command_result{error::vs_critical};
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr)
return command_result{perr};
bool bulked = cmd.hasParm("bulk") || cmd.hasParm("balk") || cmd.hasParm("pipe") || cmd.hasParm("bar") || cmd.hasParm("paypal");
int command_index = 0;
Command notify(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
{
auto history = bot->queue()->history();
for(int index = history.size(); index > 0; index--) {
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
Command notify(this->notify_response_command("notifymusicqueueentry"));
auto songs = playlist->list_songs();
int begin_index{0};
for(auto it = songs.begin(); it != songs.end(); it++)
if((*it)->id == playlist->currently_playing())
break;
else
begin_index--;
apply_song(notify, history[index - 1], command_index);
notify[command_index]["queue_index"] = -index;
if(!bulked)
this->sendCommand(notify);
else
command_index++;
}
}
{
for(auto it = songs.begin(); it != songs.end(); it++) {
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
notify = Command(this->notify_response_command("notifymusicqueueentry"));
auto song = bot->queue()->currentSong();
apply_song(notify, song, command_index);
notify[command_index]["queue_index"] = 0;
//TODO!
//apply_song(notify, *it, command_index);
notify[command_index]["queue_index"] = begin_index++;
if(!bulked)
this->sendCommand(notify);
else if(song)
else
command_index++;
}
{
auto queue = bot->queue()->queueEntries();
for(int index = 0; index < queue.size(); index++) {
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
apply_song(notify, queue[index], command_index);
notify[command_index]["queue_index"] = index + 1;
if(!bulked)
this->sendCommand(notify);
else
command_index++;
}
}
debugMessage(this->getServerId(),"Send: {}",notify.build());
if(bulked) {
if(command_index > 0) {
this->sendCommand(notify);
} else return { ErrorType::DBEmpty };
} else
return command_result{error::database_empty_result};
}
if(this->getExternalType() == CLIENT_VOICE) {
if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK) {
Command notify("notifymusicqueuefinish");
notify["bot_id"] = bot->getClientDatabaseId();
this->sendCommand(notify);
}
return command_result{error::ok};
*/
}
command_result ConnectedClient::handleCommandMusicBotQueueAdd(Command& cmd) {
@ -898,8 +1040,8 @@ command_result ConnectedClient::handleCommandMusicBotPlaylistAssign(ts::Command
if(ref_server->musicManager->find_bot_by_playlist(playlist))
return command_result{error::playlist_already_in_use};
if(playlist && playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr)
return command_result{perr};
if(!ref_server->musicManager->assign_playlist(bot, playlist))
return command_result{error::vs_critical};

View File

@ -96,7 +96,7 @@ MusicClient::~MusicClient() {
void MusicClient::sendCommand(const ts::Command &command, bool low) { }
void MusicClient::sendCommand(const ts::command_builder &command, bool low) { }
bool MusicClient::closeConnection(const std::chrono::system_clock::time_point&) {
bool MusicClient::close_connection(const std::chrono::system_clock::time_point&) {
logError(this->getServerId(), "Music manager is forced to disconnect!");
/*
@ -148,7 +148,7 @@ void MusicClient::initialize_bot() {
auto channel = this->server->getChannelTree()->findChannel(last);
if(!channel) channel = this->server->getChannelTree()->getDefaultChannel();
if(this->getClientId() == 0 || this->server->findClient(this->getClientId()) != _this.lock()) {
if(this->getClientId() == 0 || this->server->find_client_by_id(this->getClientId()) != _this.lock()) {
this->server->registerClient(_this.lock());
}
{

View File

@ -57,7 +57,7 @@ namespace ts {
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& = std::chrono::system_clock::time_point()) override;
bool close_connection(const std::chrono::system_clock::time_point& = std::chrono::system_clock::time_point()) override;
void initialize_bot();
//Music stuff

View File

@ -135,10 +135,10 @@ bool QueryClient::disconnect(const std::string &reason) {
cmd["reason"] = reason;
this->sendCommand(cmd);
}
return this->closeConnection(system_clock::now() + seconds(1));
return this->close_connection(system_clock::now() + seconds(1));
}
bool QueryClient::closeConnection(const std::chrono::system_clock::time_point& flushTimeout) {
bool QueryClient::close_connection(const std::chrono::system_clock::time_point& flushTimeout) {
auto ownLock = dynamic_pointer_cast<QueryClient>(_this.lock());
if(!ownLock) return false;
@ -285,7 +285,7 @@ void QueryClient::handleMessageWrite(int fd, short, void *) {
}
else {
logError(LOG_QUERY, "{} Failed to write message: {} ({} => {})", CLIENT_STR_LOG_PREFIX, length, errno, strerror(errno));
threads::Thread([=](){ ownLock->closeConnection(); }).detach();
threads::Thread([=](){ ownLock->close_connection(chrono::system_clock::now() + chrono::seconds{5}); }).detach();
return;
}
} else {
@ -321,12 +321,12 @@ void QueryClient::handleMessageRead(int fd, short, void *) {
logMessage(LOG_QUERY, "{} Connection closed. Client disconnected.", CLIENT_STR_LOG_PREFIX);
event_del_noblock(this->readEvent);
std::thread([ownLock]{
ownLock->closeConnection();
ownLock->close_connection();
}).detach();
} else {
logError(LOG_QUERY, "{} Failed to read! Code: {} errno: {} message: {}", CLIENT_STR_LOG_PREFIX, length, errno, strerror(errno));
event_del_noblock(this->readEvent);
threads::Thread(THREAD_SAVE_OPERATIONS, [ownLock](){ ownLock->closeConnection(); }).detach();
threads::Thread(THREAD_SAVE_OPERATIONS, [ownLock](){ ownLock->close_connection(); }).detach();
}
return;
}
@ -542,7 +542,7 @@ void QueryClient::queryTick() {
lock_guard<recursive_mutex> lock_tick(this->lock_query_tick);
if(this->idleTimestamp.time_since_epoch().count() > 0 && system_clock::now() - this->idleTimestamp > minutes(5)){
debugMessage(LOG_QUERY, "Dropping client " + this->getLoggingPeerIp() + "|" + this->getDisplayName() + ". (Timeout)");
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
}
if(this->connectionType == ConnectionType::UNKNOWN && system_clock::now() - milliseconds(500) > connectedTimestamp) {

View File

@ -29,7 +29,7 @@ namespace ts {
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool close_connection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
void disconnectFinal();
bool eventActive(QueryEventGroup, QueryEventSpecifier);

View File

@ -121,7 +121,7 @@ command_result QueryClient::handleCommand(Command& cmd) {
command_result QueryClient::handleCommandExit(Command &) {
logMessage(LOG_QUERY, "[Query] {}:{} disconnected. (Requested by client)", this->getLoggingPeerIp(), this->getPeerPort());
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
return command_result{error::ok};
}
@ -154,7 +154,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
if(this->handle->loginAttempts[this->getPeerIp()] > 3) {
this->handle->queryBann[this->getPeerIp()] = system_clock::now() + seconds(serverInstance->properties()[property::SERVERINSTANCE_SERVERQUERY_BAN_TIME].as<uint64_t>()); //TODO configurable | Disconnect all others?
this->postCommandHandler.emplace_back([&](){
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
});
return command_result{error::ban_flooding};
}

View File

@ -53,6 +53,19 @@ inline bool solvePuzzle(Puzzle *puzzle){
return true;
}
inline bool write_bin_data(mp_int& data, uint8_t* result, size_t length) {
ulong n{length};
if(auto err = mp_to_unsigned_bin_n(&data, result, &n); err)
return false;
if(n != length) {
auto off = length - n;
memcpy(result + off, result, n);
memset(result, 0, off);
}
return true;
}
void PuzzleManager::generatePuzzle() {
auto puzzle = new Puzzle{};
@ -74,12 +87,14 @@ void PuzzleManager::generatePuzzle() {
if(!valid_n || !valid_x || !valid_result)
goto generate_new;
memset(puzzle->data_x, 0, 64);
memset(puzzle->data_n, 0, 64);
memset(puzzle->data_result, 0, 64);
mp_to_unsigned_bin(&puzzle->x, puzzle->data_x);
mp_to_unsigned_bin(&puzzle->n, puzzle->data_n);
mp_to_unsigned_bin(&puzzle->result, puzzle->data_result);
if(!write_bin_data(puzzle->x, puzzle->data_x, 64))
goto generate_new;
if(!write_bin_data(puzzle->n, puzzle->data_n, 64))
goto generate_new;
if(!write_bin_data(puzzle->result, puzzle->data_result, 64))
goto generate_new;
this->cached.push_back(shared_ptr<Puzzle>(puzzle, [](Puzzle* elm){
mp_clear_multi(&elm->n, &elm->x, &elm->result, nullptr);

View File

@ -116,7 +116,7 @@ void VoiceClient::tick(const std::chrono::system_clock::time_point &time) {
this->state == ConnectionState::INIT_HIGH ? "INIT_HIGH" : "INIT_LOW",
duration_cast<seconds>(time - this->last_packet_handshake).count()
);
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
}
}
}
@ -128,115 +128,130 @@ bool VoiceClient::disconnect(const std::string &reason) {
}
bool VoiceClient::disconnect(ts::ViewReasonId reason_id, const std::string &reason, const std::shared_ptr<ts::server::ConnectedClient>& invoker, bool notify_viewer) {
/*
* We don't have to lock the disconnect lock here, because we're not really unregistering the client.
* Its only for the clients own flavour and everything which the client receives after will be ignored :)
*/
ConnectionState old_state{};
{
threads::MutexLock disconnect_lock(this->disconnectLock);
if(this->state == ConnectionState::DISCONNECTING || this->state == ConnectionState::DISCONNECTED) return false; //Already disconnecting/disconnected
std::lock_guard state_lock{this->state_lock};
if(this->state == ConnectionState::DISCONNECTING || this->state == ConnectionState::DISCONNECTED)
return false; //Already disconnecting/disconnected
old_state = this->state;
this->state = ConnectionState::DISCONNECTING;
}
Command cmd("notifyclientleftview");
cmd["reasonmsg"] = reason;
cmd["reasonid"] = reason_id;
cmd["clid"] = this->getClientId();
cmd["cfid"] = this->currentChannel ? this->currentChannel->channelId() : 0; //Failed when cid = 0????
cmd["ctid"] = 0;
if(old_state == ConnectionState::CONNECTED) {
/* Client has been successflly initialized; Send normal disconnect. */
if (invoker) {
cmd["invokerid"] = invoker->getClientId();
cmd["invokername"] = invoker->getDisplayName();
cmd["invokeruid"] = invoker->getUid();
}
Command cmd("notifyclientleftview");
cmd["reasonmsg"] = reason;
cmd["reasonid"] = reason_id;
cmd["clid"] = this->getClientId();
cmd["cfid"] = this->currentChannel ? this->currentChannel->channelId() : 0; //Failed when cid = 0????
cmd["ctid"] = 0;
if(notify_viewer && this->server) {
unique_lock channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, invoker, reason, reason_id, false, channel_lock);
if (invoker) {
cmd["invokerid"] = invoker->getClientId();
cmd["invokername"] = invoker->getDisplayName();
cmd["invokeruid"] = invoker->getUid();
}
if(notify_viewer && this->server) {
unique_lock channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, invoker, reason, reason_id, false, channel_lock);
} else {
threads::MutexLock lock(this->command_lock);
auto server_channel = dynamic_pointer_cast<ServerChannel>(this->currentChannel);
if(server_channel)
server_channel->unregister_client(_this.lock());
this->currentChannel = nullptr;
}
auto listener = make_unique<threads::Future<bool>>();
auto weak_self = this->_this;
listener->waitAndGetLater([weak_self](bool* success) {
if(weak_self.expired()) return;
auto self = weak_self.lock();
if(!self) return;
if(!success || !*success) {
debugMessage(self->getServerId(), "{} Failed to receive disconnect acknowledge!", CLIENT_STR_LOG_PREFIX_(self));
} else
debugMessage(self->getServerId(), "{} Received disconnect acknowledge!", CLIENT_STR_LOG_PREFIX_(self));
self->close_connection(chrono::system_clock::time_point{}); /* we received the ack, we do not need to flush anything */
}, system_clock::now() + seconds(5));
this->sendCommand0(cmd.build(), false, false, std::move(listener));
} else {
threads::MutexLock lock(this->command_lock);
auto server_channel = dynamic_pointer_cast<ServerChannel>(this->currentChannel);
if(server_channel)
server_channel->unregister_client(_this.lock());
this->currentChannel = nullptr;
//TODO: Extra case for INIT_HIGH?
this->close_connection(chrono::system_clock::now() + chrono::seconds{5});
}
auto listener = make_unique<threads::Future<bool>>();
auto weak_self = this->_this;
listener->waitAndGetLater([weak_self](bool* success) {
if(weak_self.expired()) return;
auto self = weak_self.lock();
if(!self || self->state != DISCONNECTING) return;
if(!success || !*success) {
debugMessage(self->getServerId(), "{} Failed to receive disconnect acknowledge!", CLIENT_STR_LOG_PREFIX_(self));
} else
debugMessage(self->getServerId(), "{} Received disconnect acknowledge!", CLIENT_STR_LOG_PREFIX_(self));
self->closeConnection();
}, system_clock::now() + seconds(5));
this->sendCommand0(cmd.build(), false, false, std::move(listener));
return true;
}
bool VoiceClient::closeConnection(const system_clock::time_point &timeout) {
bool VoiceClient::close_connection(const system_clock::time_point &timeout) {
auto self_lock = dynamic_pointer_cast<VoiceClient>(_this.lock());
assert(self_lock); //Should never happen!
threads::MutexLock disconnect_lock(this->disconnectLock);
bool flush = timeout.time_since_epoch().count() > 0;
if((this->state == ConnectionState::DISCONNECTING && flush && this->flushing_thread) || this->state == ConnectionState::DISCONNECTED){
debugMessage(this->getServerId(), "{} Tried to disconnect, but isn't connected anymore! State: {}", CLIENT_STR_LOG_PREFIX, this->state);
return false;
{
std::lock_guard state_lock{this->state_lock};
if(this->state == ConnectionState::DISCONNECTED) return false;
else if(this->state == ConnectionState::DISCONNECTING) {
/* here is nothing to pay attention for */
} else if(this->state == ConnectionState::DISCONNECTING_FLUSHING) {
if(!flush) {
this->state = ConnectionState::DISCONNECTED;
return true; /* the flush thread will execute the final disconnect */
} else {
//TODO: May update the flush timeout if its less then the other one?
return true;
}
}
this->state = flush ? ConnectionState::DISCONNECTING_FLUSHING : ConnectionState::DISCONNECTED;
}
this->state = flush ? ConnectionState::DISCONNECTING : ConnectionState::DISCONNECTED;
debugMessage(this->getServerId(), "{} Closing voice client connection. (Flush: {})", CLIENT_STR_LOG_PREFIX, flush);
if(flush) {
this->flushing_thread = std::make_shared<threads::Thread>(THREAD_SAVE_OPERATIONS | THREAD_EXECUTE_LATER, [this, self_lock, timeout](){
//We could use this here cause its locked by self_locked
//TODO: Move this out into a thread pool?
this->flushing_thread = std::make_shared<threads::Thread>(THREAD_SAVE_OPERATIONS | THREAD_EXECUTE_LATER, [this, self_lock, timeout, flush]{
{
/* Await that all commands have been processed. It does not make sense to unregister the client while command handling. */
std::lock_guard cmd_lock{this->command_lock};
}
if(flush) {
debugMessage(this->getServerId(), "{} Awaiting write prepare, write and acknowledge queue flushed", CLIENT_STR_LOG_PREFIX);
auto connection = this->getConnection();
this->getConnection()->wait_empty_write_and_prepare_queue(timeout);
debugMessage(this->getServerId(), "{} Write prepare queue progressed", CLIENT_STR_LOG_PREFIX);
while(this->state == DISCONNECTING){
while(this->state == DISCONNECTING_FLUSHING) {
if(system_clock::now() > timeout){
debugMessage(this->getServerId(), "{} Cant flush io!", CLIENT_STR_LOG_PREFIX);
auto write_queue_flushed = this->connection->wait_empty_write_and_prepare_queue(timeout);
auto acknowledge_received = connection->acknowledge_handler.awaiting_acknowledge() == 0;
if(!this->connection->wait_empty_write_and_prepare_queue(timeout)) {
debugMessage(this->getServerId(), "{} Write queue not empty!", CLIENT_STR_LOG_PREFIX);
}
{
auto reminding = connection->acknowledge_handler.awaiting_acknowledge();
if(reminding > 0)
debugMessage(this->getServerId(), "{} Could not get acknowledge for all commands before disconnecting. Acknowledges left: {}", CLIENT_STR_LOG_PREFIX, reminding);
}
if(write_queue_flushed && acknowledge_received)
break;
debugMessage(this->getServerId(), "{} Failed to flush pending messages. Acknowledges pending: {} Buffers pending: {}", CLIENT_STR_LOG_PREFIX, acknowledge_received, write_queue_flushed);
break;
}
if(!this->connection->wait_empty_write_and_prepare_queue(timeout))
continue;
{
if(connection->acknowledge_handler.awaiting_acknowledge() > 0) {
usleep(5000);
continue;
}
if(connection->acknowledge_handler.awaiting_acknowledge() > 0) {
usleep(5000);
continue;
}
debugMessage(this->getServerId(), "{} Write and acknowledge queue are flushed", CLIENT_STR_LOG_PREFIX);
break;
}
if(this->state != DISCONNECTING) return;
this->finalDisconnect();
});
flushing_thread->name("Flush thread VC").execute();
return true;
} else {
this->state = DISCONNECTED;
auto f_thread = this->flushing_thread;
if(f_thread) {
threads::NegatedMutexLock l(this->disconnectLock); //Unlock the close lock again until the flush queue has finished (may with close may by interupt)
f_thread->join();
}
this->finalDisconnect();
}
if(this->state > DISCONNECTING) /* it could happen that the client "reconnects" while flushing this shit */
this->finalDisconnect();
});
flushing_thread->name("Flush thread VC").execute();
return true;
}
@ -244,7 +259,6 @@ void VoiceClient::finalDisconnect() {
auto ownLock = dynamic_pointer_cast<VoiceClient>(_this.lock());
assert(ownLock);
threads::MutexLock disconnect_lock(this->disconnectLock);
lock_guard disconnect_lock_final(this->finalDisconnectLock);
if(this->final_disconnected) {
logError(this->getServerId(), "Tried to final disconnect {}/{} twice", this->getLoggingPeerIp() + ":" + to_string(this->getPeerPort()), this->getDisplayName());

View File

@ -50,7 +50,7 @@ namespace ts {
VoiceClient(const std::shared_ptr<VoiceServer>& server,const sockaddr_storage*);
~VoiceClient();
bool closeConnection(const std::chrono::system_clock::time_point &timeout = std::chrono::system_clock::time_point()) override;
bool close_connection(const std::chrono::system_clock::time_point &timeout) override;
bool disconnect(const std::string&) override;
bool disconnect(ViewReasonId /* reason type */, const std::string& /* reason */, const std::shared_ptr<ts::server::ConnectedClient>& /* invoker */, bool /* notify viewer */);

View File

@ -46,8 +46,8 @@ inline bool calculate_security_level(int& result, ecc_key* pubKey, size_t offset
if(shaBuffer[i] == 0) zeroBits += 8;
else break;
if(i < SHA_DIGEST_LENGTH) {
for(int bit = 0; bit < 8; bit++) {
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
for(uint8_t bit = 0; bit < 8; bit++) {
if((shaBuffer[i] & (1U << bit)) == 0) zeroBits++;
else break;
}
}
@ -78,7 +78,14 @@ command_result VoiceClient::handleCommandClientInit(Command &cmd) {
command_result VoiceClient::handleCommandClientDisconnect(Command& cmd) {
auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as<string>() : "";
this->disconnect(VREASON_SERVER_LEFT, reason, nullptr, true);
this->notifyClientLeftView(this->ref(), nullptr, VREASON_SERVER_LEFT, reason, nullptr, false); //Before we're moving us out of the channel tree!
if(this->state == CONNECTED) {
unique_lock channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, nullptr, reason, VREASON_SERVER_LEFT, true, channel_lock);
}
logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason);
this->postCommandHandler.push_back([&]{
this->close_connection(std::chrono::system_clock::now() + std::chrono::seconds{1}); /* send acknowledge and close connection */
});
return command_result{error::ok};
}

View File

@ -222,7 +222,7 @@ bool VoiceClientConnection::verify_encryption(const pipes::buffer_view &buffer /
}
void VoiceClientConnection::execute_handle_command_packets(const std::chrono::system_clock::time_point& /* scheduled */) {
if(this->client->state == ConnectionState::DISCONNECTED || !this->client->getServer())
if(this->client->state >= ConnectionState::DISCONNECTING || !this->client->getServer())
return;
//TODO: Remove the buffer_execute_lock and use the one within the this->client->handlePacketCommand method
@ -420,7 +420,7 @@ bool VoiceClientConnection::prepare_packet_for_write(vector<pipes::buffer> &resu
string error = "success";
if(packet->type().compressable() && !packet->memory_state.fragment_entry && false) {
if(packet->type().compressable() && !packet->memory_state.fragment_entry) {
packet->enable_flag(PacketFlag::Compressed);
if(!this->compress_handler.progressPacketOut(packet.get(), error)) {
logError(this->getClient()->getServerId(), "{} Could not compress outgoing packet.\nThis could cause fatal failed for the client.\nError: {}", error);
@ -627,8 +627,8 @@ bool VoiceClientConnection::wait_empty_write_and_prepare_queue(chrono::time_poin
if(until.time_since_epoch().count() != 0 && system_clock::now() > until)
return false;
};
threads::self::sleep_for(milliseconds(5));
threads::self::sleep_for(milliseconds(5));
}
return true;
}

View File

@ -25,6 +25,7 @@ inline void generate_random(uint8_t *destination, size_t length) {
ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
this->last_packet_handshake = system_clock::now();
std::unique_lock state_lock{this->state_lock};
if(this->state == ConnectionState::CONNECTED) { /* we've a reconnect */
if(system_clock::now() - this->lastPingResponse < seconds(5)) {
logMessage(this->getServerId(), "{} Client initialized session reconnect, but last ping response is not older then 5 seconds ({}). Ignoring attempt",
@ -43,20 +44,32 @@ ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
CLIENT_STR_LOG_PREFIX,
duration_cast<milliseconds>(system_clock::now() - this->lastPingResponse).count()
);
state_lock.unlock();
{
unique_lock server_channel_lock(this->server->channel_tree_lock); /* we cant get moved if this is locked! */
if(this->currentChannel) {
if(this->currentChannel)
this->server->client_move(this->ref(), nullptr, nullptr, config::messages::timeout::connection_reinitialized, ViewReasonId::VREASON_TIMEOUT, false, server_channel_lock);
}
}
this->finalDisconnect();
} else if(this->state == ConnectionState::DISCONNECTING) {
this->closeConnection(); /* executing final disconnect right now! */
state_lock.lock();
} else if(this->state >= ConnectionState::DISCONNECTING) {
state_lock.unlock();
std::shared_lock disconnect_finish{this->finalDisconnectLock}; /* await until the last disconnect has been processed */
state_lock.lock();
this->state = ConnectionState::INIT_HIGH;
} else if(this->state == ConnectionState::INIT_HIGH) {
logTrace(this->getServerId(), "{} Received a duplicated initiv. It seems like our initivexpand2 hasn't yet reached the client. The acknowledge handle should handle this issue for us.", CLIENT_STR_LOG_PREFIX);
return command_result{error::ok};
} else {
this->state = ConnectionState::INIT_HIGH;
}
state_lock.unlock();
this->connection->reset();
this->connection->register_initiv_packet();
this->state = ConnectionState::INIT_HIGH;
this->crypto.protocol_encrypted = false;
bool use_teaspeak = command.hasParm("teaspeak");

View File

@ -39,7 +39,7 @@ void WebClient::handleMessageWrite(int fd, short, void *) {
debugMessage(this->getServerId(), "[{}] Failed to write message (length {}, errno {}, message {}) Disconnecting client.", CLIENT_STR_LOG_PREFIX, written, errno, strerror(errno));
}
this->closeConnection(system_clock::now()); /* close connection in a new thread */
this->close_connection(system_clock::now()); /* close connection in a new thread */
return;
}
@ -76,7 +76,7 @@ void WebClient::handleMessageRead(int fd, short, void *) {
if(this->readEvent)
event_del_noblock(this->readEvent);
}
self_lock->closeConnection(system_clock::now()); /* direct close, but from another thread */
self_lock->close_connection(system_clock::now()); /* direct close, but from another thread */
}
return;
}

View File

@ -170,7 +170,7 @@ void WebClient::sendCommand(const ts::command_builder &command, bool low) {
#endif
}
bool WebClient::closeConnection(const std::chrono::system_clock::time_point& timeout) {
bool WebClient::close_connection(const std::chrono::system_clock::time_point& timeout) {
bool flushing = timeout.time_since_epoch().count() > 0;
auto self_lock = dynamic_pointer_cast<WebClient>(_this.lock());
@ -250,7 +250,7 @@ command_result WebClient::handleCommand(Command &command) {
if(command.command() == "clientinit") {
auto result = this->handleCommandClientInit(command);
if(result.error_code())
this->closeConnection(system_clock::now() + seconds(1));
this->close_connection(system_clock::now() + seconds(1));
return result;
}
}
@ -317,7 +317,7 @@ void WebClient::onWSDisconnected(const string& error) {
}
debugMessage(this->getServerId(), "{} WS disconnected ({}). Application data: {}", CLIENT_STR_LOG_PREFIX, close_code, message);
this->closeConnection(); //TODO?
this->close_connection(); //TODO?
}
void WebClient::onWSMessage(const pipes::WSMessage &message) {
@ -634,7 +634,7 @@ bool WebClient::disconnect(const std::string &reason) {
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);
}
return this->closeConnection(system_clock::now() + seconds(1));
return this->close_connection(system_clock::now() + seconds(1));
}
command_result WebClient::handleCommandClientInit(Command &command) {

View File

@ -29,7 +29,7 @@ namespace ts {
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool close_connection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool shouldReceiveVoice(const std::shared_ptr<ConnectedClient> &sender) override;

View File

@ -385,4 +385,17 @@ bool MusicBotManager::delete_playlist(ts::PlaylistId id, std::string &error) {
return false;
}
return true;
}
void MusicBotManager::execute_tick() {
auto vs = this->handle.lock();
if(!vs) return;
unique_lock playlist_lock(this->playlists_lock);
auto playlists = this->playlists_list;
playlist_lock.unlock();
auto db_helper = serverInstance->databaseHelper();
for(auto& playlist : playlists)
db_helper->savePlaylistPermissions(vs, playlist->playlist_id(), playlist->permission_manager());
}

View File

@ -57,6 +57,8 @@ namespace ts {
std::shared_ptr<PlayablePlaylist> create_playlist(ClientDbId /* owner */, const std::string& /* owner name */);
bool delete_playlist(PlaylistId /* id */, std::string& /* error */);
void execute_tick();
inline std::shared_ptr<server::VirtualServer> ref_server() { return this->handle.lock(); }
inline std::shared_ptr<MusicBotManager> ref() { return this->_self.lock(); }
private:

View File

@ -12,10 +12,11 @@ using namespace ts::music;
using namespace std;
using namespace std::chrono;
Playlist::Playlist(const std::shared_ptr<ts::music::MusicBotManager> &manager, const std::shared_ptr<ts::Properties> &properties, const std::shared_ptr<permission::PermissionManager>& permissions) : _properties(properties), _permissions(permissions), manager(manager) { }
Playlist::Playlist(const std::shared_ptr<ts::music::MusicBotManager> &manager, const std::shared_ptr<ts::Properties> &properties, std::shared_ptr<permission::v2::PermissionManager> permissions) :
PlaylistPermissions{std::move(permissions)}, _properties(properties), manager(manager) { }
Playlist::~Playlist() {
this->destory_tree();
this->destroy_tree();
}
void Playlist::set_self_ref(const std::shared_ptr<ts::music::Playlist> &ref) {
@ -336,7 +337,7 @@ bool Playlist::build_tree(deque<shared_ptr<PlaylistEntryInfo>> entries) {
return true;
}
void Playlist::destory_tree() {
void Playlist::destroy_tree() {
unique_lock list_lock(this->playlist_lock);
auto element = this->playlist_head;
while(element) {

View File

@ -6,6 +6,7 @@
#include <atomic>
#include <MusicPlayer.h>
#include "MusicBotManager.h"
#include "PlaylistPermissions.h"
namespace ts {
namespace server {
@ -61,7 +62,7 @@ namespace ts {
};
//TODO add some kind of play history?
class Playlist {
class Playlist : public PlaylistPermissions {
friend class MusicBotManager;
public:
struct Type {
@ -71,7 +72,7 @@ namespace ts {
};
};
Playlist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, const std::shared_ptr<permission::PermissionManager>& /* permissions */);
Playlist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
virtual ~Playlist();
void load_songs();
@ -84,13 +85,7 @@ namespace ts {
virtual bool delete_song(SongId /* song */);
virtual bool reorder_song(SongId /* song */, SongId /* new id */);
inline Properties& properties() {
return *this->_properties;
}
inline std::shared_ptr<permission::PermissionManager> permissions() {
return this->_permissions;
}
inline Properties& properties() const { return *this->_properties; }
inline PlaylistId playlist_id() {
return this->properties()[property::PLAYLIST_ID].as<PlaylistId>();
@ -110,10 +105,9 @@ namespace ts {
inline std::shared_ptr<Playlist> ref() { return std::dynamic_pointer_cast<T>(this->_self.lock()); }
protected:
virtual void set_self_ref(const std::shared_ptr<Playlist>& /* playlist */);
bool is_playlist_owner(ClientDbId database_id) const override { return this->properties()[property::PLAYLIST_OWNER_DBID].as_save<ClientDbId>() == database_id; }
std::atomic<SongId> current_id;
/* channel id's are here client database ids! */
std::shared_ptr<permission::PermissionManager> _permissions;
std::shared_ptr<Properties> _properties;
std::weak_ptr<MusicBotManager> manager;
std::weak_ptr<Playlist> _self;
@ -140,7 +134,7 @@ namespace ts {
std::deque<std::shared_ptr<PlaylistEntryInfo>> load_entries();
bool build_tree(std::deque<std::shared_ptr<PlaylistEntryInfo>> /* entries */);
void destory_tree();
void destroy_tree();
bool sql_remove(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
bool sql_add(const std::shared_ptr<PlaylistEntryInfo>& /* entry */); /* also assigns an ID */

View File

@ -10,7 +10,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::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::PermissionManager>& 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::PermissionManager>& /* permissions */);
PlayablePlaylist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, const std::shared_ptr<permission::v2::PermissionManager>& /* permissions */);
virtual ~PlayablePlaylist();
inline ReplayMode::value replay_mode() { return this->properties()[property::PLAYLIST_REPLAY_MODE].as<ReplayMode::value>(); }

View File

@ -0,0 +1,29 @@
//
// Created by wolverindev on 30.01.20.
//
#include "./PlaylistPermissions.h"
#include "../client/ConnectedClient.h"
using namespace ts;
using namespace ts::music;
PlaylistPermissions::PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> 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());
if(val.flags.value_set)
return {val.values.value, true};
return client->calculate_permission(permission, 0);
}
permission::PermissionType PlaylistPermissions::client_has_permissions(
const std::shared_ptr<server::ConnectedClient> &client, ts::permission::PermissionType needed_permission, ts::permission::PermissionType granted_permission, uint8_t flags) {
if(this->is_playlist_owner(client->getClientDatabaseId())) return permission::ok;
return permission::v2::permission_granted(
this->permission_manager()->permission_value_flagged(needed_permission),
this->calculate_client_specific_permissions(granted_permission, client),
flags & do_no_require_granted) ? permission::ok : needed_permission;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <PermissionManager.h>
namespace ts::server {
class VirtualServer;
class ConnectedClient;
}
namespace ts::music {
class PlaylistPermissions {
public:
enum permission_flags {
ignore_playlist_owner,
do_no_require_granted
};
PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> permissions);
inline const std::shared_ptr<permission::v2::PermissionManager>& 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;
virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0;
private:
};
}

View File

@ -258,7 +258,6 @@ void POWHandler::handle_puzzle_solve(const std::shared_ptr<ts::server::POWHandle
/* validate data */
{
/* should we validate x,n and level as well? */
if(memcmp(client->rsa_challenge->data_result, &buffer[4 + 1 + 2 * 64 + 04 + 100], 64) != 0) {
#ifdef POW_ERROR
debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client", net::to_string(client->address));
@ -302,7 +301,7 @@ shared_ptr<VoiceClient> POWHandler::register_verified_client(const std::shared_p
voice_client->initialize();
voice_client->socket = client->socket;
voice_client->state = ConnectionState::INIT_HIGH;
voice_client->state = ConnectionState::INIT_LOW;
memcpy(&voice_client->address_info, &client->address_info, sizeof(client->address_info));
{

View File

@ -95,7 +95,6 @@ bool VoiceServer::start(const std::deque<std::shared_ptr<VoiceServerBinding>>& b
if(bindings.empty()) {
error = "Failed to bind any address!";
this->running = false;
this->bindings.empty();
return false;
}
@ -162,13 +161,14 @@ void VoiceServer::execute_resend(const std::chrono::system_clock::time_point &no
if(client->state == ConnectionState::CONNECTED) {
client->disconnect(ViewReasonId::VREASON_TIMEOUT, config::messages::timeout::packet_resend_failed, nullptr, true);
} else {
client->closeConnection(system_clock::now() + seconds(1));
client->close_connection(system_clock::now() + seconds(1));
}
} else if(!buffers.empty()) {
{
lock_guard client_write_lock(connection->write_queue_lock);
connection->write_queue.insert(connection->write_queue.end(), buffers.begin(), buffers.end());
}
//logTrace(client->getServerId(), "{} Resending {} packets.", CLIENT_STR_LOG_PREFIX_(client), buffers.size());
buffers.clear();
connection->triggerWrite();
}
@ -183,7 +183,7 @@ bool VoiceServer::stop(const std::chrono::milliseconds& flushTimeout) {
auto list = this->activeConnections;
this->connectionLock.unlock();
for(const auto &e : list)
e->closeConnection(system_clock::now() + seconds(1));
e->close_connection(system_clock::now() + seconds(1));
auto beg = system_clock::now();
while(!this->activeConnections.empty() && flushTimeout.count() != 0 && system_clock::now() - beg < flushTimeout)
@ -332,7 +332,7 @@ void VoiceServer::handleMessageRead(int fd, short events, void *_event_handle) {
} else {
auto client_id = (ClientId) be2le16(&raw_read_buffer[10]);
if(client_id > 0) {
client = dynamic_pointer_cast<VoiceClient>(voice_server->server->findClient(client_id));
client = dynamic_pointer_cast<VoiceClient>(voice_server->server->find_client_by_id(client_id));
} else {
client = voice_server->findClient(&remote_address, true);
}

View File

@ -189,7 +189,7 @@ void WebControlServer::stop() {
this->clientLock.unlock();
for(const auto& e : clList) {
e->closeConnection(system_clock::now());
e->close_connection(system_clock::now());
}

View File

@ -230,11 +230,12 @@ namespace terminal {
break;
case ChatMessageMode::TEXTMODE_PRIVATE:
{
auto client = server->findClient(cmd.arguments[2].as<ClientId>());
ConnectedLockedClient<ConnectedClient> client{server->find_client_by_id(cmd.arguments[2].as<ClientId>())};
if(!client){
logError("Cloud not find manager from clid");
return false;
}
client->notifyTextMessage(ChatMessageMode::TEXTMODE_CHANNEL, server->getServerRoot(), client->getClientId(), 0, system_clock::now(), message);
}
break;

2
shared

@ -1 +1 @@
Subproject commit a8843f53113f814e7218f76683190072851b17df
Subproject commit 04666982d937a1f14fe7fff22aa735afe7563525