diff --git a/CMakeLists.txt b/CMakeLists.txt index dd0a5b0..a7aef66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(TEASPEAK_SERVER ON) #end now #set(MEMORY_DEBUG_FLAGS " -fsanitize=leak -fsanitize=address -fstack-protector-all ") #set(MEMORY_DEBUG_FLAGS "-fsanitize=address -fstack-protector-all") -set(MEMORY_DEBUG_FLAGS "-fstack-protector-all") +#set(MEMORY_DEBUG_FLAGS "-fstack-protector-all") if (NOT BUILD_OS_ARCH) set(BUILD_OS_ARCH $ENV{build_os_arch}) diff --git a/git-teaspeak b/git-teaspeak index 3a9c535..8e90036 160000 --- a/git-teaspeak +++ b/git-teaspeak @@ -1 +1 @@ -Subproject commit 3a9c5359719d893a35646191389c17338460535a +Subproject commit 8e90036a3759183ee4d620a5ec294167dec8eece diff --git a/server/src/client/ConnectedClient.h b/server/src/client/ConnectedClient.h index 22f1a34..40946fe 100644 --- a/server/src/client/ConnectedClient.h +++ b/server/src/client/ConnectedClient.h @@ -309,7 +309,7 @@ namespace ts { } inline bool playlist_subscribed(const std::shared_ptr& playlist) const { - return this->_subscribed_playlist.lock() == playlist; + return this->subscribed_playlist_.lock() == playlist; } protected: std::weak_ptr _this; @@ -378,7 +378,7 @@ namespace ts { std::weak_ptr selectedBot; std::weak_ptr subscribed_bot; - std::weak_ptr _subscribed_playlist{}; + std::weak_ptr subscribed_playlist_{}; bool loadDataForCurrentServer() override; @@ -541,7 +541,7 @@ namespace ts { command_result handleCommandMusicBotQueueList(Command&); command_result handleCommandMusicBotQueueAdd(Command&); - command_result handleCommandMusicBotQueueRemove(Command&); + command_result handleCommandMusicBotQcueueRemove(Command&); command_result handleCommandMusicBotQueueReorder(Command&); command_result handleCommandMusicBotPlaylistAssign(Command&); diff --git a/server/src/client/command_handler/misc.cpp b/server/src/client/command_handler/misc.cpp index 387f926..a55d9da 100644 --- a/server/src/client/command_handler/misc.cpp +++ b/server/src/client/command_handler/misc.cpp @@ -2866,6 +2866,7 @@ command_result ConnectedClient::handleCommandListFeatureSupport(ts::Command &cmd REGISTER_FEATURE("log-query", FeatureSupportMode::FULL, 1); REGISTER_FEATURE("whisper-echo", FeatureSupportMode::FULL, 1); REGISTER_FEATURE("video", FeatureSupportMode::EXPERIMENTAL, 1); + REGISTER_FEATURE("sidebar-mode", FeatureSupportMode::FULL, 1); this->sendCommand(notify); return command_result{error::ok}; diff --git a/server/src/client/command_handler/music.cpp b/server/src/client/command_handler/music.cpp index c15379e..abf3ae3 100644 --- a/server/src/client/command_handler/music.cpp +++ b/server/src/client/command_handler/music.cpp @@ -284,11 +284,13 @@ command_result ConnectedClient::handleCommandMusicBotPlayerAction(Command& cmd) bot->rewindSong(); } else if(cmd["action"] == 5) { if(!player) return command_result{error::music_no_player}; - player->forward(::music::PlayerUnits(cmd["units"].as())); + player->forward(::music::PlayerUnits{(int64_t) cmd["units"].as()}); } else if(cmd["action"] == 6) { if(!player) return command_result{error::music_no_player}; - player->rewind(::music::PlayerUnits(cmd["units"].as())); - } else return command_result{error::music_invalid_action}; + player->rewind(::music::PlayerUnits{(int64_t) cmd["units"].as()}); + } else { + return command_result{error::music_invalid_action}; + } return command_result{error::ok}; } @@ -799,7 +801,7 @@ inline void fill_song_info(ts::command_builder_bulk bulk, const std::shared_ptr< if(extract_metadata && song->metadata.is_loaded() && metadata) { bulk.put("song_metadata_title", metadata->title); bulk.put("song_metadata_description", metadata->description); - bulk.put("song_metadata_url", metadata->url); + bulk.put("song_metadata_url", metadata->url); /* Internally resolved URL. Should not be externally used */ bulk.put("song_metadata_length", metadata->length.count()); if(auto thumbnail = static_pointer_cast<::music::ThumbnailUrl>(metadata->thumbnail); thumbnail && thumbnail->type() == ::music::THUMBNAIL_URL) { bulk.put("song_metadata_thumbnail_url", thumbnail->url()); @@ -836,7 +838,7 @@ command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd) } fill_song_info(result.bulk(index), song, extract_metadata); - if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK && result.current_size() + estimated_song_info_size(song, extract_metadata) > 128 * 1024) { + if(this->getType() != ClientType::CLIENT_QUERY && result.current_size() + estimated_song_info_size(song, extract_metadata) > 64 * 1024) { this->sendCommand(result); result.reset(); index = 0; @@ -844,9 +846,13 @@ command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd) index++; } } - if(index > 0) + + if(index > 0) { this->sendCommand(result); - if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK) { + } + + /* This step is actiually not really needed... */ + if(this->getType() != ClientType::CLIENT_QUERY) { ts::command_builder finish{"notifyplaylistsonglistfinished"}; finish.put(0, "playlist_id", playlist->playlist_id()); this->sendCommand(finish); @@ -1137,8 +1143,9 @@ command_result ConnectedClient::handleCommandMusicBotPlaylistAssign(ts::Command auto bot = ref_server->music_manager_->findBotById(cmd["bot_id"]); if(!bot) return command_result{error::music_invalid_id}; - if(bot->getOwner() != this->getClientDatabaseId()) + if(bot->getOwner() != this->getClientDatabaseId()) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_music_play_power, bot->calculate_permission(permission::i_client_music_needed_play_power, 0)); + } auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]); if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id}; @@ -1163,20 +1170,24 @@ command_result ConnectedClient::handleCommandPlaylistSetSubscription(ts::Command if(!config::music::enabled) return command_result{error::music_disabled}; auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]); - if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id}; + if(!playlist && cmd["playlist_id"] != 0) { + return command_result{error::playlist_invalid_id}; + } { - auto old_playlist = this->_subscribed_playlist.lock(); - if(old_playlist) + auto old_playlist = this->subscribed_playlist_.lock(); + if(old_playlist) { old_playlist->remove_subscriber(_this.lock()); + } } if(playlist) { - if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr) + 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}; + } playlist->add_subscriber(_this.lock()); - this->_subscribed_playlist = playlist; + this->subscribed_playlist_ = playlist; } return command_result{error::ok}; diff --git a/server/src/client/music/MusicQueue.cpp b/server/src/client/music/MusicQueue.cpp deleted file mode 100644 index 1001cf6..0000000 --- a/server/src/client/music/MusicQueue.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include "MusicQueue.h" -#include "MusicClient.h" - -using namespace ts; -using namespace ts::server; -using namespace ts::music; -using namespace ::music; -using namespace std; -using namespace std::chrono; - -MusicQueue::MusicQueue(ts::server::MusicClient* self) { - this->handle = self; -} - -MusicQueue::~MusicQueue() {} - -std::shared_ptr MusicQueue::currentSong() { - return this->current; -} - -void MusicQueue::notifySongEnded() { - if(this->currentSong()) { - this->getNextSong(); - } -} - -void MusicQueue::notifySongAbort() { - this->getNextSong(); //TODO retry count! -} - -std::shared_ptr MusicQueue::rewind() { - threads::MutexLock lock(this->lock); - - if(this->current) - this->queue.push_front(std::move(this->current)); - if(!this->_history.empty()) { - this->current = dynamic_pointer_cast(this->_history.front()); - this->_history.pop_front(); - } - - return this->current; -} - -std::shared_ptr MusicQueue::getNextSong() { - threads::MutexLock lock(this->lock); - if(this->current) { - this->_history.push_front(this->current); - for(int index = 10; index < this->_history.size(); index++) { //Last ten songs full cache! - if(!dynamic_pointer_cast(this->_history[index])) break; - - auto element = this->_history[index]; - this->_history[index] = make_shared(element->getUrl(), element->getInvoker(), element->getSongId()); - } - } - - if(this->queue.empty()) this->current = nullptr; - else { - this->current = this->queue.front(); - this->queue.pop_front(); - } - return this->current; -} - -std::shared_ptr MusicQueue::find_queue(ts::SongId id) { - threads::MutexLock lock(this->lock); - for(const auto& element : this->queue) - if(element->getSongId() == id) - return element; - return nullptr; -} - -std::shared_ptr MusicQueue::find(ts::SongId id) { - threads::MutexLock lock(this->lock); - for(const auto& element : this->queue) - if(element->getSongId() == id) - return element; - for(const auto& element : this->_history) - if(element->getSongId() == id) - return element; - if(this->current && this->current->getSongId() == id) - return this->current; - - return nullptr; -} - -std::deque> MusicQueue::queueEntries() { - return this->queue; -} - -std::deque> MusicQueue::history() { - return this->_history; -} - -bool MusicQueue::deleteEntry(const std::shared_ptr& entry) { - if(!entry) return false; - - threads::MutexLock lock(this->lock); - auto found = std::find(this->queue.begin(), this->queue.end(), entry); - if(found == this->queue.end()) return false; - this->queue.erase(found); - return true; -} - -int MusicQueue::changeOrder(const std::shared_ptr& entry, int position) { - threads::MutexLock lock(this->lock); - auto found = std::find(this->queue.begin(), this->queue.end(), entry); - if(found == this->queue.end()) return -1; - this->queue.erase(found); - - if(position < 0) position = (int) this->queue.size(); - if(position > this->queue.size()) position = (int) this->queue.size(); - this->queue.insert(this->queue.begin(), entry); - return position; -} - -std::shared_ptr MusicQueue::insertEntry(const std::string &url, const tsclient &invoker, const std::shared_ptr &loader) { - auto entry = PlayableSong::create({ - 0, - url, - invoker ? invoker->getClientDatabaseId() : 0 - }, loader); - { - entry->set_song_id(this->song_id_index++); - threads::MutexLock lock(this->lock); - this->queue.push_back(entry); - } - - entry->get_loader(this->handle->getServer(), true); - return entry; -} \ No newline at end of file diff --git a/server/src/client/music/MusicQueue.h b/server/src/client/music/MusicQueue.h deleted file mode 100644 index 59349f4..0000000 --- a/server/src/client/music/MusicQueue.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "../ConnectedClient.h" -#include "Song.h" -#include - -#include - -namespace ts { - namespace server { - class MusicClient; - } - - namespace music { - class MusicHistoryEntry : public SongInfo { - public: - MusicHistoryEntry(std::string url, ClientDbId invoker, ts::SongId songId) : url(std::move(url)), invoker(invoker), id(songId) {} - - std::string getUrl() const override { return this->url; } - ts::ClientDbId getInvoker() const override { return this->invoker; } - ts::SongId getSongId() const override { return this->id; } - private: - ts::SongId id; - std::string url; - ts::ClientDbId invoker; - }; - - class MusicQueue { - public: - MusicQueue(server::MusicClient*); - ~MusicQueue(); - - std::shared_ptr currentSong(); - std::deque> queueEntries(); - std::deque> history(); //near to past - - std::shared_ptr rewind(); - std::shared_ptr getNextSong(); - std::shared_ptr find_queue(ts::SongId); - std::shared_ptr find(ts::SongId); - - bool deleteEntry(const std::shared_ptr&); - int changeOrder(const std::shared_ptr&, int position); - - std::shared_ptr insertEntry(const std::string& url, const tsclient& invoker, const std::shared_ptr& loader = nullptr); - - - void notifySongEnded(); - void notifySongAbort(); - private: - server::MusicClient* handle; - - threads::Mutex lock; - std::shared_ptr current; - std::deque> queue; - uint32_t song_id_index = 1; - - std::deque> _history; - }; - } -} \ No newline at end of file diff --git a/server/src/music/MusicPlaylist.cpp b/server/src/music/MusicPlaylist.cpp index 5be44f3..8199653 100644 --- a/server/src/music/MusicPlaylist.cpp +++ b/server/src/music/MusicPlaylist.cpp @@ -61,8 +61,9 @@ std::shared_ptr Playlist::playlist_find(const std::unique_lockentry); - if(current->entry->song_id == id) + if(current->entry->song_id == id) { return current; + } current = current->next_song; } @@ -186,8 +187,8 @@ bool Playlist::sql_apply_changes(const std::shared_ptrplaylist_lock); - deque> changed_entries; + std::unique_lock list_lock{this->playlist_mutex}; + std::deque> changed_entries; auto head = this->playlist_head; while(head) { if(head->modified) { @@ -290,10 +291,11 @@ std::deque> Playlist::load_entries() { bool Playlist::build_tree(deque> entries) { this->playlist_head = nullptr; - if(entries.empty()) + if(entries.empty()) { return true; + } - unique_lock list_lock(this->playlist_lock); + std::unique_lock list_lock{this->playlist_mutex}; auto find_entry = [&](SongId id) -> shared_ptr { for(const auto& entry : entries) if(entry->song_id == id) @@ -322,14 +324,16 @@ bool Playlist::build_tree(deque> entries) { this->playlist_head = entry; } else { - if(head->modified) + if(head->modified) { entry->set_previous_song(current_tail); - else + } else { entry->previous_song = current_tail; + } } - if(current_tail) + if(current_tail) { current_tail->next_song = entry; + } current_tail = entry; head = head->next; @@ -339,7 +343,7 @@ bool Playlist::build_tree(deque> entries) { } void Playlist::destroy_tree() { - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); auto element = this->playlist_head; while(element) { element->entry = nullptr; @@ -352,7 +356,7 @@ void Playlist::destroy_tree() { } std::deque> Playlist::list_songs() { - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); return this->_list_songs(list_lock); } @@ -371,7 +375,7 @@ std::deque> Playlist::_list_songs(const std:: } std::shared_ptr Playlist::find_song(ts::SongId id) { - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); auto head = this->playlist_head; while(head) { if(head->entry->song_id == id) @@ -389,7 +393,7 @@ std::shared_ptr Playlist::add_song(const std::shared_ptr Playlist::add_song(ClientDbId client, const std::string &url, const std::string& url_loader, ts::SongId order) { - auto entry = make_shared(); + auto entry = std::make_shared(); entry->previous_song_id = order; entry->invoker = client; @@ -401,7 +405,7 @@ std::shared_ptr Playlist::add_song(ClientDbId client, const s auto list_entry = make_shared(); list_entry->entry = entry; - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); if(order == 0) { auto end = playlist_end(list_lock); entry->previous_song_id = end ? end->entry->song_id : 0; @@ -427,7 +431,7 @@ std::shared_ptr Playlist::add_song(ClientDbId client, const s } bool Playlist::delete_song(ts::SongId id) { - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); auto song = this->playlist_find(list_lock, id); if(!song) return false; @@ -440,7 +444,7 @@ bool Playlist::delete_song(ts::SongId id) { } bool Playlist::reorder_song(ts::SongId song_id, ts::SongId order_id) { - unique_lock list_lock(this->playlist_lock); + unique_lock list_lock(this->playlist_mutex); auto song = this->playlist_find(list_lock, song_id); auto order = this->playlist_find(list_lock, order_id); if(!song) return false; diff --git a/server/src/music/MusicPlaylist.h b/server/src/music/MusicPlaylist.h index 7b9f006..31d0120 100644 --- a/server/src/music/MusicPlaylist.h +++ b/server/src/music/MusicPlaylist.h @@ -128,7 +128,7 @@ namespace ts { bool is_subscriber(const std::shared_ptr&); protected: virtual void set_self_ref(const std::shared_ptr& /* playlist */); - bool is_playlist_owner(ClientDbId database_id) const override { return this->properties()[property::PLAYLIST_OWNER_DBID].as_save() == database_id; } + [[nodiscard]] bool is_playlist_owner(ClientDbId database_id) const override { return this->properties()[property::PLAYLIST_OWNER_DBID].as_save() == database_id; } std::atomic current_id; std::shared_ptr _properties; @@ -140,7 +140,7 @@ namespace ts { std::shared_ptr get_server(); ServerId get_server_id(); - std::shared_mutex playlist_lock{}; + std::shared_mutex playlist_mutex{}; std::shared_ptr playlist_head{}; std::mutex subscriber_lock{}; @@ -148,7 +148,7 @@ namespace ts { virtual std::deque> _list_songs(const std::unique_lock& /* playlist lock */); - /* playlist functions are threadsave */ + /* playlist functions are thread safe */ std::shared_ptr playlist_find(const std::unique_lock& /* playlist lock */, SongId /* song */); std::shared_ptr playlist_end(const std::unique_lock &); bool playlist_insert( diff --git a/server/src/music/PlayablePlaylist.cpp b/server/src/music/PlayablePlaylist.cpp index cb8b277..0e55c44 100644 --- a/server/src/music/PlayablePlaylist.cpp +++ b/server/src/music/PlayablePlaylist.cpp @@ -18,7 +18,7 @@ PlayablePlaylist::~PlayablePlaylist() {} void PlayablePlaylist::load_songs() { Playlist::load_songs(); - unique_lock playlist_lock(this->playlist_lock); + unique_lock playlist_lock(this->playlist_mutex); auto song_id = this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as_save(); auto current_song = this->playlist_find(playlist_lock, song_id); if(!current_song && song_id != 0) { @@ -113,7 +113,7 @@ std::shared_ptr PlayablePlaylist::playlist_next_entry() { if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */ auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as(); - unique_lock playlist_lock(this->playlist_lock); + unique_lock playlist_lock(this->playlist_mutex); auto old_song = this->playlist_find(playlist_lock, this->currently_playing()); if(replay_mode == ReplayMode::SINGLE_LOOPED) { @@ -165,7 +165,7 @@ std::shared_ptr PlayablePlaylist::playlist_previous_entry() { if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */ auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as(); - unique_lock playlist_lock(this->playlist_lock); + unique_lock playlist_lock(this->playlist_mutex); this->properties()[property::PLAYLIST_FLAG_FINISHED] = false; auto current_song = this->playlist_find(playlist_lock, this->currently_playing()); @@ -192,7 +192,7 @@ std::shared_ptr PlayablePlaylist::playlist_previous_entry() { bool PlayablePlaylist::set_current_song(SongId song_id) { { - unique_lock playlist_lock(this->playlist_lock); + unique_lock playlist_lock(this->playlist_mutex); auto current_song = this->playlist_find(playlist_lock, song_id); if(!current_song && song_id != 0) return false; diff --git a/server/src/music/PlaylistPermissions.h b/server/src/music/PlaylistPermissions.h index b73a7fc..822f93f 100644 --- a/server/src/music/PlaylistPermissions.h +++ b/server/src/music/PlaylistPermissions.h @@ -14,17 +14,26 @@ namespace ts::music { ignore_playlist_owner, do_no_require_granted }; - PlaylistPermissions(std::shared_ptr permissions); + explicit PlaylistPermissions(std::shared_ptr permissions); - inline const std::shared_ptr& permission_manager() const { return this->_permissions; } + [[nodiscard]] inline const std::shared_ptr& permission_manager() const { return this->_permissions; } /* returns permission::ok if client has permissions */ - permission::PermissionType client_has_permissions(const std::shared_ptr& 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& /* client */); + permission::PermissionType client_has_permissions( + const std::shared_ptr& /* 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& /* client */ + ); + protected: const std::shared_ptr _permissions; - virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0; - private: + [[nodiscard]] virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0; }; } \ No newline at end of file diff --git a/shared b/shared index 12c2a15..eb77a7f 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit 12c2a1592d86fa8b10c9d56919222de3891bd4a7 +Subproject commit eb77a7fefb454469ed4f0b495959923048a2b768