A lot of updates
This commit is contained in:
parent
fe05c63882
commit
543e6b1abc
@ -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)
|
||||
|
@ -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();
|
||||
}
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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)",
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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());
|
||||
}
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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};
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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 */);
|
||||
|
||||
|
@ -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};
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -386,3 +386,16 @@ bool MusicBotManager::delete_playlist(ts::PlaylistId id, std::string &error) {
|
||||
}
|
||||
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());
|
||||
}
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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>(); }
|
||||
|
29
server/src/music/PlaylistPermissions.cpp
Normal file
29
server/src/music/PlaylistPermissions.cpp
Normal 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;
|
||||
}
|
30
server/src/music/PlaylistPermissions.h
Normal file
30
server/src/music/PlaylistPermissions.h
Normal 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:
|
||||
};
|
||||
}
|
@ -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));
|
||||
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
2
shared
@ -1 +1 @@
|
||||
Subproject commit a8843f53113f814e7218f76683190072851b17df
|
||||
Subproject commit 04666982d937a1f14fe7fff22aa735afe7563525
|
Loading…
x
Reference in New Issue
Block a user