HTTPDownloader: Drop Common namespace

Annoying to type...
This commit is contained in:
Stenzek 2023-11-06 23:23:44 +10:00 committed by refractionpcsx2
parent e9a4d9702c
commit c557ea1b6f
8 changed files with 155 additions and 171 deletions

View File

@ -21,8 +21,6 @@
#include "common/StringUtil.h" #include "common/StringUtil.h"
#include "common/Timer.h" #include "common/Timer.h"
using namespace Common;
static constexpr float DEFAULT_TIMEOUT_IN_SECONDS = 30; static constexpr float DEFAULT_TIMEOUT_IN_SECONDS = 30;
static constexpr u32 DEFAULT_MAX_ACTIVE_REQUESTS = 4; static constexpr u32 DEFAULT_MAX_ACTIVE_REQUESTS = 4;
@ -55,7 +53,7 @@ void HTTPDownloader::CreateRequest(std::string url, Request::Callback callback)
req->type = Request::Type::Get; req->type = Request::Type::Get;
req->url = std::move(url); req->url = std::move(url);
req->callback = std::move(callback); req->callback = std::move(callback);
req->start_time = Timer::GetCurrentValue(); req->start_time = Common::Timer::GetCurrentValue();
std::unique_lock<std::mutex> lock(m_pending_http_request_lock); std::unique_lock<std::mutex> lock(m_pending_http_request_lock);
if (LockedGetActiveRequestCount() < m_max_active_requests) if (LockedGetActiveRequestCount() < m_max_active_requests)
@ -75,7 +73,7 @@ void HTTPDownloader::CreatePostRequest(std::string url, std::string post_data, R
req->url = std::move(url); req->url = std::move(url);
req->post_data = std::move(post_data); req->post_data = std::move(post_data);
req->callback = std::move(callback); req->callback = std::move(callback);
req->start_time = Timer::GetCurrentValue(); req->start_time = Common::Timer::GetCurrentValue();
std::unique_lock<std::mutex> lock(m_pending_http_request_lock); std::unique_lock<std::mutex> lock(m_pending_http_request_lock);
if (LockedGetActiveRequestCount() < m_max_active_requests) if (LockedGetActiveRequestCount() < m_max_active_requests)
@ -94,7 +92,7 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
InternalPollRequests(); InternalPollRequests();
const Common::Timer::Value current_time = Timer::GetCurrentValue(); const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
u32 active_requests = 0; u32 active_requests = 0;
u32 unstarted_requests = 0; u32 unstarted_requests = 0;

View File

@ -23,87 +23,83 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
namespace Common class HTTPDownloader
{ {
class HTTPDownloader public:
enum : s32
{ {
public: HTTP_STATUS_CANCELLED = -3,
enum : s32 HTTP_STATUS_TIMEOUT = -2,
{ HTTP_STATUS_ERROR = -1,
HTTP_STATUS_CANCELLED = -3, HTTP_STATUS_OK = 200
HTTP_STATUS_TIMEOUT = -2,
HTTP_STATUS_ERROR = -1,
HTTP_STATUS_OK = 200
};
struct Request
{
using Data = std::vector<u8>;
using Callback = std::function<void(s32 status_code, const std::string& content_type, Data data)>;
enum class Type
{
Get,
Post,
};
enum class State
{
Pending,
Cancelled,
Started,
Receiving,
Complete,
};
HTTPDownloader* parent;
Callback callback;
std::string url;
std::string post_data;
std::string content_type;
Data data;
u64 start_time;
s32 status_code = 0;
u32 content_length = 0;
Type type = Type::Get;
std::atomic<State> state{State::Pending};
};
HTTPDownloader();
virtual ~HTTPDownloader();
static std::unique_ptr<HTTPDownloader> Create(const char* user_agent = DEFAULT_USER_AGENT);
static std::string URLEncode(const std::string_view& str);
static std::string URLDecode(const std::string_view& str);
static std::string GetExtensionForContentType(const std::string& content_type);
void SetTimeout(float timeout);
void SetMaxActiveRequests(u32 max_active_requests);
void CreateRequest(std::string url, Request::Callback callback);
void CreatePostRequest(std::string url, std::string post_data, Request::Callback callback);
void PollRequests();
void WaitForAllRequests();
bool HasAnyRequests();
static const char DEFAULT_USER_AGENT[];
protected:
virtual Request* InternalCreateRequest() = 0;
virtual void InternalPollRequests() = 0;
virtual bool StartRequest(Request* request) = 0;
virtual void CloseRequest(Request* request) = 0;
void LockedAddRequest(Request* request);
u32 LockedGetActiveRequestCount();
void LockedPollRequests(std::unique_lock<std::mutex>& lock);
float m_timeout;
u32 m_max_active_requests;
std::mutex m_pending_http_request_lock;
std::vector<Request*> m_pending_http_requests;
}; };
} // namespace Common struct Request
{
using Data = std::vector<u8>;
using Callback = std::function<void(s32 status_code, const std::string& content_type, Data data)>;
enum class Type
{
Get,
Post,
};
enum class State
{
Pending,
Cancelled,
Started,
Receiving,
Complete,
};
HTTPDownloader* parent;
Callback callback;
std::string url;
std::string post_data;
std::string content_type;
Data data;
u64 start_time;
s32 status_code = 0;
u32 content_length = 0;
Type type = Type::Get;
std::atomic<State> state{State::Pending};
};
HTTPDownloader();
virtual ~HTTPDownloader();
static std::unique_ptr<HTTPDownloader> Create(const char* user_agent = DEFAULT_USER_AGENT);
static std::string URLEncode(const std::string_view& str);
static std::string URLDecode(const std::string_view& str);
static std::string GetExtensionForContentType(const std::string& content_type);
void SetTimeout(float timeout);
void SetMaxActiveRequests(u32 max_active_requests);
void CreateRequest(std::string url, Request::Callback callback);
void CreatePostRequest(std::string url, std::string post_data, Request::Callback callback);
void PollRequests();
void WaitForAllRequests();
bool HasAnyRequests();
static const char DEFAULT_USER_AGENT[];
protected:
virtual Request* InternalCreateRequest() = 0;
virtual void InternalPollRequests() = 0;
virtual bool StartRequest(Request* request) = 0;
virtual void CloseRequest(Request* request) = 0;
void LockedAddRequest(Request* request);
u32 LockedGetActiveRequestCount();
void LockedPollRequests(std::unique_lock<std::mutex>& lock);
float m_timeout;
u32 m_max_active_requests;
std::mutex m_pending_http_request_lock;
std::vector<Request*> m_pending_http_requests;
};

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team * Copyright (C) 2002-2023 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -26,8 +26,6 @@
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
using namespace Common;
HTTPDownloaderCurl::HTTPDownloaderCurl() HTTPDownloaderCurl::HTTPDownloaderCurl()
: HTTPDownloader() : HTTPDownloader()
{ {

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team * Copyright (C) 2002-2023 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -21,34 +21,31 @@
#include <mutex> #include <mutex>
#include <curl/curl.h> #include <curl/curl.h>
namespace Common class HTTPDownloaderCurl final : public HTTPDownloader
{ {
class HTTPDownloaderCurl final : public HTTPDownloader public:
HTTPDownloaderCurl();
~HTTPDownloaderCurl() override;
bool Initialize(const char* user_agent);
protected:
Request* InternalCreateRequest() override;
void InternalPollRequests() override;
bool StartRequest(HTTPDownloader::Request* request) override;
void CloseRequest(HTTPDownloader::Request* request) override;
private:
struct Request : HTTPDownloader::Request
{ {
public: CURL* handle = nullptr;
HTTPDownloaderCurl(); std::atomic_bool closed{false};
~HTTPDownloaderCurl() override;
bool Initialize(const char* user_agent);
protected:
Request* InternalCreateRequest() override;
void InternalPollRequests() override;
bool StartRequest(HTTPDownloader::Request* request) override;
void CloseRequest(HTTPDownloader::Request* request) override;
private:
struct Request : HTTPDownloader::Request
{
CURL* handle = nullptr;
std::atomic_bool closed{false};
};
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
void ProcessRequest(Request* req);
std::string m_user_agent;
std::unique_ptr<cb::ThreadPool> m_thread_pool;
std::mutex m_cancel_mutex;
}; };
} // namespace Common
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
void ProcessRequest(Request* req);
std::string m_user_agent;
std::unique_ptr<cb::ThreadPool> m_thread_pool;
std::mutex m_cancel_mutex;
};

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team * Copyright (C) 2002-2023 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -25,8 +25,6 @@
#pragma comment(lib, "winhttp.lib") #pragma comment(lib, "winhttp.lib")
using namespace Common;
HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() HTTPDownloaderWinHttp::HTTPDownloaderWinHttp()
: HTTPDownloader() : HTTPDownloader()
{ {

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team * Copyright (C) 2002-2023 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -20,34 +20,31 @@
#include <winhttp.h> #include <winhttp.h>
namespace Common class HTTPDownloaderWinHttp final : public HTTPDownloader
{ {
class HTTPDownloaderWinHttp final : public HTTPDownloader public:
HTTPDownloaderWinHttp();
~HTTPDownloaderWinHttp() override;
bool Initialize(const char* user_agent);
protected:
Request* InternalCreateRequest() override;
void InternalPollRequests() override;
bool StartRequest(HTTPDownloader::Request* request) override;
void CloseRequest(HTTPDownloader::Request* request) override;
private:
struct Request : HTTPDownloader::Request
{ {
public: std::wstring object_name;
HTTPDownloaderWinHttp(); HINTERNET hConnection = NULL;
~HTTPDownloaderWinHttp() override; HINTERNET hRequest = NULL;
u32 io_position = 0;
bool Initialize(const char* user_agent);
protected:
Request* InternalCreateRequest() override;
void InternalPollRequests() override;
bool StartRequest(HTTPDownloader::Request* request) override;
void CloseRequest(HTTPDownloader::Request* request) override;
private:
struct Request : HTTPDownloader::Request
{
std::wstring object_name;
HINTERNET hConnection = NULL;
HINTERNET hRequest = NULL;
u32 io_position = 0;
};
static void CALLBACK HTTPStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
HINTERNET m_hSession = NULL;
}; };
} // namespace Common
static void CALLBACK HTTPStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
HINTERNET m_hSession = NULL;
};

View File

@ -143,8 +143,8 @@ namespace Achievements
static void UpdateGameSummary(); static void UpdateGameSummary();
static void DownloadImage(std::string url, std::string cache_filename); static void DownloadImage(std::string url, std::string cache_filename);
static bool CreateClient(rc_client_t** client, std::unique_ptr<Common::HTTPDownloader>* http); static bool CreateClient(rc_client_t** client, std::unique_ptr<HTTPDownloader>* http);
static void DestroyClient(rc_client_t** client, std::unique_ptr<Common::HTTPDownloader>* http); static void DestroyClient(rc_client_t** client, std::unique_ptr<HTTPDownloader>* http);
static void ClientMessageCallback(const char* message, const rc_client_t* client); static void ClientMessageCallback(const char* message, const rc_client_t* client);
static uint32_t ClientReadMemory(uint32_t address, uint8_t* buffer, uint32_t num_bytes, rc_client_t* client); static uint32_t ClientReadMemory(uint32_t address, uint8_t* buffer, uint32_t num_bytes, rc_client_t* client);
static void ClientServerCall( static void ClientServerCall(
@ -203,7 +203,7 @@ namespace Achievements
static std::recursive_mutex s_achievements_mutex; static std::recursive_mutex s_achievements_mutex;
static rc_client_t* s_client; static rc_client_t* s_client;
static std::string s_image_directory; static std::string s_image_directory;
static std::unique_ptr<Common::HTTPDownloader> s_http_downloader; static std::unique_ptr<HTTPDownloader> s_http_downloader;
static u32 s_game_disc_crc; static u32 s_game_disc_crc;
static std::string s_game_hash; static std::string s_game_hash;
@ -352,8 +352,8 @@ std::string Achievements::GetGameHash()
void Achievements::DownloadImage(std::string url, std::string cache_filename) void Achievements::DownloadImage(std::string url, std::string cache_filename)
{ {
auto callback = [cache_filename](s32 status_code, std::string content_type, Common::HTTPDownloader::Request::Data data) { auto callback = [cache_filename](s32 status_code, std::string content_type, HTTPDownloader::Request::Data data) {
if (status_code != Common::HTTPDownloader::HTTP_STATUS_OK) if (status_code != HTTPDownloader::HTTP_STATUS_OK)
return; return;
if (!FileSystem::WriteBinaryFile(cache_filename.c_str(), data.data(), data.size())) if (!FileSystem::WriteBinaryFile(cache_filename.c_str(), data.data(), data.size()))
@ -472,9 +472,9 @@ bool Achievements::Initialize()
return true; return true;
} }
bool Achievements::CreateClient(rc_client_t** client, std::unique_ptr<Common::HTTPDownloader>* http) bool Achievements::CreateClient(rc_client_t** client, std::unique_ptr<HTTPDownloader>* http)
{ {
*http = Common::HTTPDownloader::Create(GetUserAgent().c_str()); *http = HTTPDownloader::Create(GetUserAgent().c_str());
if (!*http) if (!*http)
{ {
Host::ReportErrorAsync("Achievements Error", "Failed to create HTTPDownloader, cannot use achievements"); Host::ReportErrorAsync("Achievements Error", "Failed to create HTTPDownloader, cannot use achievements");
@ -501,7 +501,7 @@ bool Achievements::CreateClient(rc_client_t** client, std::unique_ptr<Common::HT
return true; return true;
} }
void Achievements::DestroyClient(rc_client_t** client, std::unique_ptr<Common::HTTPDownloader>* http) void Achievements::DestroyClient(rc_client_t** client, std::unique_ptr<HTTPDownloader>* http)
{ {
(*http)->WaitForAllRequests(); (*http)->WaitForAllRequests();
@ -649,10 +649,10 @@ uint32_t Achievements::ClientReadMemory(uint32_t address, uint8_t* buffer, uint3
void Achievements::ClientServerCall( void Achievements::ClientServerCall(
const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client) const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client)
{ {
Common::HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, std::string content_type, HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, std::string content_type,
Common::HTTPDownloader::Request::Data data) { HTTPDownloader::Request::Data data) {
rc_api_server_response_t rr; rc_api_server_response_t rr;
rr.http_status_code = (status_code <= 0) ? (status_code == Common::HTTPDownloader::HTTP_STATUS_CANCELLED ? rr.http_status_code = (status_code <= 0) ? (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED ?
RC_API_SERVER_RESPONSE_CLIENT_ERROR : RC_API_SERVER_RESPONSE_CLIENT_ERROR :
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR) : RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR) :
status_code; status_code;
@ -662,7 +662,7 @@ void Achievements::ClientServerCall(
callback(&rr, callback_data); callback(&rr, callback_data);
}; };
Common::HTTPDownloader* http = static_cast<Common::HTTPDownloader*>(rc_client_get_userdata(client)); HTTPDownloader* http = static_cast<HTTPDownloader*>(rc_client_get_userdata(client));
// TODO: Content-type for post // TODO: Content-type for post
if (request->post_data) if (request->post_data)
@ -1645,9 +1645,9 @@ bool Achievements::Login(const char* username, const char* password, Error* erro
// We need to use a temporary client if achievements aren't currently active. // We need to use a temporary client if achievements aren't currently active.
rc_client_t* client = s_client; rc_client_t* client = s_client;
Common::HTTPDownloader* http = s_http_downloader.get(); HTTPDownloader* http = s_http_downloader.get();
const bool is_temporary_client = (client == nullptr); const bool is_temporary_client = (client == nullptr);
std::unique_ptr<Common::HTTPDownloader> temporary_downloader; std::unique_ptr<HTTPDownloader> temporary_downloader;
ScopedGuard temporary_client_guard = [&client, is_temporary_client, &temporary_downloader]() { ScopedGuard temporary_client_guard = [&client, is_temporary_client, &temporary_downloader]() {
if (is_temporary_client) if (is_temporary_client)
DestroyClient(&client, &temporary_downloader); DestroyClient(&client, &temporary_downloader);

View File

@ -1267,14 +1267,14 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
{ {
std::string url(url_template); std::string url(url_template);
if (has_title) if (has_title)
StringUtil::ReplaceAll(&url, "${title}", Common::HTTPDownloader::URLEncode(entry.title)); StringUtil::ReplaceAll(&url, "${title}", HTTPDownloader::URLEncode(entry.title));
if (has_file_title) if (has_file_title)
{ {
std::string display_name(FileSystem::GetDisplayNameFromPath(entry.path)); std::string display_name(FileSystem::GetDisplayNameFromPath(entry.path));
StringUtil::ReplaceAll(&url, "${filetitle}", Common::HTTPDownloader::URLEncode(Path::GetFileTitle(display_name))); StringUtil::ReplaceAll(&url, "${filetitle}", HTTPDownloader::URLEncode(Path::GetFileTitle(display_name)));
} }
if (has_serial) if (has_serial)
StringUtil::ReplaceAll(&url, "${serial}", Common::HTTPDownloader::URLEncode(entry.serial)); StringUtil::ReplaceAll(&url, "${serial}", HTTPDownloader::URLEncode(entry.serial));
download_urls.emplace_back(entry.path, std::move(url)); download_urls.emplace_back(entry.path, std::move(url));
} }
@ -1286,7 +1286,7 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
return false; return false;
} }
std::unique_ptr<Common::HTTPDownloader> downloader(Common::HTTPDownloader::Create()); std::unique_ptr<HTTPDownloader> downloader(HTTPDownloader::Create());
if (!downloader) if (!downloader)
{ {
progress->DisplayError("Failed to create HTTP downloader."); progress->DisplayError("Failed to create HTTP downloader.");
@ -1315,11 +1315,11 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
} }
// we could actually do a few in parallel here... // we could actually do a few in parallel here...
std::string filename(Common::HTTPDownloader::URLDecode(url)); std::string filename(HTTPDownloader::URLDecode(url));
downloader->CreateRequest( downloader->CreateRequest(
std::move(url), [use_serial, &save_callback, entry_path = std::move(entry_path), filename = std::move(filename)]( std::move(url), [use_serial, &save_callback, entry_path = std::move(entry_path), filename = std::move(filename)](
s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data) { s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data) {
if (status_code != Common::HTTPDownloader::HTTP_STATUS_OK || data.empty()) if (status_code != HTTPDownloader::HTTP_STATUS_OK || data.empty())
return; return;
std::unique_lock lock(s_mutex); std::unique_lock lock(s_mutex);
@ -1330,7 +1330,7 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
// prefer the content type from the response for the extension // prefer the content type from the response for the extension
// otherwise, if it's missing, and the request didn't have an extension.. fall back to jpegs. // otherwise, if it's missing, and the request didn't have an extension.. fall back to jpegs.
std::string template_filename; std::string template_filename;
std::string content_type_extension(Common::HTTPDownloader::GetExtensionForContentType(content_type)); std::string content_type_extension(HTTPDownloader::GetExtensionForContentType(content_type));
// don't treat the domain name as an extension.. // don't treat the domain name as an extension..
const std::string::size_type last_slash = filename.find('/'); const std::string::size_type last_slash = filename.find('/');