mirror of
https://github.com/PabloMK7/citra.git
synced 2024-11-29 10:50:17 +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…
Reference in a new issue