mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Announce-Service: Add conditional variable for the wait in the announce thread
This commit is contained in:
		
							parent
							
								
									93742f17b3
								
							
						
					
					
						commit
						eba2351f9e
					
				
					 4 changed files with 63 additions and 25 deletions
				
			
		|  | @ -60,15 +60,53 @@ using RoomList = std::vector<Room>; | ||||||
| class Backend : NonCopyable { | class Backend : NonCopyable { | ||||||
| public: | public: | ||||||
|     virtual ~Backend() = default; |     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, |     virtual void SetRoomInformation(const std::string& uid, const std::string& name, const u16 port, | ||||||
|                                     const u32 max_player, const u32 net_version, |                                     const u32 max_player, const u32 net_version, | ||||||
|                                     const bool has_password, const std::string& preferred_game, |                                     const bool has_password, const std::string& preferred_game, | ||||||
|                                     const u64 preferred_game_id) = 0; |                                     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, |     virtual void AddPlayer(const std::string& nickname, const MacAddress& mac_address, | ||||||
|                            const u64 game_id, const std::string& game_name) = 0; |                            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; |     virtual std::future<Common::WebResult> Announce() = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Empties the stored players | ||||||
|  |      */ | ||||||
|     virtual void ClearPlayers() = 0; |     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; |     virtual std::future<RoomList> GetRoomList(std::function<void()> func) = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Sends a delete message to the announce service | ||||||
|  |      */ | ||||||
|     virtual void Delete() = 0; |     virtual void Delete() = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -93,7 +131,7 @@ public: | ||||||
|     } |     } | ||||||
|     void ClearPlayers() override {} |     void ClearPlayers() override {} | ||||||
|     std::future<RoomList> GetRoomList(std::function<void()> func) 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(); |             func(); | ||||||
|             return RoomList{}; |             return RoomList{}; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ namespace Core { | ||||||
| // Time between room is announced to web_service
 | // Time between room is announced to web_service
 | ||||||
| static constexpr std::chrono::seconds announce_time_interval(15); | static constexpr std::chrono::seconds announce_time_interval(15); | ||||||
| 
 | 
 | ||||||
| AnnounceMultiplayerSession::AnnounceMultiplayerSession() : announce(false), finished(true) { | AnnounceMultiplayerSession::AnnounceMultiplayerSession() : announce(false) { | ||||||
| #ifdef ENABLE_WEB_SERVICE | #ifdef ENABLE_WEB_SERVICE | ||||||
|     backend = std::make_unique<WebService::RoomJson>( |     backend = std::make_unique<WebService::RoomJson>( | ||||||
|         Settings::values.announce_multiplayer_room_endpoint_url, Settings::values.citra_username, |         Settings::values.announce_multiplayer_room_endpoint_url, Settings::values.citra_username, | ||||||
|  | @ -39,19 +39,19 @@ void AnnounceMultiplayerSession::Start() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnnounceMultiplayerSession::Stop() { | void AnnounceMultiplayerSession::Stop() { | ||||||
|     if (!announce && finished) |     if (!announce) | ||||||
|         return; |         return; | ||||||
|     announce = false; |     announce = false; | ||||||
|     // Detaching the loop, to not wait for the sleep to finish. The loop thread will finish soon.
 |     // Detaching the loop, to not wait for the sleep to finish. The loop thread will finish soon.
 | ||||||
|     if (announce_multiplayer_thread) { |     if (announce_multiplayer_thread) { | ||||||
|         announce_multiplayer_thread->detach(); |         cv.notify_all(); | ||||||
|  |         announce_multiplayer_thread->join(); | ||||||
|         announce_multiplayer_thread.reset(); |         announce_multiplayer_thread.reset(); | ||||||
|         backend->Delete(); |         backend->Delete(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::shared_ptr<std::function<void(const Common::WebResult&)>> | AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback( | ||||||
| AnnounceMultiplayerSession::BindErrorCallback( |  | ||||||
|     std::function<void(const Common::WebResult&)> function) { |     std::function<void(const Common::WebResult&)> function) { | ||||||
|     std::lock_guard<std::mutex> lock(callback_mutex); |     std::lock_guard<std::mutex> lock(callback_mutex); | ||||||
|     auto handle = std::make_shared<std::function<void(const Common::WebResult&)>>(function); |     auto handle = std::make_shared<std::function<void(const Common::WebResult&)>>(function); | ||||||
|  | @ -59,8 +59,7 @@ AnnounceMultiplayerSession::BindErrorCallback( | ||||||
|     return handle; |     return handle; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnnounceMultiplayerSession::UnbindErrorCallback( | void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) { | ||||||
|     std::shared_ptr<std::function<void(const Common::WebResult&)>> handle) { |  | ||||||
|     std::lock_guard<std::mutex> lock(callback_mutex); |     std::lock_guard<std::mutex> lock(callback_mutex); | ||||||
|     error_callbacks.erase(handle); |     error_callbacks.erase(handle); | ||||||
| } | } | ||||||
|  | @ -70,13 +69,11 @@ AnnounceMultiplayerSession::~AnnounceMultiplayerSession() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | ||||||
|     while (!finished) { |  | ||||||
|         std::this_thread::sleep_for(announce_time_interval / 10); |  | ||||||
|     } |  | ||||||
|     announce = true; |     announce = true; | ||||||
|     finished = false; |  | ||||||
|     std::future<Common::WebResult> future; |     std::future<Common::WebResult> future; | ||||||
|     while (announce) { |     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(); |         std::shared_ptr<Network::Room> room = Network::GetRoom().lock(); | ||||||
|         if (!room) { |         if (!room) { | ||||||
|             announce = false; |             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( | std::future<AnnounceMultiplayerRoom::RoomList> AnnounceMultiplayerSession::GetRoomList( | ||||||
|  |  | ||||||
|  | @ -5,8 +5,10 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <atomic> | #include <atomic> | ||||||
|  | #include <condition_variable> | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <mutex> | ||||||
| #include <set> | #include <set> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include "common/announce_multiplayer_room.h" | #include "common/announce_multiplayer_room.h" | ||||||
|  | @ -21,6 +23,7 @@ namespace Core { | ||||||
|  */ |  */ | ||||||
| class AnnounceMultiplayerSession : NonCopyable { | class AnnounceMultiplayerSession : NonCopyable { | ||||||
| public: | public: | ||||||
|  |     using CallbackHandle = std::shared_ptr<std::function<void(const Common::WebResult&)>>; | ||||||
|     AnnounceMultiplayerSession(); |     AnnounceMultiplayerSession(); | ||||||
|     ~AnnounceMultiplayerSession(); |     ~AnnounceMultiplayerSession(); | ||||||
| 
 | 
 | ||||||
|  | @ -29,14 +32,13 @@ public: | ||||||
|      * @param function The function that gets called |      * @param function The function that gets called | ||||||
|      * @return A handle that can be used the unbind the function |      * @return A handle that can be used the unbind the function | ||||||
|      */ |      */ | ||||||
|     std::shared_ptr<std::function<void(const Common::WebResult&)>> BindErrorCallback( |     CallbackHandle BindErrorCallback(std::function<void(const Common::WebResult&)> function); | ||||||
|         std::function<void(const Common::WebResult&)> function); |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Unbind a function from the error callbacks |      * Unbind a function from the error callbacks | ||||||
|      * @param handle The handle for the function that should get unbind |      * @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 |      * Starts the announce of a room to web services | ||||||
|  | @ -57,13 +59,16 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::atomic<bool> announce{false}; |     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::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<std::thread> announce_multiplayer_thread; | ||||||
| 
 | 
 | ||||||
|     std::unique_ptr<AnnounceMultiplayerRoom::Backend> |     /// Backend interface that logs fields
 | ||||||
|         backend; ///< Backend interface that logs fields
 |     std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend; | ||||||
| 
 | 
 | ||||||
|     void AnnounceMultiplayerLoop(); |     void AnnounceMultiplayerLoop(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ std::future<Common::WebResult> PostJson(const std::string& url, const std::strin | ||||||
|                                         const std::string& token) { |                                         const std::string& token) { | ||||||
|     if (url.empty()) { |     if (url.empty()) { | ||||||
|         LOG_ERROR(WebService, "URL is invalid"); |         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"}; |             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()}; |     const bool are_credentials_provided{!token.empty() && !username.empty()}; | ||||||
|     if (!allow_anonymous && !are_credentials_provided) { |     if (!allow_anonymous && !are_credentials_provided) { | ||||||
|         LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); |         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, |             return Common::WebResult{Common::WebResult::Code::CredentialsMissing, | ||||||
|                                      "Credentials needed"}; |                                      "Credentials needed"}; | ||||||
|         }); |         }); | ||||||
|  | @ -97,13 +97,13 @@ std::future<T> GetJson(std::function<T(const std::string&)> func, const std::str | ||||||
|                        const std::string& token) { |                        const std::string& token) { | ||||||
|     if (url.empty()) { |     if (url.empty()) { | ||||||
|         LOG_ERROR(WebService, "URL is invalid"); |         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()}; |     const bool are_credentials_provided{!token.empty() && !username.empty()}; | ||||||
|     if (!allow_anonymous && !are_credentials_provided) { |     if (!allow_anonymous && !are_credentials_provided) { | ||||||
|         LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); |         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(); |     Win32WSAStartup(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue