Skip to content

Commit a5ac666

Browse files
author
N3xoX1
committed
Add network static library
1 parent 19c3550 commit a5ac666

21 files changed

Lines changed: 3550 additions & 0 deletions

nxemu.sln

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "enet", "external\enet.vcxpr
102102
EndProject
103103
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "external\zstd.vcxproj", "{808D773C-086C-4E17-A195-B4AF30EEE86E}"
104104
EndProject
105+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "network", "src\network\network.vcxproj", "{286FF3B0-952D-4193-94AB-C8C300BC85F0}"
106+
EndProject
105107
Global
106108
GlobalSection(SolutionConfigurationPlatforms) = preSolution
107109
Debug|x64 = Debug|x64
@@ -366,6 +368,14 @@ Global
366368
{808D773C-086C-4E17-A195-B4AF30EEE86E}.Release|x64.Build.0 = Release|x64
367369
{808D773C-086C-4E17-A195-B4AF30EEE86E}.Release|x86.ActiveCfg = Release|x64
368370
{808D773C-086C-4E17-A195-B4AF30EEE86E}.Release|x86.Build.0 = Release|x64
371+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Debug|x64.ActiveCfg = Debug|x64
372+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Debug|x64.Build.0 = Debug|x64
373+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Debug|x86.ActiveCfg = Debug|x64
374+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Debug|x86.Build.0 = Debug|x64
375+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Release|x64.ActiveCfg = Release|x64
376+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Release|x64.Build.0 = Release|x64
377+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Release|x86.ActiveCfg = Release|x64
378+
{286FF3B0-952D-4193-94AB-C8C300BC85F0}.Release|x86.Build.0 = Release|x64
369379
EndGlobalSection
370380
GlobalSection(SolutionProperties) = preSolution
371381
HideSolutionNode = FALSE
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#include <chrono>
5+
#include <future>
6+
#include <vector>
7+
#include "announce_multiplayer_session.h"
8+
#include "yuzu_common/announce_multiplayer_room.h"
9+
#include "yuzu_common/yuzu_assert.h"
10+
#include "yuzu_common/settings.h"
11+
#include "network/network.h"
12+
13+
#ifdef ENABLE_WEB_SERVICE
14+
#include "web_service/announce_room_json.h"
15+
#endif
16+
17+
namespace Core {
18+
19+
// Time between room is announced to web_service
20+
static constexpr std::chrono::seconds announce_time_interval(15);
21+
22+
AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_)
23+
: room_network{room_network_} {
24+
#ifdef ENABLE_WEB_SERVICE
25+
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
26+
Settings::values.yuzu_username.GetValue(),
27+
Settings::values.yuzu_token.GetValue());
28+
#else
29+
backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
30+
#endif
31+
}
32+
33+
WebService::WebResult AnnounceMultiplayerSession::Register() {
34+
auto room = room_network.GetRoom().lock();
35+
if (!room) {
36+
return WebService::WebResult{WebService::WebResult::Code::LibError,
37+
"Network is not initialized", ""};
38+
}
39+
if (room->GetState() != Network::Room::State::Open) {
40+
return WebService::WebResult{WebService::WebResult::Code::LibError, "Room is not open", ""};
41+
}
42+
UpdateBackendData(room);
43+
WebService::WebResult result = backend->Register();
44+
if (result.result_code != WebService::WebResult::Code::Success) {
45+
return result;
46+
}
47+
LOG_INFO(WebService, "Room has been registered");
48+
room->SetVerifyUID(result.returned_data);
49+
registered = true;
50+
return WebService::WebResult{WebService::WebResult::Code::Success, "", ""};
51+
}
52+
53+
void AnnounceMultiplayerSession::Start() {
54+
if (announce_multiplayer_thread) {
55+
Stop();
56+
}
57+
shutdown_event.Reset();
58+
announce_multiplayer_thread =
59+
std::make_unique<std::thread>(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this);
60+
}
61+
62+
void AnnounceMultiplayerSession::Stop() {
63+
if (announce_multiplayer_thread) {
64+
shutdown_event.Set();
65+
announce_multiplayer_thread->join();
66+
announce_multiplayer_thread.reset();
67+
backend->Delete();
68+
registered = false;
69+
}
70+
}
71+
72+
AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback(
73+
std::function<void(const WebService::WebResult&)> function) {
74+
std::lock_guard lock(callback_mutex);
75+
auto handle = std::make_shared<std::function<void(const WebService::WebResult&)>>(function);
76+
error_callbacks.insert(handle);
77+
return handle;
78+
}
79+
80+
void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) {
81+
std::lock_guard lock(callback_mutex);
82+
error_callbacks.erase(handle);
83+
}
84+
85+
AnnounceMultiplayerSession::~AnnounceMultiplayerSession() {
86+
Stop();
87+
}
88+
89+
void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room> room) {
90+
Network::RoomInformation room_information = room->GetRoomInformation();
91+
std::vector<AnnounceMultiplayerRoom::Member> memberlist = room->GetRoomMemberList();
92+
backend->SetRoomInformation(room_information.name, room_information.description,
93+
room_information.port, room_information.member_slots,
94+
Network::network_version, room->HasPassword(),
95+
room_information.preferred_game);
96+
backend->ClearPlayers();
97+
for (const auto& member : memberlist) {
98+
backend->AddPlayer(member);
99+
}
100+
}
101+
102+
void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
103+
// Invokes all current bound error callbacks.
104+
const auto ErrorCallback = [this](WebService::WebResult result) {
105+
std::lock_guard lock(callback_mutex);
106+
for (auto callback : error_callbacks) {
107+
(*callback)(result);
108+
}
109+
};
110+
111+
if (!registered) {
112+
WebService::WebResult result = Register();
113+
if (result.result_code != WebService::WebResult::Code::Success) {
114+
ErrorCallback(result);
115+
return;
116+
}
117+
}
118+
119+
auto update_time = std::chrono::steady_clock::now();
120+
std::future<WebService::WebResult> future;
121+
while (!shutdown_event.WaitUntil(update_time)) {
122+
update_time += announce_time_interval;
123+
auto room = room_network.GetRoom().lock();
124+
if (!room) {
125+
break;
126+
}
127+
if (room->GetState() != Network::Room::State::Open) {
128+
break;
129+
}
130+
UpdateBackendData(room);
131+
WebService::WebResult result = backend->Update();
132+
if (result.result_code != WebService::WebResult::Code::Success) {
133+
ErrorCallback(result);
134+
}
135+
if (result.result_string == "404") {
136+
registered = false;
137+
// Needs to register the room again
138+
WebService::WebResult register_result = Register();
139+
if (register_result.result_code != WebService::WebResult::Code::Success) {
140+
ErrorCallback(register_result);
141+
}
142+
}
143+
}
144+
}
145+
146+
AnnounceMultiplayerRoom::RoomList AnnounceMultiplayerSession::GetRoomList() {
147+
return backend->GetRoomList();
148+
}
149+
150+
bool AnnounceMultiplayerSession::IsRunning() const {
151+
return announce_multiplayer_thread != nullptr;
152+
}
153+
154+
void AnnounceMultiplayerSession::UpdateCredentials() {
155+
ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
156+
157+
#ifdef ENABLE_WEB_SERVICE
158+
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
159+
Settings::values.yuzu_username.GetValue(),
160+
Settings::values.yuzu_token.GetValue());
161+
#endif
162+
}
163+
164+
} // namespace Core
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#pragma once
5+
6+
#include <atomic>
7+
#include <functional>
8+
#include <memory>
9+
#include <mutex>
10+
#include <set>
11+
#include <thread>
12+
#include "yuzu_common/announce_multiplayer_room.h"
13+
#include "yuzu_common/common_types.h"
14+
#include "yuzu_common/thread.h"
15+
16+
namespace Network {
17+
class Room;
18+
class RoomNetwork;
19+
} // namespace Network
20+
21+
namespace Core {
22+
23+
/**
24+
* Instruments AnnounceMultiplayerRoom::Backend.
25+
* Creates a thread that regularly updates the room information and submits them
26+
* An async get of room information is also possible
27+
*/
28+
class AnnounceMultiplayerSession {
29+
public:
30+
using CallbackHandle = std::shared_ptr<std::function<void(const WebService::WebResult&)>>;
31+
AnnounceMultiplayerSession(Network::RoomNetwork& room_network_);
32+
~AnnounceMultiplayerSession();
33+
34+
/**
35+
* Allows to bind a function that will get called if the announce encounters an error
36+
* @param function The function that gets called
37+
* @return A handle that can be used the unbind the function
38+
*/
39+
CallbackHandle BindErrorCallback(std::function<void(const WebService::WebResult&)> function);
40+
41+
/**
42+
* Unbind a function from the error callbacks
43+
* @param handle The handle for the function that should get unbind
44+
*/
45+
void UnbindErrorCallback(CallbackHandle handle);
46+
47+
/**
48+
* Registers a room to web services
49+
* @return The result of the registration attempt.
50+
*/
51+
WebService::WebResult Register();
52+
53+
/**
54+
* Starts the announce of a room to web services
55+
*/
56+
void Start();
57+
58+
/**
59+
* Stops the announce to web services
60+
*/
61+
void Stop();
62+
63+
/**
64+
* Returns a list of all room information the backend got
65+
* @param func A function that gets executed when the async get finished, e.g. a signal
66+
* @return a list of rooms received from the web service
67+
*/
68+
AnnounceMultiplayerRoom::RoomList GetRoomList();
69+
70+
/**
71+
* Whether the announce session is still running
72+
*/
73+
bool IsRunning() const;
74+
75+
/**
76+
* Recreates the backend, updating the credentials.
77+
* This can only be used when the announce session is not running.
78+
*/
79+
void UpdateCredentials();
80+
81+
private:
82+
void UpdateBackendData(std::shared_ptr<Network::Room> room);
83+
void AnnounceMultiplayerLoop();
84+
85+
Common::Event shutdown_event;
86+
std::mutex callback_mutex;
87+
std::set<CallbackHandle> error_callbacks;
88+
std::unique_ptr<std::thread> announce_multiplayer_thread;
89+
90+
/// Backend interface that logs fields
91+
std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend;
92+
93+
std::atomic_bool registered = false; ///< Whether the room has been registered
94+
95+
Network::RoomNetwork& room_network;
96+
};
97+
98+
} // namespace Core

