Announce-Service: Add conditional variable for the wait in the announce thread
This commit is contained in:
		| @@ -60,15 +60,53 @@ using RoomList = std::vector<Room>; | ||||
| class Backend : NonCopyable { | ||||
| public: | ||||
|     virtual ~Backend() = default; | ||||
|  | ||||
|     /** | ||||
|      * Sets the Information that gets used for the announce | ||||
|      * @param uid The Id of the room | ||||
|      * @param name The name of the room | ||||
|      * @param port The port of the room | ||||
|      * @param net_version The version of the libNetwork that gets used | ||||
|      * @param has_password True if the room is passowrd protected | ||||
|      * @param preferred_game The preferred game of the room | ||||
|      * @param preferred_game_id The title id of the preferred game | ||||
|      */ | ||||
|     virtual void SetRoomInformation(const std::string& uid, const std::string& name, const u16 port, | ||||
|                                     const u32 max_player, const u32 net_version, | ||||
|                                     const bool has_password, const std::string& preferred_game, | ||||
|                                     const u64 preferred_game_id) = 0; | ||||
|     /** | ||||
|      * Adds a player information to the data that gets announced | ||||
|      * @param nickname The nickname of the player | ||||
|      * @param mac_address The MAC Address of the player | ||||
|      * @param game_id The title id of the game the player plays | ||||
|      * @param game_name The name of the game the player plays | ||||
|      */ | ||||
|     virtual void AddPlayer(const std::string& nickname, const MacAddress& mac_address, | ||||
|                            const u64 game_id, const std::string& game_name) = 0; | ||||
|  | ||||
|     /** | ||||
|      * Send the data to the announce service | ||||
|      * @result The result of the announce attempt | ||||
|      */ | ||||
|     virtual std::future<Common::WebResult> Announce() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Empties the stored players | ||||
|      */ | ||||
|     virtual void ClearPlayers() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get the room information from the announce service | ||||
|      * @param func a function that gets exectued when the get finished. | ||||
|      * Can be used as a callback | ||||
|      * @result A list of all rooms the announce service has | ||||
|      */ | ||||
|     virtual std::future<RoomList> GetRoomList(std::function<void()> func) = 0; | ||||
|  | ||||
|     /** | ||||
|      * Sends a delete message to the announce service | ||||
|      */ | ||||
|     virtual void Delete() = 0; | ||||
| }; | ||||
|  | ||||
| @@ -93,7 +131,7 @@ public: | ||||
|     } | ||||
|     void ClearPlayers() override {} | ||||
|     std::future<RoomList> GetRoomList(std::function<void()> func) override { | ||||
|         return std::async(std::launch::async, [func]() { | ||||
|         return std::async(std::launch::deferred, [func]() { | ||||
|             func(); | ||||
|             return RoomList{}; | ||||
|         }); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ namespace Core { | ||||
| // Time between room is announced to web_service | ||||
| static constexpr std::chrono::seconds announce_time_interval(15); | ||||
|  | ||||
| AnnounceMultiplayerSession::AnnounceMultiplayerSession() : announce(false), finished(true) { | ||||
| AnnounceMultiplayerSession::AnnounceMultiplayerSession() : announce(false) { | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|     backend = std::make_unique<WebService::RoomJson>( | ||||
|         Settings::values.announce_multiplayer_room_endpoint_url, Settings::values.citra_username, | ||||
| @@ -39,19 +39,19 @@ void AnnounceMultiplayerSession::Start() { | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::Stop() { | ||||
|     if (!announce && finished) | ||||
|     if (!announce) | ||||
|         return; | ||||
|     announce = false; | ||||
|     // Detaching the loop, to not wait for the sleep to finish. The loop thread will finish soon. | ||||
|     if (announce_multiplayer_thread) { | ||||
|         announce_multiplayer_thread->detach(); | ||||
|         cv.notify_all(); | ||||
|         announce_multiplayer_thread->join(); | ||||
|         announce_multiplayer_thread.reset(); | ||||
|         backend->Delete(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| std::shared_ptr<std::function<void(const Common::WebResult&)>> | ||||
| AnnounceMultiplayerSession::BindErrorCallback( | ||||
| AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback( | ||||
|     std::function<void(const Common::WebResult&)> function) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|     auto handle = std::make_shared<std::function<void(const Common::WebResult&)>>(function); | ||||
| @@ -59,8 +59,7 @@ AnnounceMultiplayerSession::BindErrorCallback( | ||||
|     return handle; | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::UnbindErrorCallback( | ||||
|     std::shared_ptr<std::function<void(const Common::WebResult&)>> handle) { | ||||
| void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) { | ||||
|     std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|     error_callbacks.erase(handle); | ||||
| } | ||||
| @@ -70,13 +69,11 @@ AnnounceMultiplayerSession::~AnnounceMultiplayerSession() { | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | ||||
|     while (!finished) { | ||||
|         std::this_thread::sleep_for(announce_time_interval / 10); | ||||
|     } | ||||
|     announce = true; | ||||
|     finished = false; | ||||
|     std::future<Common::WebResult> future; | ||||
|     while (announce) { | ||||
|         std::unique_lock<std::mutex> lock(cv_m); | ||||
|         cv.wait_for(lock, announce_time_interval); | ||||
|         std::shared_ptr<Network::Room> room = Network::GetRoom().lock(); | ||||
|         if (!room) { | ||||
|             announce = false; | ||||
| @@ -107,9 +104,7 @@ void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         std::this_thread::sleep_for(announce_time_interval); | ||||
|     } | ||||
|     finished = true; | ||||
| } | ||||
|  | ||||
| std::future<AnnounceMultiplayerRoom::RoomList> AnnounceMultiplayerSession::GetRoomList( | ||||
|   | ||||
| @@ -5,8 +5,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <atomic> | ||||
| #include <condition_variable> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <set> | ||||
| #include <thread> | ||||
| #include "common/announce_multiplayer_room.h" | ||||
| @@ -21,6 +23,7 @@ namespace Core { | ||||
|  */ | ||||
| class AnnounceMultiplayerSession : NonCopyable { | ||||
| public: | ||||
|     using CallbackHandle = std::shared_ptr<std::function<void(const Common::WebResult&)>>; | ||||
|     AnnounceMultiplayerSession(); | ||||
|     ~AnnounceMultiplayerSession(); | ||||
|  | ||||
| @@ -29,14 +32,13 @@ public: | ||||
|      * @param function The function that gets called | ||||
|      * @return A handle that can be used the unbind the function | ||||
|      */ | ||||
|     std::shared_ptr<std::function<void(const Common::WebResult&)>> BindErrorCallback( | ||||
|         std::function<void(const Common::WebResult&)> function); | ||||
|     CallbackHandle BindErrorCallback(std::function<void(const Common::WebResult&)> function); | ||||
|  | ||||
|     /** | ||||
|      * Unbind a function from the error callbacks | ||||
|      * @param handle The handle for the function that should get unbind | ||||
|      */ | ||||
|     void UnbindErrorCallback(std::shared_ptr<std::function<void(const Common::WebResult&)>> handle); | ||||
|     void UnbindErrorCallback(CallbackHandle handle); | ||||
|  | ||||
|     /** | ||||
|      * Starts the announce of a room to web services | ||||
| @@ -57,13 +59,16 @@ public: | ||||
|  | ||||
| private: | ||||
|     std::atomic<bool> announce{false}; | ||||
|     std::atomic<bool> finished{true}; | ||||
|  | ||||
|     /// conditional variable to notify the announce thread to end early | ||||
|     std::condition_variable cv; | ||||
|     std::mutex cv_m; ///< mutex for cv | ||||
|     std::mutex callback_mutex; | ||||
|     std::set<std::shared_ptr<std::function<void(const Common::WebResult&)>>> error_callbacks; | ||||
|     std::set<CallbackHandle> error_callbacks; | ||||
|     std::unique_ptr<std::thread> announce_multiplayer_thread; | ||||
|  | ||||
|     std::unique_ptr<AnnounceMultiplayerRoom::Backend> | ||||
|         backend; ///< Backend interface that logs fields | ||||
|     /// Backend interface that logs fields | ||||
|     std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend; | ||||
|  | ||||
|     void AnnounceMultiplayerLoop(); | ||||
| }; | ||||
|   | ||||
| @@ -37,7 +37,7 @@ std::future<Common::WebResult> PostJson(const std::string& url, const std::strin | ||||
|                                         const std::string& token) { | ||||
|     if (url.empty()) { | ||||
|         LOG_ERROR(WebService, "URL is invalid"); | ||||
|         return std::async(std::launch::async, []() { | ||||
|         return std::async(std::launch::deferred, []() { | ||||
|             return Common::WebResult{Common::WebResult::Code::InvalidURL, "URL is invalid"}; | ||||
|         }); | ||||
|     } | ||||
| @@ -45,7 +45,7 @@ std::future<Common::WebResult> PostJson(const std::string& url, const std::strin | ||||
|     const bool are_credentials_provided{!token.empty() && !username.empty()}; | ||||
|     if (!allow_anonymous && !are_credentials_provided) { | ||||
|         LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); | ||||
|         return std::async(std::launch::async, []() { | ||||
|         return std::async(std::launch::deferred, []() { | ||||
|             return Common::WebResult{Common::WebResult::Code::CredentialsMissing, | ||||
|                                      "Credentials needed"}; | ||||
|         }); | ||||
| @@ -97,13 +97,13 @@ std::future<T> GetJson(std::function<T(const std::string&)> func, const std::str | ||||
|                        const std::string& token) { | ||||
|     if (url.empty()) { | ||||
|         LOG_ERROR(WebService, "URL is invalid"); | ||||
|         return std::async(std::launch::async, [func{std::move(func)}]() { return func(""); }); | ||||
|         return std::async(std::launch::deferred, [func{std::move(func)}]() { return func(""); }); | ||||
|     } | ||||
|  | ||||
|     const bool are_credentials_provided{!token.empty() && !username.empty()}; | ||||
|     if (!allow_anonymous && !are_credentials_provided) { | ||||
|         LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); | ||||
|         return std::async(std::launch::async, [func{std::move(func)}]() { return func(""); }); | ||||
|         return std::async(std::launch::deferred, [func{std::move(func)}]() { return func(""); }); | ||||
|     } | ||||
|  | ||||
|     Win32WSAStartup(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 B3n30
					B3n30