mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	core, web_service: Changes to announce service
Separated registering and updating to correspond to the new announce API endpoint. Also added a verify_UID for JWT audience verification.
This commit is contained in:
		
							parent
							
								
									1a8841f96e
								
							
						
					
					
						commit
						ab335ccf1b
					
				
					 5 changed files with 135 additions and 49 deletions
				
			
		|  | @ -17,14 +17,17 @@ using MacAddress = std::array<u8, 6>; | |||
| 
 | ||||
| struct Room { | ||||
|     struct Member { | ||||
|         std::string name; | ||||
|         std::string username; | ||||
|         std::string nickname; | ||||
|         std::string avatar_url; | ||||
|         MacAddress mac_address; | ||||
|         std::string game_name; | ||||
|         u64 game_id; | ||||
|     }; | ||||
|     std::string id; | ||||
|     std::string verify_UID; ///< UID used for verification
 | ||||
|     std::string name; | ||||
|     std::string description; | ||||
|     std::string UID; | ||||
|     std::string owner; | ||||
|     std::string ip; | ||||
|     u16 port; | ||||
|  | @ -57,9 +60,8 @@ public: | |||
|      * @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 std::string& description, const u16 port, | ||||
|                                     const u32 max_player, const u32 net_version, | ||||
|     virtual void SetRoomInformation(const std::string& name, const std::string& description, | ||||
|                                     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; | ||||
|     /**
 | ||||
|  | @ -69,14 +71,21 @@ public: | |||
|      * @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& username, const std::string& nickname, | ||||
|                            const std::string& avatar_url, 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 | ||||
|      * Updates the data in the announce service. Re-register the room when required. | ||||
|      * @result The result of the update attempt | ||||
|      */ | ||||
|     virtual Common::WebResult Announce() = 0; | ||||
|     virtual Common::WebResult Update() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Registers the data in the announce service | ||||
|      * @result A global Guid of the room which may be used for verification | ||||
|      */ | ||||
|     virtual std::string Register() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Empties the stored players | ||||
|  | @ -102,16 +111,19 @@ public: | |||
| class NullBackend : public Backend { | ||||
| public: | ||||
|     ~NullBackend() = default; | ||||
|     void SetRoomInformation(const std::string& /*uid*/, const std::string& /*name*/, | ||||
|                             const std::string& /*description*/, const u16 /*port*/, | ||||
|                             const u32 /*max_player*/, const u32 /*net_version*/, | ||||
|     void SetRoomInformation(const std::string& /*name*/, const std::string& /*description*/, | ||||
|                             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*/) override {} | ||||
|     void AddPlayer(const std::string& /*nickname*/, const MacAddress& /*mac_address*/, | ||||
|     void AddPlayer(const std::string& /*username*/, const std::string& /*nickname*/, | ||||
|                    const std::string& /*avatar_url*/, const MacAddress& /*mac_address*/, | ||||
|                    const u64 /*game_id*/, const std::string& /*game_name*/) override {} | ||||
|     Common::WebResult Announce() override { | ||||
|     Common::WebResult Update() override { | ||||
|         return Common::WebResult{Common::WebResult::Code::NoWebservice, "WebService is missing"}; | ||||
|     } | ||||
|     std::string Register() override { | ||||
|         return ""; | ||||
|     } | ||||
|     void ClearPlayers() override {} | ||||
|     RoomList GetRoomList() override { | ||||
|         return RoomList{}; | ||||
|  |  | |||
|  | @ -29,6 +29,21 @@ AnnounceMultiplayerSession::AnnounceMultiplayerSession() { | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| void AnnounceMultiplayerSession::Register() { | ||||
|     std::shared_ptr<Network::Room> room = Network::GetRoom().lock(); | ||||
|     if (!room) { | ||||
|         return; | ||||
|     } | ||||
|     if (room->GetState() != Network::Room::State::Open) { | ||||
|         return; | ||||
|     } | ||||
|     UpdateBackendData(room); | ||||
|     std::string result = backend->Register(); | ||||
|     LOG_INFO(WebService, "Room has been registered"); | ||||
|     room->SetVerifyUID(result); | ||||
|     registered = true; | ||||
| } | ||||
| 
 | ||||
| void AnnounceMultiplayerSession::Start() { | ||||
|     if (announce_multiplayer_thread) { | ||||
|         Stop(); | ||||
|  | @ -44,6 +59,7 @@ void AnnounceMultiplayerSession::Stop() { | |||
|         announce_multiplayer_thread->join(); | ||||
|         announce_multiplayer_thread.reset(); | ||||
|         backend->Delete(); | ||||
|         registered = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -64,7 +80,24 @@ AnnounceMultiplayerSession::~AnnounceMultiplayerSession() { | |||
|     Stop(); | ||||
| } | ||||
| 
 | ||||
| void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room> room) { | ||||
|     Network::RoomInformation room_information = room->GetRoomInformation(); | ||||
|     std::vector<Network::Room::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, room_information.preferred_game_id); | ||||
|     backend->ClearPlayers(); | ||||
|     for (const auto& member : memberlist) { | ||||
|         backend->AddPlayer(member.username, member.nickname, member.avatar_url, member.mac_address, | ||||
|                            member.game_info.id, member.game_info.name); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | ||||
|     if (!registered) { | ||||
|         Register(); | ||||
|     } | ||||
|     auto update_time = std::chrono::steady_clock::now(); | ||||
|     std::future<Common::WebResult> future; | ||||
|     while (!shutdown_event.WaitUntil(update_time)) { | ||||
|  | @ -76,25 +109,19 @@ void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { | |||
|         if (room->GetState() != Network::Room::State::Open) { | ||||
|             break; | ||||
|         } | ||||
|         Network::RoomInformation room_information = room->GetRoomInformation(); | ||||
|         std::vector<Network::Room::Member> memberlist = room->GetRoomMemberList(); | ||||
|         backend->SetRoomInformation(room_information.uid, room_information.name, | ||||
|                                     room_information.description, room_information.port, | ||||
|                                     room_information.member_slots, Network::network_version, | ||||
|                                     room->HasPassword(), room_information.preferred_game, | ||||
|                                     room_information.preferred_game_id); | ||||
|         backend->ClearPlayers(); | ||||
|         for (const auto& member : memberlist) { | ||||
|             backend->AddPlayer(member.nickname, member.mac_address, member.game_info.id, | ||||
|                                member.game_info.name); | ||||
|         } | ||||
|         Common::WebResult result = backend->Announce(); | ||||
|         UpdateBackendData(room); | ||||
|         Common::WebResult result = backend->Update(); | ||||
|         if (result.result_code != Common::WebResult::Code::Success) { | ||||
|             std::lock_guard<std::mutex> lock(callback_mutex); | ||||
|             for (auto callback : error_callbacks) { | ||||
|                 (*callback)(result); | ||||
|             } | ||||
|         } | ||||
|         if (result.result_string == "404") { | ||||
|             registered = false; | ||||
|             // Needs to register the room again
 | ||||
|             Register(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
|  | @ -13,6 +14,10 @@ | |||
| #include "common/common_types.h" | ||||
| #include "common/thread.h" | ||||
| 
 | ||||
| namespace Network { | ||||
| class Room; | ||||
| } | ||||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -39,6 +44,9 @@ public: | |||
|      */ | ||||
|     void UnbindErrorCallback(CallbackHandle handle); | ||||
| 
 | ||||
|     /// Registers a room to web services
 | ||||
|     void Register(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Starts the announce of a room to web services | ||||
|      */ | ||||
|  | @ -65,6 +73,9 @@ private: | |||
|     /// Backend interface that logs fields
 | ||||
|     std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend; | ||||
| 
 | ||||
|     std::atomic_bool registered = false; ///< Whether the room has been registered
 | ||||
| 
 | ||||
|     void UpdateBackendData(std::shared_ptr<Network::Room> room); | ||||
|     void AnnounceMultiplayerLoop(); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,22 +12,36 @@ | |||
| namespace AnnounceMultiplayerRoom { | ||||
| 
 | ||||
| void to_json(nlohmann::json& json, const Room::Member& member) { | ||||
|     json["name"] = member.name; | ||||
|     if (!member.username.empty()) { | ||||
|         json["username"] = member.username; | ||||
|     } | ||||
|     json["nickname"] = member.nickname; | ||||
|     if (!member.avatar_url.empty()) { | ||||
|         json["avatarUrl"] = member.avatar_url; | ||||
|     } | ||||
|     json["gameName"] = member.game_name; | ||||
|     json["gameId"] = member.game_id; | ||||
| } | ||||
| 
 | ||||
| void from_json(const nlohmann::json& json, Room::Member& member) { | ||||
|     member.name = json.at("name").get<std::string>(); | ||||
|     member.nickname = json.at("nickname").get<std::string>(); | ||||
|     member.game_name = json.at("gameName").get<std::string>(); | ||||
|     member.game_id = json.at("gameId").get<u64>(); | ||||
|     try { | ||||
|         member.username = json.at("username").get<std::string>(); | ||||
|         member.avatar_url = json.at("avatarUrl").get<std::string>(); | ||||
|     } catch (const nlohmann::detail::out_of_range& e) { | ||||
|         member.username = member.avatar_url = ""; | ||||
|         LOG_DEBUG(Network, "Member \'{}\' isn't authenticated", member.nickname); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void to_json(nlohmann::json& json, const Room& room) { | ||||
|     json["id"] = room.UID; | ||||
|     json["port"] = room.port; | ||||
|     json["name"] = room.name; | ||||
|     json["description"] = room.description; | ||||
|     if (!room.description.empty()) { | ||||
|         json["description"] = room.description; | ||||
|     } | ||||
|     json["preferredGameName"] = room.preferred_game; | ||||
|     json["preferredGameId"] = room.preferred_game_id; | ||||
|     json["maxPlayers"] = room.max_player; | ||||
|  | @ -40,6 +54,7 @@ void to_json(nlohmann::json& json, const Room& room) { | |||
| } | ||||
| 
 | ||||
| void from_json(const nlohmann::json& json, Room& room) { | ||||
|     room.verify_UID = json.at("externalGuid").get<std::string>(); | ||||
|     room.ip = json.at("address").get<std::string>(); | ||||
|     room.name = json.at("name").get<std::string>(); | ||||
|     try { | ||||
|  | @ -66,14 +81,12 @@ void from_json(const nlohmann::json& json, Room& room) { | |||
| 
 | ||||
| namespace WebService { | ||||
| 
 | ||||
| void RoomJson::SetRoomInformation(const std::string& uid, const std::string& name, | ||||
|                                   const std::string& description, const u16 port, | ||||
|                                   const u32 max_player, const u32 net_version, | ||||
| void RoomJson::SetRoomInformation(const std::string& name, const std::string& description, | ||||
|                                   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) { | ||||
|     room.name = name; | ||||
|     room.description = description; | ||||
|     room.UID = uid; | ||||
|     room.port = port; | ||||
|     room.max_player = max_player; | ||||
|     room.net_version = net_version; | ||||
|  | @ -81,20 +94,39 @@ void RoomJson::SetRoomInformation(const std::string& uid, const std::string& nam | |||
|     room.preferred_game = preferred_game; | ||||
|     room.preferred_game_id = preferred_game_id; | ||||
| } | ||||
| void RoomJson::AddPlayer(const std::string& nickname, | ||||
| void RoomJson::AddPlayer(const std::string& username, const std::string& nickname, | ||||
|                          const std::string& avatar_url, | ||||
|                          const AnnounceMultiplayerRoom::MacAddress& mac_address, const u64 game_id, | ||||
|                          const std::string& game_name) { | ||||
|     AnnounceMultiplayerRoom::Room::Member member; | ||||
|     member.name = nickname; | ||||
|     member.username = username; | ||||
|     member.nickname = nickname; | ||||
|     member.avatar_url = avatar_url; | ||||
|     member.mac_address = mac_address; | ||||
|     member.game_id = game_id; | ||||
|     member.game_name = game_name; | ||||
|     room.members.push_back(member); | ||||
| } | ||||
| 
 | ||||
| Common::WebResult RoomJson::Announce() { | ||||
| Common::WebResult RoomJson::Update() { | ||||
|     if (room_id.empty()) { | ||||
|         LOG_ERROR(WebService, "Room must be registered to be updated"); | ||||
|         return Common::WebResult{Common::WebResult::Code::LibError, "Room is not registered"}; | ||||
|     } | ||||
|     nlohmann::json json{{"players", room.members}}; | ||||
|     return client.PostJson(fmt::format("/lobby2/{}", room_id), json.dump(), false); | ||||
| } | ||||
| 
 | ||||
| std::string RoomJson::Register() { | ||||
|     nlohmann::json json = room; | ||||
|     return client.PostJson("/lobby", json.dump(), false); | ||||
|     auto reply = client.PostJson("/lobby2", json.dump(), false).returned_data; | ||||
|     if (reply.empty()) { | ||||
|         return ""; | ||||
|     } | ||||
|     auto reply_json = nlohmann::json::parse(reply); | ||||
|     room = reply_json.get<AnnounceMultiplayerRoom::Room>(); | ||||
|     room_id = reply_json.at("id").get<std::string>(); | ||||
|     return room.verify_UID; | ||||
| } | ||||
| 
 | ||||
| void RoomJson::ClearPlayers() { | ||||
|  | @ -102,7 +134,7 @@ void RoomJson::ClearPlayers() { | |||
| } | ||||
| 
 | ||||
| AnnounceMultiplayerRoom::RoomList RoomJson::GetRoomList() { | ||||
|     auto reply = client.GetJson("/lobby", true).returned_data; | ||||
|     auto reply = client.GetJson("/lobby2", true).returned_data; | ||||
|     if (reply.empty()) { | ||||
|         return {}; | ||||
|     } | ||||
|  | @ -110,12 +142,14 @@ AnnounceMultiplayerRoom::RoomList RoomJson::GetRoomList() { | |||
| } | ||||
| 
 | ||||
| void RoomJson::Delete() { | ||||
|     nlohmann::json json; | ||||
|     json["id"] = room.UID; | ||||
|     if (room_id.empty()) { | ||||
|         LOG_ERROR(WebService, "Room must be registered to be deleted"); | ||||
|         return; | ||||
|     } | ||||
|     Common::DetachedTasks::AddTask( | ||||
|         [host{this->host}, username{this->username}, token{this->token}, content{json.dump()}]() { | ||||
|         [host{this->host}, username{this->username}, token{this->token}, room_id{this->room_id}]() { | ||||
|             // create a new client here because the this->client might be destroyed.
 | ||||
|             Client{host, username, token}.DeleteJson("/lobby", content, false); | ||||
|             Client{host, username, token}.DeleteJson(fmt::format("/lobby2/{}", room_id), "", false); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,15 +20,16 @@ public: | |||
|     RoomJson(const std::string& host, const std::string& username, const std::string& token) | ||||
|         : client(host, username, token), host(host), username(username), token(token) {} | ||||
|     ~RoomJson() = default; | ||||
|     void SetRoomInformation(const std::string& uid, const std::string& name, | ||||
|                             const std::string& description, const u16 port, const u32 max_player, | ||||
|                             const u32 net_version, const bool has_password, | ||||
|     void SetRoomInformation(const std::string& name, const std::string& description, 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) override; | ||||
|     void AddPlayer(const std::string& nickname, | ||||
|     void AddPlayer(const std::string& username, const std::string& nickname, | ||||
|                    const std::string& avatar_url, | ||||
|                    const AnnounceMultiplayerRoom::MacAddress& mac_address, const u64 game_id, | ||||
|                    const std::string& game_name) override; | ||||
|     Common::WebResult Announce() override; | ||||
|     Common::WebResult Update() override; | ||||
|     std::string Register() override; | ||||
|     void ClearPlayers() override; | ||||
|     AnnounceMultiplayerRoom::RoomList GetRoomList() override; | ||||
|     void Delete() override; | ||||
|  | @ -39,6 +40,7 @@ private: | |||
|     std::string host; | ||||
|     std::string username; | ||||
|     std::string token; | ||||
|     std::string room_id; | ||||
| }; | ||||
| 
 | ||||
| } // namespace WebService
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue