[frontend, web] refactor: web service frontend rewrite (#221)

- Automatic verification based on regex
- Token generation button
- Removed unneeded links
- public lobby creation [android]

Signed-off-by: crueter <swurl@swurl.xyz>
Co-authored-by: Aleksandr Popovich <alekpopo@pm.me>
Co-authored-by: Aleksandr Popovich <alekpopo@proton.me>
Reviewed-on: eden-emu/eden#221
Co-authored-by: crueter <swurl@swurl.xyz>
Co-committed-by: crueter <swurl@swurl.xyz>
This commit is contained in:
crueter 2025-07-01 01:44:12 +00:00 committed by crueter
parent 2fe728766e
commit 94c66f98bf
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: BA8734FD0EE46976
34 changed files with 1985 additions and 327 deletions

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/android/id_cache.h"
@ -10,13 +10,17 @@
#include "network/network.h"
#include "android/log.h"
#include "common/settings.h"
#include "web_service/web_backend.h"
#include "web_service/verify_user_jwt.h"
#include "web_service/web_result.h"
#include <thread>
#include <chrono>
namespace IDCache = Common::Android;
AndroidMultiplayer::AndroidMultiplayer(Core::System& system_,
AndroidMultiplayer::AndroidMultiplayer(Core::System &system_,
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
: system{system_}, announce_multiplayer_session(session) {}
@ -27,8 +31,8 @@ void AndroidMultiplayer::AddNetPlayMessage(jint type, jstring msg) {
IDCache::GetAddNetPlayMessage(), type, msg);
}
void AndroidMultiplayer::AddNetPlayMessage(int type, const std::string& msg) {
JNIEnv* env = IDCache::GetEnvForThread();
void AndroidMultiplayer::AddNetPlayMessage(int type, const std::string &msg) {
JNIEnv *env = IDCache::GetEnvForThread();
AddNetPlayMessage(type, Common::Android::ToJString(env, msg));
}
@ -46,7 +50,7 @@ bool AndroidMultiplayer::NetworkInit() {
if (auto member = Network::GetRoomMember().lock()) {
// register the network structs to use in slots and signals
member->BindOnStateChanged([this](const Network::RoomMember::State& state) {
member->BindOnStateChanged([this](const Network::RoomMember::State &state) {
if (state == Network::RoomMember::State::Joined ||
state == Network::RoomMember::State::Moderator) {
NetPlayStatus status;
@ -64,7 +68,7 @@ bool AndroidMultiplayer::NetworkInit() {
AddNetPlayMessage(static_cast<int>(status), msg);
}
});
member->BindOnError([this](const Network::RoomMember::Error& error) {
member->BindOnError([this](const Network::RoomMember::Error &error) {
NetPlayStatus status;
std::string msg;
switch (error) {
@ -107,29 +111,30 @@ bool AndroidMultiplayer::NetworkInit() {
}
AddNetPlayMessage(static_cast<int>(status), msg);
});
member->BindOnStatusMessageReceived([this](const Network::StatusMessageEntry& status_message) {
NetPlayStatus status = NetPlayStatus::NO_ERROR;
std::string msg(status_message.nickname);
switch (status_message.type) {
case Network::IdMemberJoin:
status = NetPlayStatus::MEMBER_JOIN;
break;
case Network::IdMemberLeave:
status = NetPlayStatus::MEMBER_LEAVE;
break;
case Network::IdMemberKicked:
status = NetPlayStatus::MEMBER_KICKED;
break;
case Network::IdMemberBanned:
status = NetPlayStatus::MEMBER_BANNED;
break;
case Network::IdAddressUnbanned:
status = NetPlayStatus::ADDRESS_UNBANNED;
break;
}
AddNetPlayMessage(static_cast<int>(status), msg);
});
member->BindOnChatMessageReceived([this](const Network::ChatEntry& chat) {
member->BindOnStatusMessageReceived(
[this](const Network::StatusMessageEntry &status_message) {
NetPlayStatus status = NetPlayStatus::NO_ERROR;
std::string msg(status_message.nickname);
switch (status_message.type) {
case Network::IdMemberJoin:
status = NetPlayStatus::MEMBER_JOIN;
break;
case Network::IdMemberLeave:
status = NetPlayStatus::MEMBER_LEAVE;
break;
case Network::IdMemberKicked:
status = NetPlayStatus::MEMBER_KICKED;
break;
case Network::IdMemberBanned:
status = NetPlayStatus::MEMBER_BANNED;
break;
case Network::IdAddressUnbanned:
status = NetPlayStatus::ADDRESS_UNBANNED;
break;
}
AddNetPlayMessage(static_cast<int>(status), msg);
});
member->BindOnChatMessageReceived([this](const Network::ChatEntry &chat) {
NetPlayStatus status = NetPlayStatus::CHAT_MESSAGE;
std::string msg(chat.nickname);
msg += ": ";
@ -140,10 +145,14 @@ bool AndroidMultiplayer::NetworkInit() {
return true;
}
NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress, int port,
const std::string& username, const std::string &preferredGameName,
const u64 &preferredGameId, const std::string& password,
const std::string& room_name, int max_players) {
NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string &ipaddress, int port,
const std::string &username,
const std::string &preferredGameName,
const u64 &preferredGameId,
const std::string &password,
const std::string &room_name, int max_players,
bool isPublic) {
auto member = Network::GetRoomMember().lock();
if (!member) {
return NetPlayStatus::NETWORK_ERROR;
@ -168,17 +177,55 @@ NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress
.id = preferredGameId,
};
port = (port == 0) ? Network::DefaultRoomPort : static_cast<u16>(port);
port = (port == 0) ? Network::DefaultRoomPort : static_cast<u16>(port);
if (!room->Create(room_name, "", ipaddress, static_cast<u16>(port), password,
static_cast<u32>(std::min(max_players, 16)), username, game, std::make_unique<Network::VerifyUser::NullBackend>(), {})) {
static_cast<u32>(std::min(max_players, 16)), username, game,
CreateVerifyBackend(isPublic), {})) {
return NetPlayStatus::CREATE_ROOM_ERROR;
}
// public announce session
if (isPublic) {
if (auto session = announce_multiplayer_session.lock()) {
WebService::WebResult result = session->Register();
if (result.result_code != WebService::WebResult::Code::Success) {
LOG_ERROR(WebService, "Failed to announce public room lobby");
room->Destroy();
return NetPlayStatus::CREATE_ROOM_ERROR;
}
session->Start();
} else {
LOG_ERROR(Network, "Failed to start announce session");
}
}
// Failsafe timer to avoid joining before creation
std::this_thread::sleep_for(std::chrono::milliseconds(100));
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP, password, "");
std::string token;
// TODO(alekpop): properly handle the compile definition, it's not working right
//#ifdef ENABLE_WEB_SERVICE
// LOG_INFO(WebService, "Web Service enabled");
if (isPublic) {
WebService::Client client(Settings::values.web_api_url.GetValue(),
Settings::values.eden_username.GetValue(),
Settings::values.eden_token.GetValue());
token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
if (token.empty()) {
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
} else {
LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size());
}
}
//#else
// LOG_INFO(WebService, "Web Service disabled");
//#endif
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP,
password, token);
// Failsafe timer to avoid joining before creation
for (int i = 0; i < 5; i++) {
@ -194,8 +241,9 @@ NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress
return NetPlayStatus::CREATE_ROOM_ERROR;
}
NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress, int port,
const std::string& username, const std::string& password) {
NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string &ipaddress, int port,
const std::string &username,
const std::string &password) {
auto member = Network::GetRoomMember().lock();
if (!member) {
return NetPlayStatus::NETWORK_ERROR;
@ -209,7 +257,8 @@ NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress,
return NetPlayStatus::ALREADY_IN_ROOM;
}
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP, password, "");
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP,
password, "");
// Wait a bit for the connection and join process to complete
std::this_thread::sleep_for(std::chrono::milliseconds(500));
@ -226,7 +275,7 @@ NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress,
return NetPlayStatus::WRONG_PASSWORD;
}
void AndroidMultiplayer::NetPlaySendMessage(const std::string& msg) {
void AndroidMultiplayer::NetPlaySendMessage(const std::string &msg) {
if (auto room = Network::GetRoomMember().lock()) {
if (room->GetState() != Network::RoomMember::State::Joined &&
room->GetState() != Network::RoomMember::State::Moderator) {
@ -237,11 +286,11 @@ void AndroidMultiplayer::NetPlaySendMessage(const std::string& msg) {
}
}
void AndroidMultiplayer::NetPlayKickUser(const std::string& username) {
void AndroidMultiplayer::NetPlayKickUser(const std::string &username) {
if (auto room = Network::GetRoomMember().lock()) {
auto members = room->GetMemberInformation();
auto it = std::find_if(members.begin(), members.end(),
[&username](const Network::RoomMember::MemberInformation& member) {
[&username](const Network::RoomMember::MemberInformation &member) {
return member.nickname == username;
});
if (it != members.end()) {
@ -250,11 +299,11 @@ void AndroidMultiplayer::NetPlayKickUser(const std::string& username) {
}
}
void AndroidMultiplayer::NetPlayBanUser(const std::string& username) {
void AndroidMultiplayer::NetPlayBanUser(const std::string &username) {
if (auto room = Network::GetRoomMember().lock()) {
auto members = room->GetMemberInformation();
auto it = std::find_if(members.begin(), members.end(),
[&username](const Network::RoomMember::MemberInformation& member) {
[&username](const Network::RoomMember::MemberInformation &member) {
return member.nickname == username;
});
if (it != members.end()) {
@ -263,7 +312,7 @@ void AndroidMultiplayer::NetPlayBanUser(const std::string& username) {
}
}
void AndroidMultiplayer::NetPlayUnbanUser(const std::string& username) {
void AndroidMultiplayer::NetPlayUnbanUser(const std::string &username) {
if (auto room = Network::GetRoomMember().lock()) {
room->SendModerationRequest(Network::RoomMessageTypes::IdModUnban, username);
}
@ -278,7 +327,7 @@ std::vector<std::string> AndroidMultiplayer::NetPlayRoomInfo() {
auto room_info = room->GetRoomInformation();
info_list.push_back(room_info.name + "|" + std::to_string(room_info.member_slots));
// all members
for (const auto& member : members) {
for (const auto &member: members) {
info_list.push_back(member.nickname);
}
}
@ -368,14 +417,29 @@ std::vector<std::string> AndroidMultiplayer::NetPlayGetBanList() {
auto [username_bans, ip_bans] = room->GetBanList();
// Add username bans
for (const auto& username : username_bans) {
for (const auto &username: username_bans) {
ban_list.push_back(username);
}
// Add IP bans
for (const auto& ip : ip_bans) {
for (const auto &ip: ip_bans) {
ban_list.push_back(ip);
}
}
return ban_list;
}
std::unique_ptr<Network::VerifyUser::Backend> AndroidMultiplayer::CreateVerifyBackend(bool use_validation) {
std::unique_ptr<Network::VerifyUser::Backend> verify_backend;
if (use_validation) {
//#ifdef ENABLE_WEB_SERVICE
verify_backend =
std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url.GetValue());
//#else
// verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
//#endif
} else {
verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
}
return verify_backend;
}