2017-10-31 09:02:42 +00:00
|
|
|
// Copyright 2017 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <chrono>
|
2020-08-17 22:26:20 +00:00
|
|
|
#include <future>
|
2017-10-31 09:02:42 +00:00
|
|
|
#include <vector>
|
|
|
|
#include "announce_multiplayer_session.h"
|
|
|
|
#include "common/announce_multiplayer_room.h"
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "network/network.h"
|
2020-08-20 07:46:35 +00:00
|
|
|
#include "network/network_settings.h"
|
2017-10-31 09:02:42 +00:00
|
|
|
|
|
|
|
#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);
|
|
|
|
|
2017-11-10 18:37:26 +00:00
|
|
|
AnnounceMultiplayerSession::AnnounceMultiplayerSession() {
|
2017-10-31 09:02:42 +00:00
|
|
|
#ifdef ENABLE_WEB_SERVICE
|
2020-08-20 07:46:35 +00:00
|
|
|
backend = std::make_unique<WebService::RoomJson>(NetSettings::values.web_api_url,
|
|
|
|
NetSettings::values.citra_username,
|
|
|
|
NetSettings::values.citra_token);
|
2017-10-31 09:02:42 +00:00
|
|
|
#else
|
|
|
|
backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-04-19 14:55:49 +00:00
|
|
|
Common::WebResult AnnounceMultiplayerSession::Register() {
|
2018-10-27 07:40:15 +00:00
|
|
|
std::shared_ptr<Network::Room> room = Network::GetRoom().lock();
|
|
|
|
if (!room) {
|
2019-04-19 14:55:49 +00:00
|
|
|
return Common::WebResult{Common::WebResult::Code::LibError, "Network is not initialized"};
|
2018-10-27 07:40:15 +00:00
|
|
|
}
|
|
|
|
if (room->GetState() != Network::Room::State::Open) {
|
2019-04-19 14:55:49 +00:00
|
|
|
return Common::WebResult{Common::WebResult::Code::LibError, "Room is not open"};
|
2018-10-27 07:40:15 +00:00
|
|
|
}
|
|
|
|
UpdateBackendData(room);
|
2019-04-19 14:55:49 +00:00
|
|
|
Common::WebResult result = backend->Register();
|
|
|
|
if (result.result_code != Common::WebResult::Code::Success) {
|
|
|
|
return result;
|
|
|
|
}
|
2018-10-27 07:40:15 +00:00
|
|
|
LOG_INFO(WebService, "Room has been registered");
|
2019-04-19 14:55:49 +00:00
|
|
|
room->SetVerifyUID(result.returned_data);
|
2018-10-27 07:40:15 +00:00
|
|
|
registered = true;
|
2019-04-19 14:55:49 +00:00
|
|
|
return Common::WebResult{Common::WebResult::Code::Success};
|
2018-10-27 07:40:15 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 09:02:42 +00:00
|
|
|
void AnnounceMultiplayerSession::Start() {
|
|
|
|
if (announce_multiplayer_thread) {
|
|
|
|
Stop();
|
|
|
|
}
|
2017-11-10 18:37:26 +00:00
|
|
|
shutdown_event.Reset();
|
2017-10-31 09:02:42 +00:00
|
|
|
announce_multiplayer_thread =
|
|
|
|
std::make_unique<std::thread>(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnnounceMultiplayerSession::Stop() {
|
|
|
|
if (announce_multiplayer_thread) {
|
2017-11-10 18:37:26 +00:00
|
|
|
shutdown_event.Set();
|
2017-11-07 20:51:11 +00:00
|
|
|
announce_multiplayer_thread->join();
|
2017-10-31 09:02:42 +00:00
|
|
|
announce_multiplayer_thread.reset();
|
|
|
|
backend->Delete();
|
2018-10-27 07:40:15 +00:00
|
|
|
registered = false;
|
2017-10-31 09:02:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-07 20:51:11 +00:00
|
|
|
AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback(
|
2017-10-31 09:02:42 +00:00
|
|
|
std::function<void(const Common::WebResult&)> function) {
|
2019-04-01 16:29:59 +00:00
|
|
|
std::lock_guard lock(callback_mutex);
|
2017-10-31 09:02:42 +00:00
|
|
|
auto handle = std::make_shared<std::function<void(const Common::WebResult&)>>(function);
|
|
|
|
error_callbacks.insert(handle);
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
2017-11-07 20:51:11 +00:00
|
|
|
void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) {
|
2019-04-01 16:29:59 +00:00
|
|
|
std::lock_guard lock(callback_mutex);
|
2017-10-31 09:02:42 +00:00
|
|
|
error_callbacks.erase(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
AnnounceMultiplayerSession::~AnnounceMultiplayerSession() {
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
|
2018-10-27 07:40:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 09:02:42 +00:00
|
|
|
void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
|
2019-04-19 14:55:49 +00:00
|
|
|
// Invokes all current bound error callbacks.
|
|
|
|
const auto ErrorCallback = [this](Common::WebResult result) {
|
|
|
|
std::lock_guard<std::mutex> lock(callback_mutex);
|
|
|
|
for (auto callback : error_callbacks) {
|
|
|
|
(*callback)(result);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-10-27 07:40:15 +00:00
|
|
|
if (!registered) {
|
2019-04-19 14:55:49 +00:00
|
|
|
Common::WebResult result = Register();
|
|
|
|
if (result.result_code != Common::WebResult::Code::Success) {
|
|
|
|
ErrorCallback(result);
|
|
|
|
return;
|
|
|
|
}
|
2018-10-27 07:40:15 +00:00
|
|
|
}
|
2019-04-19 14:55:49 +00:00
|
|
|
|
2017-11-10 18:37:26 +00:00
|
|
|
auto update_time = std::chrono::steady_clock::now();
|
2017-10-31 09:02:42 +00:00
|
|
|
std::future<Common::WebResult> future;
|
2017-11-10 18:37:26 +00:00
|
|
|
while (!shutdown_event.WaitUntil(update_time)) {
|
|
|
|
update_time += announce_time_interval;
|
2017-11-05 19:23:22 +00:00
|
|
|
std::shared_ptr<Network::Room> room = Network::GetRoom().lock();
|
|
|
|
if (!room) {
|
2017-11-10 18:37:26 +00:00
|
|
|
break;
|
2017-11-05 19:23:22 +00:00
|
|
|
}
|
|
|
|
if (room->GetState() != Network::Room::State::Open) {
|
2017-11-10 18:37:26 +00:00
|
|
|
break;
|
2017-11-05 19:23:22 +00:00
|
|
|
}
|
2018-10-27 07:40:15 +00:00
|
|
|
UpdateBackendData(room);
|
|
|
|
Common::WebResult result = backend->Update();
|
2018-09-12 16:22:48 +00:00
|
|
|
if (result.result_code != Common::WebResult::Code::Success) {
|
2019-04-19 14:55:49 +00:00
|
|
|
ErrorCallback(result);
|
2017-10-31 09:02:42 +00:00
|
|
|
}
|
2018-10-27 07:40:15 +00:00
|
|
|
if (result.result_string == "404") {
|
|
|
|
registered = false;
|
|
|
|
// Needs to register the room again
|
2019-04-19 14:55:49 +00:00
|
|
|
Common::WebResult result = Register();
|
|
|
|
if (result.result_code != Common::WebResult::Code::Success) {
|
|
|
|
ErrorCallback(result);
|
|
|
|
}
|
2018-10-27 07:40:15 +00:00
|
|
|
}
|
2017-10-31 09:02:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-12 16:22:48 +00:00
|
|
|
AnnounceMultiplayerRoom::RoomList AnnounceMultiplayerSession::GetRoomList() {
|
|
|
|
return backend->GetRoomList();
|
2017-10-31 09:02:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-20 02:42:20 +00:00
|
|
|
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
|
2020-08-20 07:46:35 +00:00
|
|
|
backend = std::make_unique<WebService::RoomJson>(NetSettings::values.web_api_url,
|
|
|
|
NetSettings::values.citra_username,
|
|
|
|
NetSettings::values.citra_token);
|
2019-04-20 02:42:20 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-10-31 09:02:42 +00:00
|
|
|
} // namespace Core
|