yuzu_room: Remove dependency on core
This commit is contained in:
		| @@ -2,6 +2,8 @@ | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| add_library(network STATIC | ||||
|     announce_multiplayer_session.cpp | ||||
|     announce_multiplayer_session.h | ||||
|     network.cpp | ||||
|     network.h | ||||
|     packet.cpp | ||||
| @@ -17,3 +19,7 @@ add_library(network STATIC | ||||
| create_target_directory_groups(network) | ||||
|  | ||||
| target_link_libraries(network PRIVATE common enet Boost::boost) | ||||
| if (ENABLE_WEB_SERVICE) | ||||
|     target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE) | ||||
|     target_link_libraries(network PRIVATE web_service) | ||||
| endif() | ||||
|   | ||||
							
								
								
									
										164
									
								
								src/network/announce_multiplayer_session.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/network/announce_multiplayer_session.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include <chrono> | ||||
| #include <future> | ||||
| #include <vector> | ||||
| #include "announce_multiplayer_session.h" | ||||
| #include "common/announce_multiplayer_room.h" | ||||
| #include "common/assert.h" | ||||
| #include "common/settings.h" | ||||
| #include "network/network.h" | ||||
|  | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
| #include "web_service/announce_room_json.h" | ||||
| #endif | ||||
|  | ||||
| namespace Core { | ||||
|  | ||||
| // Time between room is announced to web_service | ||||
| static constexpr std::chrono::seconds announce_time_interval(15); | ||||
|  | ||||
| AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_) | ||||
|     : room_network{room_network_} { | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|     backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(), | ||||
|                                                      Settings::values.yuzu_username.GetValue(), | ||||
|                                                      Settings::values.yuzu_token.GetValue()); | ||||
| #else | ||||
|     backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| WebService::WebResult AnnounceMultiplayerSession::Register() { | ||||
|     auto room = room_network.GetRoom().lock(); | ||||
|     if (!room) { | ||||
|         return WebService::WebResult{WebService::WebResult::Code::LibError, | ||||
|                                      "Network is not initialized", ""}; | ||||
|     } | ||||
|     if (room->GetState() != Network::Room::State::Open) { | ||||
|         return WebService::WebResult{WebService::WebResult::Code::LibError, "Room is not open", ""}; | ||||
|     } | ||||
|     UpdateBackendData(room); | ||||
|     WebService::WebResult result = backend->Register(); | ||||
|     if (result.result_code != WebService::WebResult::Code::Success) { | ||||
|         return result; | ||||
|     } | ||||
|     LOG_INFO(WebService, "Room has been registered"); | ||||
|     room->SetVerifyUID(result.returned_data); | ||||
|     registered = true; | ||||
|     return WebService::WebResult{WebService::WebResult::Code::Success, "", ""}; | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::Start() { | ||||
|     if (announce_multiplayer_thread) { | ||||
|         Stop(); | ||||
|     } | ||||
|     shutdown_event.Reset(); | ||||
|     announce_multiplayer_thread = | ||||
|         std::make_unique<std::thread>(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this); | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::Stop() { | ||||
|     if (announce_multiplayer_thread) { | ||||
|         shutdown_event.Set(); | ||||
|         announce_multiplayer_thread->join(); | ||||
|         announce_multiplayer_thread.reset(); | ||||
|         backend->Delete(); | ||||
|         registered = false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback( | ||||
|     std::function<void(const WebService::WebResult&)> function) { | ||||
|     std::lock_guard lock(callback_mutex); | ||||
|     auto handle = std::make_shared<std::function<void(const WebService::WebResult&)>>(function); | ||||
|     error_callbacks.insert(handle); | ||||
|     return handle; | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) { | ||||
|     std::lock_guard lock(callback_mutex); | ||||
|     error_callbacks.erase(handle); | ||||
| } | ||||
|  | ||||
| AnnounceMultiplayerSession::~AnnounceMultiplayerSession() { | ||||
|     Stop(); | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room> room) { | ||||
|     Network::RoomInformation room_information = room->GetRoomInformation(); | ||||
|     std::vector<AnnounceMultiplayerRoom::Member> memberlist = room->GetRoomMemberList(); | ||||
|     backend->SetRoomInformation(room_information.name, room_information.description, | ||||
|                                 room_information.port, room_information.member_slots, | ||||
|                                 Network::network_version, room->HasPassword(), | ||||
|                                 room_information.preferred_game); | ||||
|     backend->ClearPlayers(); | ||||
|     for (const auto& member : memberlist) { | ||||
|         backend->AddPlayer(member); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | ||||
|     // Invokes all current bound error callbacks. | ||||
|     const auto ErrorCallback = [this](WebService::WebResult result) { | ||||
|         std::lock_guard lock(callback_mutex); | ||||
|         for (auto callback : error_callbacks) { | ||||
|             (*callback)(result); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     if (!registered) { | ||||
|         WebService::WebResult result = Register(); | ||||
|         if (result.result_code != WebService::WebResult::Code::Success) { | ||||
|             ErrorCallback(result); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     auto update_time = std::chrono::steady_clock::now(); | ||||
|     std::future<WebService::WebResult> future; | ||||
|     while (!shutdown_event.WaitUntil(update_time)) { | ||||
|         update_time += announce_time_interval; | ||||
|         auto room = room_network.GetRoom().lock(); | ||||
|         if (!room) { | ||||
|             break; | ||||
|         } | ||||
|         if (room->GetState() != Network::Room::State::Open) { | ||||
|             break; | ||||
|         } | ||||
|         UpdateBackendData(room); | ||||
|         WebService::WebResult result = backend->Update(); | ||||
|         if (result.result_code != WebService::WebResult::Code::Success) { | ||||
|             ErrorCallback(result); | ||||
|         } | ||||
|         if (result.result_string == "404") { | ||||
|             registered = false; | ||||
|             // Needs to register the room again | ||||
|             WebService::WebResult register_result = Register(); | ||||
|             if (register_result.result_code != WebService::WebResult::Code::Success) { | ||||
|                 ErrorCallback(register_result); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| AnnounceMultiplayerRoom::RoomList AnnounceMultiplayerSession::GetRoomList() { | ||||
|     return backend->GetRoomList(); | ||||
| } | ||||
|  | ||||
| bool AnnounceMultiplayerSession::IsRunning() const { | ||||
|     return announce_multiplayer_thread != nullptr; | ||||
| } | ||||
|  | ||||
| void AnnounceMultiplayerSession::UpdateCredentials() { | ||||
|     ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running"); | ||||
|  | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|     backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(), | ||||
|                                                      Settings::values.yuzu_username.GetValue(), | ||||
|                                                      Settings::values.yuzu_token.GetValue()); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| } // namespace Core | ||||
							
								
								
									
										98
									
								
								src/network/announce_multiplayer_session.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/network/announce_multiplayer_session.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <atomic> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <set> | ||||
| #include <thread> | ||||
| #include "common/announce_multiplayer_room.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/thread.h" | ||||
|  | ||||
| namespace Network { | ||||
| class Room; | ||||
| class RoomNetwork; | ||||
| } // namespace Network | ||||
|  | ||||
| namespace Core { | ||||
|  | ||||
| /** | ||||
|  * Instruments AnnounceMultiplayerRoom::Backend. | ||||
|  * Creates a thread that regularly updates the room information and submits them | ||||
|  * An async get of room information is also possible | ||||
|  */ | ||||
| class AnnounceMultiplayerSession { | ||||
| public: | ||||
|     using CallbackHandle = std::shared_ptr<std::function<void(const WebService::WebResult&)>>; | ||||
|     AnnounceMultiplayerSession(Network::RoomNetwork& room_network_); | ||||
|     ~AnnounceMultiplayerSession(); | ||||
|  | ||||
|     /** | ||||
|      * Allows to bind a function that will get called if the announce encounters an error | ||||
|      * @param function The function that gets called | ||||
|      * @return A handle that can be used the unbind the function | ||||
|      */ | ||||
|     CallbackHandle BindErrorCallback(std::function<void(const WebService::WebResult&)> function); | ||||
|  | ||||
|     /** | ||||
|      * Unbind a function from the error callbacks | ||||
|      * @param handle The handle for the function that should get unbind | ||||
|      */ | ||||
|     void UnbindErrorCallback(CallbackHandle handle); | ||||
|  | ||||
|     /** | ||||
|      * Registers a room to web services | ||||
|      * @return The result of the registration attempt. | ||||
|      */ | ||||
|     WebService::WebResult Register(); | ||||
|  | ||||
|     /** | ||||
|      * Starts the announce of a room to web services | ||||
|      */ | ||||
|     void Start(); | ||||
|  | ||||
|     /** | ||||
|      * Stops the announce to web services | ||||
|      */ | ||||
|     void Stop(); | ||||
|  | ||||
|     /** | ||||
|      *  Returns a list of all room information the backend got | ||||
|      * @param func A function that gets executed when the async get finished, e.g. a signal | ||||
|      * @return a list of rooms received from the web service | ||||
|      */ | ||||
|     AnnounceMultiplayerRoom::RoomList GetRoomList(); | ||||
|  | ||||
|     /** | ||||
|      * Whether the announce session is still running | ||||
|      */ | ||||
|     bool IsRunning() const; | ||||
|  | ||||
|     /** | ||||
|      * Recreates the backend, updating the credentials. | ||||
|      * This can only be used when the announce session is not running. | ||||
|      */ | ||||
|     void UpdateCredentials(); | ||||
|  | ||||
| private: | ||||
|     void UpdateBackendData(std::shared_ptr<Network::Room> room); | ||||
|     void AnnounceMultiplayerLoop(); | ||||
|  | ||||
|     Common::Event shutdown_event; | ||||
|     std::mutex callback_mutex; | ||||
|     std::set<CallbackHandle> error_callbacks; | ||||
|     std::unique_ptr<std::thread> announce_multiplayer_thread; | ||||
|  | ||||
|     /// Backend interface that logs fields | ||||
|     std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend; | ||||
|  | ||||
|     std::atomic_bool registered = false; ///< Whether the room has been registered | ||||
|  | ||||
|     Network::RoomNetwork& room_network; | ||||
| }; | ||||
|  | ||||
| } // namespace Core | ||||
		Reference in New Issue
	
	Block a user