// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include "announce_multiplayer_session.h" #include "common/announce_multiplayer_room.h" #include "common/assert.h" #include "core/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() : announce(false) { #ifdef ENABLE_WEB_SERVICE backend = std::make_unique( Settings::values.announce_multiplayer_room_endpoint_url, Settings::values.citra_username, Settings::values.citra_token); #else backend = std::make_unique(); #endif } void AnnounceMultiplayerSession::Start() { if (announce_multiplayer_thread) { Stop(); } announce_multiplayer_thread = std::make_unique(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this); } void AnnounceMultiplayerSession::Stop() { 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) { cv.notify_all(); announce_multiplayer_thread->join(); announce_multiplayer_thread.reset(); backend->Delete(); } } AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback( std::function function) { std::lock_guard lock(callback_mutex); auto handle = std::make_shared>(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::AnnounceMultiplayerLoop() { announce = true; std::future future; while (announce) { std::unique_lock lock(cv_m); cv.wait_for(lock, announce_time_interval); std::shared_ptr room = Network::GetRoom().lock(); if (!room) { announce = false; continue; } if (room->GetState() != Network::Room::State::Open) { announce = false; continue; } Network::RoomInformation room_information = room->GetRoomInformation(); std::vector memberlist = room->GetRoomMemberList(); backend->SetRoomInformation( room_information.uid, room_information.name, 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); } future = backend->Announce(); if (future.valid()) { Common::WebResult result = future.get(); if (result.result_code != Common::WebResult::Code::Success) { std::lock_guard lock(callback_mutex); for (auto callback : error_callbacks) { (*callback)(result); } } } } } std::future AnnounceMultiplayerSession::GetRoomList( std::function func) { return backend->GetRoomList(func); } } // namespace Core