src/network/network.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#include "yuzu_common/yuzu_assert.h"
5+
#include "yuzu_common/logging/log.h"
6+
#include "enet/enet.h"
7+
#include "network/network.h"
8+
9+
namespace Network {
10+
11+
RoomNetwork::RoomNetwork() {
12+
m_room = std::make_shared<Room>();
13+
m_room_member = std::make_shared<RoomMember>();
14+
}
15+
16+
bool RoomNetwork::Init() {
17+
if (enet_initialize() != 0) {
18+
LOG_ERROR(Network, "Error initializing ENet");
19+
return false;
20+
}
21+
m_room = std::make_shared<Room>();
22+
m_room_member = std::make_shared<RoomMember>();
23+
LOG_DEBUG(Network, "initialized OK");
24+
return true;
25+
}
26+
27+
std::weak_ptr<Room> RoomNetwork::GetRoom() {
28+
return m_room;
29+
}
30+
31+
std::weak_ptr<RoomMember> RoomNetwork::GetRoomMember() {
32+
return m_room_member;
33+
}
34+
35+
void RoomNetwork::Shutdown() {
36+
if (m_room_member) {
37+
if (m_room_member->IsConnected())
38+
m_room_member->Leave();
39+
m_room_member.reset();
40+
}
41+
if (m_room) {
42+
if (m_room->GetState() == Room::State::Open)
43+
m_room->Destroy();
44+
m_room.reset();
45+
}
46+
enet_deinitialize();
47+
LOG_DEBUG(Network, "shutdown OK");
48+
}
49+
50+
} // namespace Network

src/network/network.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#pragma once
5+
6+
#include <memory>
7+
#include "network/room.h"
8+
#include "network/room_member.h"
9+
10+
namespace Network {
11+
12+
class RoomNetwork {
13+
public:
14+
RoomNetwork();
15+
16+
/// Initializes and registers the network device, the room, and the room member.
17+
bool Init();
18+
19+
/// Returns a pointer to the room handle
20+
std::weak_ptr<Room> GetRoom();
21+
22+
/// Returns a pointer to the room member handle
23+
std::weak_ptr<RoomMember> GetRoomMember();
24+
25+
/// Unregisters the network device, the room, and the room member and shut them down.
26+
void Shutdown();
27+
28+
private:
29+
std::shared_ptr<RoomMember> m_room_member; ///< RoomMember (Client) for network games
30+
std::shared_ptr<Room> m_room; ///< Room (Server) for network games
31+
};
32+
33+
} // namespace Network

0 commit comments

Comments
 (0)