mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-25 19:55:50 +00:00
refactor: migrate SlippiUser to be backed by a Rust layer (#6)
* fix: user folder path for macOS * fix: slippi_rust_extensions -> slippi-rust-extensions when linking * fix: set application support folder to dolphin-beta and fix log
This commit is contained in:
parent
7e201a68ea
commit
03887849e5
12 changed files with 119 additions and 364 deletions
2
Externals/SlippiRustExtensions
vendored
2
Externals/SlippiRustExtensions
vendored
|
@ -1 +1 @@
|
|||
Subproject commit af04c6c1878731da5ccc7e1742f355af54755bb5
|
||||
Subproject commit c5643d5d2cb7073b52dcfbdb7836771b264bc33d
|
|
@ -154,7 +154,7 @@ PUBLIC
|
|||
fmt::fmt
|
||||
${MBEDTLS_LIBRARIES}
|
||||
minizip-ng
|
||||
slippi_rust_extensions
|
||||
slippi-rust-extensions
|
||||
|
||||
PRIVATE
|
||||
${CURL_LIBRARIES}
|
||||
|
|
|
@ -754,6 +754,19 @@ std::string GetBundleDirectory()
|
|||
|
||||
return app_bundle_path;
|
||||
}
|
||||
|
||||
std::string GetApplicationSupportDirectory()
|
||||
{
|
||||
std::string dir =
|
||||
File::GetHomeDirectory() + "/Library/Application Support/com.project-slippi.dolphin-beta";
|
||||
|
||||
if (!CreateDir(dir))
|
||||
{
|
||||
ERROR_LOG_FMT(COMMON, "Unable to create Application Support directory: {}", dir);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string GetExePath()
|
||||
|
|
|
@ -234,6 +234,7 @@ void SetSysDirectory(const std::string& path);
|
|||
|
||||
#ifdef __APPLE__
|
||||
std::string GetBundleDirectory();
|
||||
std::string GetApplicationSupportDirectory();
|
||||
#endif
|
||||
|
||||
std::string GetExePath();
|
||||
|
|
|
@ -61,8 +61,7 @@ enum class LogType : int
|
|||
SLIPPI,
|
||||
SLIPPI_ONLINE,
|
||||
SLIPPI_RUST_DEPENDENCIES,
|
||||
SLIPPI_RUST_EXI,
|
||||
SLIPPI_RUST_GAME_REPORTER,
|
||||
SLIPPI_RUST_ONLINE,
|
||||
SLIPPI_RUST_JUKEBOX,
|
||||
SP1,
|
||||
SYMBOLS,
|
||||
|
|
|
@ -166,9 +166,7 @@ LogManager::LogManager()
|
|||
m_log[LogType::SLIPPI_ONLINE] = {"SLIPPI_ONLINE", "Slippi Online"};
|
||||
m_log[LogType::SLIPPI_RUST_DEPENDENCIES] = {"SLIPPI_RUST_DEPENDENCIES",
|
||||
"[Rust] Slippi Dependencies", false, true};
|
||||
m_log[LogType::SLIPPI_RUST_EXI] = {"SLIPPI_RUST_EXI", "[Rust] Slippi EXI", false, true};
|
||||
m_log[LogType::SLIPPI_RUST_GAME_REPORTER] = {"SLIPPI_RUST_GAME_REPORTER",
|
||||
"[Rust] Slippi Game Reporter", false, true};
|
||||
m_log[LogType::SLIPPI_RUST_ONLINE] = {"SLIPPI_RUST_ONLINE,", "[Rust] Slippi Online", false, true};
|
||||
m_log[LogType::SLIPPI_RUST_JUKEBOX] = {"SLIPPI_RUST_JUKEBOX", "[Rust] Slippi Jukebox", false,
|
||||
true};
|
||||
m_log[LogType::SP1] = {"SP1", "Serial Port 1"};
|
||||
|
|
|
@ -141,9 +141,17 @@ CEXISlippi::CEXISlippi(Core::System& system, const std::string current_file_name
|
|||
{
|
||||
INFO_LOG_FMT(SLIPPI, "EXI SLIPPI Constructor called.");
|
||||
|
||||
slprs_exi_device_ptr = slprs_exi_device_create(current_file_name.c_str(), OSDMessageHandler);
|
||||
std::string user_file_path = File::GetUserPath(F_USERJSON_IDX);
|
||||
|
||||
user = std::make_unique<SlippiUser>();
|
||||
SlippiRustEXIConfig slprs_exi_config;
|
||||
slprs_exi_config.iso_path = current_file_name.c_str();
|
||||
slprs_exi_config.user_json_path = user_file_path.c_str();
|
||||
slprs_exi_config.scm_slippi_semver_str = Common::GetSemVerStr().c_str();
|
||||
slprs_exi_config.osd_add_msg_fn = OSDMessageHandler;
|
||||
|
||||
slprs_exi_device_ptr = slprs_exi_device_create(slprs_exi_config);
|
||||
|
||||
user = std::make_unique<SlippiUser>(slprs_exi_device_ptr);
|
||||
g_playback_status = std::make_unique<SlippiPlaybackStatus>();
|
||||
matchmaking = std::make_unique<SlippiMatchmaking>(user.get());
|
||||
game_file_loader = std::make_unique<SlippiGameFileLoader>();
|
||||
|
@ -287,9 +295,7 @@ CEXISlippi::~CEXISlippi()
|
|||
if (active_match_id.find("mode.ranked") != std::string::npos)
|
||||
{
|
||||
ERROR_LOG_FMT(SLIPPI_ONLINE, "Exit during in-progress ranked game: {}", active_match_id);
|
||||
auto user_info = user->GetUserInfo();
|
||||
slprs_exi_device_report_match_abandonment(slprs_exi_device_ptr, user_info.uid.c_str(),
|
||||
user_info.play_key.c_str(), active_match_id.c_str());
|
||||
slprs_exi_device_report_match_abandonment(slprs_exi_device_ptr, active_match_id.c_str());
|
||||
}
|
||||
handleConnectionCleanup();
|
||||
|
||||
|
@ -2714,7 +2720,6 @@ void CEXISlippi::handleChatMessage(u8* payload)
|
|||
|
||||
if (slippi_netplay)
|
||||
{
|
||||
auto user_info = user->GetUserInfo();
|
||||
auto packet = std::make_unique<sf::Packet>();
|
||||
// OSD::AddMessage("[Me]: "+ msg, OSD::Duration::VERY_LONG, OSD::Color::YELLOW);
|
||||
slippi_netplay->remote_sent_chat_message_id = message_id;
|
||||
|
@ -3017,10 +3022,8 @@ void CEXISlippi::handleCompleteSet(const SlippiExiTypes::ReportSetCompletionQuer
|
|||
if (last_match_id.find("mode.ranked") != std::string::npos)
|
||||
{
|
||||
INFO_LOG_FMT(SLIPPI_ONLINE, "Reporting set completion: {}", last_match_id);
|
||||
auto user_info = user->GetUserInfo();
|
||||
|
||||
slprs_exi_device_report_match_completion(slprs_exi_device_ptr, user_info.uid.c_str(),
|
||||
user_info.play_key.c_str(), last_match_id.c_str(),
|
||||
slprs_exi_device_report_match_completion(slprs_exi_device_ptr, last_match_id.c_str(),
|
||||
query.end_mode);
|
||||
}
|
||||
}
|
||||
|
@ -3031,12 +3034,10 @@ void CEXISlippi::handleGetPlayerSettings()
|
|||
|
||||
SlippiExiTypes::GetPlayerSettingsResponse resp = {};
|
||||
|
||||
std::vector<std::vector<std::string>> messages_by_player = {
|
||||
SlippiUser::default_chat_messages, SlippiUser::default_chat_messages,
|
||||
SlippiUser::default_chat_messages, SlippiUser::default_chat_messages};
|
||||
std::vector<std::vector<std::string>> messages_by_player = {{}, {}, {}, {}};
|
||||
|
||||
// These chat messages will be used when previewing messages
|
||||
auto user_chat_messages = user->GetUserInfo().chat_messages;
|
||||
auto user_chat_messages = user->GetUserChatMessages();
|
||||
if (user_chat_messages.size() == 16)
|
||||
{
|
||||
messages_by_player[0] = user_chat_messages;
|
||||
|
@ -3051,6 +3052,13 @@ void CEXISlippi::handleGetPlayerSettings()
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// If any of the users in the chat messages vector have a payload that is incorrect,
|
||||
// force that player to the default chat messages. A valid payload is 16 entries.
|
||||
if (messages_by_player[i].size() != 16)
|
||||
{
|
||||
messages_by_player[i] = user->GetDefaultChatMessages();
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
auto str = ConvertStringForGame(messages_by_player[i][j], MAX_MESSAGE_LENGTH);
|
||||
|
|
|
@ -540,15 +540,19 @@ void SlippiMatchmaking::handleMatchmaking()
|
|||
player_info.display_name = el.value("displayName", "");
|
||||
player_info.connect_code = el.value("connectCode", "");
|
||||
player_info.port = el.value("port", 0);
|
||||
player_info.chat_messages = SlippiUser::default_chat_messages;
|
||||
if (el["chatMessages"].is_array())
|
||||
{
|
||||
player_info.chat_messages = el.value("chatMessages", SlippiUser::default_chat_messages);
|
||||
player_info.chat_messages = el.value("chatMessages", m_user->GetDefaultChatMessages());
|
||||
if (player_info.chat_messages.size() != 16)
|
||||
{
|
||||
player_info.chat_messages = SlippiUser::default_chat_messages;
|
||||
player_info.chat_messages = m_user->GetDefaultChatMessages();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player_info.chat_messages = m_user->GetDefaultChatMessages();
|
||||
}
|
||||
|
||||
m_player_info.push_back(player_info);
|
||||
|
||||
if (is_local)
|
||||
|
|
|
@ -1,363 +1,94 @@
|
|||
#include "SlippiUser.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "AtlBase.h"
|
||||
#include "AtlConv.h"
|
||||
#endif
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/Version.h"
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "SlippiRustExtensions.h"
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
|
||||
#include <json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
const std::vector<std::string> SlippiUser::default_chat_messages = {
|
||||
"ggs",
|
||||
"one more",
|
||||
"brb",
|
||||
"good luck",
|
||||
|
||||
"well played",
|
||||
"that was fun",
|
||||
"thanks",
|
||||
"too good",
|
||||
|
||||
"sorry",
|
||||
"my b",
|
||||
"lol",
|
||||
"wow",
|
||||
|
||||
"gotta go",
|
||||
"one sec",
|
||||
"let's play again later",
|
||||
"bad connection",
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MAX_SYSTEM_PROGRAM (4096)
|
||||
static void system_hidden(const char* cmd)
|
||||
// Takes a RustChatMessages pointer and extracts messages from them, then
|
||||
// frees the underlying memory safely.
|
||||
std::vector<std::string> ConvertChatMessagesFromRust(RustChatMessages* rsMessages)
|
||||
{
|
||||
PROCESS_INFORMATION p_info;
|
||||
STARTUPINFO s_info;
|
||||
std::vector<std::string> chatMessages;
|
||||
|
||||
memset(&s_info, 0, sizeof(s_info));
|
||||
memset(&p_info, 0, sizeof(p_info));
|
||||
s_info.cb = sizeof(s_info);
|
||||
|
||||
wchar_t utf16cmd[MAX_SYSTEM_PROGRAM] = {0};
|
||||
MultiByteToWideChar(CP_UTF8, 0, cmd, -1, utf16cmd, MAX_SYSTEM_PROGRAM);
|
||||
if (CreateProcessW(NULL, utf16cmd, NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL, &s_info, &p_info))
|
||||
for (int i = 0; i < rsMessages->len; i++)
|
||||
{
|
||||
DWORD ExitCode;
|
||||
WaitForSingleObject(p_info.hProcess, INFINITE);
|
||||
GetExitCodeProcess(p_info.hProcess, &ExitCode);
|
||||
CloseHandle(p_info.hProcess);
|
||||
CloseHandle(p_info.hThread);
|
||||
std::string message = std::string(rsMessages->data[i]);
|
||||
chatMessages.push_back(message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void RunSystemCommand(const std::string& command)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_wsystem(UTF8ToTStr(command).c_str());
|
||||
#else
|
||||
system(command.c_str());
|
||||
#endif
|
||||
slprs_user_free_messages(rsMessages);
|
||||
|
||||
return chatMessages;
|
||||
}
|
||||
|
||||
static size_t receive(char* ptr, size_t size, size_t nmemb, void* rcvBuf)
|
||||
SlippiUser::SlippiUser(uintptr_t rs_exi_device_ptr)
|
||||
{
|
||||
size_t len = size * nmemb;
|
||||
INFO_LOG_FMT(SLIPPI_ONLINE, "[User] Received data: {}", len);
|
||||
|
||||
std::string* buf = (std::string*)rcvBuf;
|
||||
|
||||
buf->insert(buf->end(), ptr, ptr + len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
SlippiUser::SlippiUser()
|
||||
{
|
||||
CURL* curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &receive);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000);
|
||||
|
||||
// Set up HTTP Headers
|
||||
m_curl_header_list = curl_slist_append(m_curl_header_list, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_curl_header_list);
|
||||
|
||||
#ifdef _WIN32
|
||||
// ALPN support is enabled by default but requires Windows >= 8.1.
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, false);
|
||||
#endif
|
||||
|
||||
m_curl = curl;
|
||||
}
|
||||
slprs_exi_device_ptr = rs_exi_device_ptr;
|
||||
}
|
||||
|
||||
SlippiUser::~SlippiUser()
|
||||
{
|
||||
// Wait for thread to terminate
|
||||
m_run_thread = false;
|
||||
if (m_file_listen_thread.joinable())
|
||||
m_file_listen_thread.join();
|
||||
|
||||
if (m_curl)
|
||||
{
|
||||
curl_slist_free_all(m_curl_header_list);
|
||||
curl_easy_cleanup(m_curl);
|
||||
}
|
||||
// Do nothing, the exi ptr is cleaned up by the exi device
|
||||
}
|
||||
|
||||
bool SlippiUser::AttemptLogin()
|
||||
{
|
||||
std::string user_file_path = getUserFilePath();
|
||||
|
||||
// TODO: Remove a couple updates after ranked
|
||||
#ifndef __APPLE__
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string old_user_file_path = File::GetExeDirectory() + DIR_SEP + "user.json";
|
||||
#else
|
||||
std::string old_user_file_path = File::GetUserPath(D_USER_IDX) + DIR_SEP + "user.json";
|
||||
#endif
|
||||
if (File::Exists(old_user_file_path) && !File::Rename(old_user_file_path, user_file_path))
|
||||
{
|
||||
WARN_LOG_FMT(SLIPPI_ONLINE, "Could not move file {} to {}", old_user_file_path,
|
||||
user_file_path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get user file
|
||||
std::string user_file_contents;
|
||||
File::ReadFileToString(user_file_path, user_file_contents);
|
||||
|
||||
m_user_info = parseFile(user_file_contents);
|
||||
|
||||
m_is_logged_in = !m_user_info.uid.empty();
|
||||
if (m_is_logged_in)
|
||||
{
|
||||
overwriteFromServer();
|
||||
WARN_LOG_FMT(SLIPPI_ONLINE, "Found user {} ({})", m_user_info.display_name, m_user_info.uid);
|
||||
}
|
||||
|
||||
return m_is_logged_in;
|
||||
return slprs_user_attempt_login(slprs_exi_device_ptr);
|
||||
}
|
||||
|
||||
void SlippiUser::OpenLogInPage()
|
||||
{
|
||||
std::string url = "https://slippi.gg/online/enable";
|
||||
std::string path = getUserFilePath();
|
||||
|
||||
#ifdef _WIN32
|
||||
// On windows, sometimes the path can have backslashes and slashes mixed, convert all to
|
||||
// backslashes
|
||||
path = ReplaceAll(path, "\\", "\\");
|
||||
path = ReplaceAll(path, "/", "\\");
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
char* escaped_path = curl_easy_escape(nullptr, path.c_str(), static_cast<int>(path.length()));
|
||||
path = std::string(escaped_path);
|
||||
curl_free(escaped_path);
|
||||
#endif
|
||||
|
||||
std::string full_url = url + "?path=" + path;
|
||||
|
||||
INFO_LOG_FMT(SLIPPI_ONLINE, "[User] Login at path: {}", full_url);
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string command = "explorer \"" + full_url + "\"";
|
||||
#elif defined(__APPLE__)
|
||||
std::string command = "open \"" + full_url + "\"";
|
||||
#else
|
||||
std::string command = "xdg-open \"" + full_url + "\""; // Linux
|
||||
#endif
|
||||
|
||||
RunSystemCommand(command);
|
||||
}
|
||||
|
||||
void SlippiUser::UpdateApp()
|
||||
{
|
||||
std::string url = "https://slippi.gg/downloads?update=true";
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string command = "explorer \"" + url + "\"";
|
||||
#elif defined(__APPLE__)
|
||||
std::string command = "open \"" + url + "\"";
|
||||
#else
|
||||
std::string command = "xdg-open \"" + url + "\""; // Linux
|
||||
#endif
|
||||
|
||||
RunSystemCommand(command);
|
||||
slprs_user_open_login_page(slprs_exi_device_ptr);
|
||||
}
|
||||
|
||||
void SlippiUser::ListenForLogIn()
|
||||
{
|
||||
if (m_run_thread)
|
||||
return;
|
||||
slprs_user_listen_for_login(slprs_exi_device_ptr);
|
||||
}
|
||||
|
||||
if (m_file_listen_thread.joinable())
|
||||
m_file_listen_thread.join();
|
||||
|
||||
m_run_thread = true;
|
||||
m_file_listen_thread = std::thread(&SlippiUser::FileListenThread, this);
|
||||
bool SlippiUser::UpdateApp()
|
||||
{
|
||||
return slprs_user_update_app(slprs_exi_device_ptr);
|
||||
}
|
||||
|
||||
void SlippiUser::LogOut()
|
||||
{
|
||||
m_run_thread = false;
|
||||
deleteFile();
|
||||
|
||||
UserInfo empty_user;
|
||||
m_is_logged_in = false;
|
||||
m_user_info = empty_user;
|
||||
slprs_user_logout(slprs_exi_device_ptr);
|
||||
}
|
||||
|
||||
void SlippiUser::OverwriteLatestVersion(std::string version)
|
||||
{
|
||||
m_user_info.latest_version = version;
|
||||
slprs_user_overwrite_latest_version(slprs_exi_device_ptr, version.c_str());
|
||||
}
|
||||
|
||||
SlippiUser::UserInfo SlippiUser::GetUserInfo()
|
||||
{
|
||||
return m_user_info;
|
||||
SlippiUser::UserInfo userInfo;
|
||||
|
||||
RustUserInfo* info = slprs_user_get_info(slprs_exi_device_ptr);
|
||||
userInfo.uid = std::string(info->uid);
|
||||
userInfo.play_key = std::string(info->play_key);
|
||||
userInfo.display_name = std::string(info->display_name);
|
||||
userInfo.connect_code = std::string(info->connect_code);
|
||||
userInfo.latest_version = std::string(info->latest_version);
|
||||
slprs_user_free_info(info);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
std::vector<std::string> SlippiUser::GetDefaultChatMessages()
|
||||
{
|
||||
RustChatMessages* chatMessages = slprs_user_get_default_messages(slprs_exi_device_ptr);
|
||||
return ConvertChatMessagesFromRust(chatMessages);
|
||||
}
|
||||
|
||||
std::vector<std::string> SlippiUser::GetUserChatMessages()
|
||||
{
|
||||
RustChatMessages* chatMessages = slprs_user_get_messages(slprs_exi_device_ptr);
|
||||
return ConvertChatMessagesFromRust(chatMessages);
|
||||
}
|
||||
|
||||
bool SlippiUser::IsLoggedIn()
|
||||
{
|
||||
return m_is_logged_in;
|
||||
}
|
||||
|
||||
void SlippiUser::FileListenThread()
|
||||
{
|
||||
while (m_run_thread)
|
||||
{
|
||||
if (AttemptLogin())
|
||||
{
|
||||
m_run_thread = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Common::SleepCurrentThread(500);
|
||||
}
|
||||
}
|
||||
|
||||
// On Linux platforms, the user.json file lives in the XDG_CONFIG_HOME/SlippiOnline
|
||||
// directory in order to deal with the fact that we want the configuration for AppImage
|
||||
// builds to be mutable.
|
||||
std::string SlippiUser::getUserFilePath()
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
std::string user_file_path =
|
||||
File::GetBundleDirectory() + "/Contents/Resources" + DIR_SEP + "user.json";
|
||||
#else
|
||||
std::string user_file_path = File::GetUserPath(F_USERJSON_IDX);
|
||||
INFO_LOG_FMT(SLIPPI, "{}", user_file_path);
|
||||
#endif
|
||||
return user_file_path;
|
||||
}
|
||||
|
||||
inline std::string readString(json obj, std::string key)
|
||||
{
|
||||
auto item = obj.find(key);
|
||||
if (item == obj.end() || item.value().is_null())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return obj[key];
|
||||
}
|
||||
|
||||
SlippiUser::UserInfo SlippiUser::parseFile(std::string file_contents)
|
||||
{
|
||||
UserInfo info;
|
||||
info.file_contents = file_contents;
|
||||
|
||||
auto res = json::parse(file_contents, nullptr, false);
|
||||
if (res.is_discarded() || !res.is_object())
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
info.uid = readString(res, "uid");
|
||||
info.display_name = readString(res, "displayName");
|
||||
info.play_key = readString(res, "playKey");
|
||||
info.connect_code = readString(res, "connectCode");
|
||||
info.latest_version = readString(res, "latestVersion");
|
||||
info.chat_messages = SlippiUser::default_chat_messages;
|
||||
if (res["chatMessages"].is_array())
|
||||
{
|
||||
info.chat_messages = res.value("chatMessages", SlippiUser::default_chat_messages);
|
||||
if (info.chat_messages.size() != 16)
|
||||
{
|
||||
info.chat_messages = SlippiUser::default_chat_messages;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void SlippiUser::deleteFile()
|
||||
{
|
||||
std::string user_file_path = getUserFilePath();
|
||||
File::Delete(user_file_path);
|
||||
}
|
||||
|
||||
void SlippiUser::overwriteFromServer()
|
||||
{
|
||||
if (!m_curl)
|
||||
return;
|
||||
|
||||
// Perform curl request
|
||||
std::string resp;
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL,
|
||||
(URL_START + "/" + m_user_info.uid + "?additionalFields=chatMessages").c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &resp);
|
||||
CURLcode res = curl_easy_perform(m_curl);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
ERROR_LOG_FMT(SLIPPI, "[User] Error fetching user info from server, code: {}",
|
||||
static_cast<u8>(res));
|
||||
return;
|
||||
}
|
||||
|
||||
long response_code;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
if (response_code != 200)
|
||||
{
|
||||
ERROR_LOG_FMT(SLIPPI, "[User] Server responded with non-success status: {}", response_code);
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite user info with data from server
|
||||
auto r = json::parse(resp, nullptr, false);
|
||||
m_user_info.connect_code = r.value("connectCode", m_user_info.connect_code);
|
||||
m_user_info.latest_version = r.value("latestVersion", m_user_info.latest_version);
|
||||
m_user_info.display_name = r.value("displayName", m_user_info.display_name);
|
||||
if (r["chatMessages"].is_array())
|
||||
{
|
||||
m_user_info.chat_messages = r.value("chatMessages", SlippiUser::default_chat_messages);
|
||||
if (m_user_info.chat_messages.size() != 16)
|
||||
{
|
||||
m_user_info.chat_messages = SlippiUser::default_chat_messages;
|
||||
}
|
||||
}
|
||||
return slprs_user_get_is_logged_in(slprs_exi_device_ptr);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,18 @@
|
|||
#include <vector>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
// This class is currently a shim for the Rust user interface. We're doing it this way
|
||||
// to begin migrating things over without needing to do larger invasive changes.
|
||||
//
|
||||
// The remaining methods in here are simply layers that direct the call over to the Rust side.
|
||||
// A quirk of this is that we're using the EXI device pointer, so this class absolutely
|
||||
// cannot outlive the EXI device - but we control that and just need to do our due diligence
|
||||
// when making changes.
|
||||
class SlippiUser
|
||||
{
|
||||
public:
|
||||
// This type is filled in with data from the Rust side.
|
||||
// Eventually, this entire class will disappear.
|
||||
struct UserInfo
|
||||
{
|
||||
std::string uid = "";
|
||||
|
@ -25,35 +34,22 @@ public:
|
|||
std::vector<std::string> chat_messages;
|
||||
};
|
||||
|
||||
SlippiUser();
|
||||
SlippiUser(uintptr_t rs_exi_device_ptr);
|
||||
~SlippiUser();
|
||||
|
||||
bool AttemptLogin();
|
||||
void OpenLogInPage();
|
||||
void UpdateApp();
|
||||
bool UpdateApp();
|
||||
void ListenForLogIn();
|
||||
void LogOut();
|
||||
void OverwriteLatestVersion(std::string version);
|
||||
UserInfo GetUserInfo();
|
||||
std::vector<std::string> GetUserChatMessages();
|
||||
std::vector<std::string> GetDefaultChatMessages();
|
||||
bool IsLoggedIn();
|
||||
void FileListenThread();
|
||||
|
||||
const static std::vector<std::string> default_chat_messages;
|
||||
|
||||
protected:
|
||||
std::string getUserFilePath();
|
||||
UserInfo parseFile(std::string file_contents);
|
||||
void deleteFile();
|
||||
void overwriteFromServer();
|
||||
|
||||
UserInfo m_user_info;
|
||||
bool m_is_logged_in = false;
|
||||
|
||||
const std::string URL_START = "https://users-rest-dot-slippi.uc.r.appspot.com/user";
|
||||
CURL* m_curl = nullptr;
|
||||
struct curl_slist* m_curl_header_list = nullptr;
|
||||
std::vector<char> m_receive_buf;
|
||||
|
||||
std::thread m_file_listen_thread;
|
||||
std::atomic<bool> m_run_thread;
|
||||
// A pointer to a "shadow" EXI Device that lives on the Rust side of things.
|
||||
// Do *not* do any cleanup of this! The EXI device will handle it.
|
||||
uintptr_t slprs_exi_device_ptr;
|
||||
};
|
||||
|
|
|
@ -565,7 +565,7 @@ endif()
|
|||
#endif()
|
||||
|
||||
corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/Externals/SlippiRustExtensions/Cargo.toml ${RUST_FEATURES})
|
||||
target_link_libraries(dolphin-emu PUBLIC slippi_rust_extensions)
|
||||
target_link_libraries(dolphin-emu PUBLIC slippi-rust-extensions)
|
||||
|
||||
if(APPLE)
|
||||
include(BundleUtilities)
|
||||
|
|
|
@ -410,9 +410,14 @@ void SetUserDirectory(std::string custom_path)
|
|||
std::string home_path = std::string(home) + DIR_SEP;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// Mainline Dolphin switched to storing things elsewhere some time ago.
|
||||
// To get it working for now, let's just use the Slippi route.
|
||||
user_path = File::GetBundleDirectory() + "/Contents/Resources/User" DIR_SEP;
|
||||
// Since the Replays build shares the same identifier as the netplay build,
|
||||
// we'll just have a netplay and playback folder inside the identifer similar to how
|
||||
// the Launcher does it to keep with some convention.
|
||||
#ifdef IS_PLAYBACK
|
||||
user_path = File::GetApplicationSupportDirectory() + "/playback/User" DIR_SEP;
|
||||
#else
|
||||
user_path = File::GetApplicationSupportDirectory() + "/netplay/User" DIR_SEP;
|
||||
#endif
|
||||
#elif defined(ANDROID)
|
||||
if (env_path)
|
||||
{
|
||||
|
@ -513,7 +518,7 @@ bool TriggerSTMPowerEvent()
|
|||
#ifdef HAVE_X11
|
||||
void InhibitScreenSaver(Window win, bool inhibit)
|
||||
#else
|
||||
void InhibitScreenSaver(bool inhibit)
|
||||
void InhibitScreenSaver(bool inhibit)
|
||||
#endif
|
||||
{
|
||||
// Inhibit the screensaver. Depending on the operating system this may also
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue