diff --git a/CMakeLists.txt b/CMakeLists.txt index dddcf33403..f11a7d71cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -710,6 +710,8 @@ add_library(Common STATIC Common/Net/HTTPClient.h Common/Net/HTTPHeaders.cpp Common/Net/HTTPHeaders.h + Common/Net/HTTPRequest.cpp + Common/Net/HTTPRequest.h Common/Net/HTTPServer.cpp Common/Net/HTTPServer.h Common/Net/NetBuffer.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 2e5a95a43b..c26c2295a3 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -494,6 +494,7 @@ + @@ -938,6 +939,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index deb16350c3..8c8aedeb5f 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -512,6 +512,9 @@ System + + Net + @@ -959,6 +962,9 @@ System + + Net + @@ -1107,4 +1113,4 @@ ext\basis_universal - \ No newline at end of file + diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index 9974fd6888..b5c47f6695 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -589,86 +589,4 @@ void HTTPDownload::Do() { completed_ = true; } -std::shared_ptr Downloader::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) { - std::shared_ptr dl(new HTTPDownload(RequestMethod::GET, url, "", "", outfile, mode)); - - if (!userAgent_.empty()) - dl->SetUserAgent(userAgent_); - if (acceptMime) - dl->SetAccept(acceptMime); - newDownloads_.push_back(dl); - dl->Start(); - return dl; -} - -std::shared_ptr Downloader::StartDownloadWithCallback( - const std::string &url, - const Path &outfile, - ProgressBarMode mode, - std::function callback, - const std::string &name, - const char *acceptMime) { - std::shared_ptr dl(new HTTPDownload(RequestMethod::GET, url, "", "", outfile, mode, name)); - if (!userAgent_.empty()) - dl->SetUserAgent(userAgent_); - if (acceptMime) - dl->SetAccept(acceptMime); - dl->SetCallback(callback); - newDownloads_.push_back(dl); - dl->Start(); - return dl; -} - -std::shared_ptr Downloader::AsyncPostWithCallback( - const std::string &url, - const std::string &postData, - const std::string &postMime, - ProgressBarMode mode, - std::function callback, - const std::string &name) { - std::shared_ptr dl(new HTTPDownload(RequestMethod::POST, url, postData, postMime, Path(), mode, name)); - if (!userAgent_.empty()) - dl->SetUserAgent(userAgent_); - dl->SetCallback(callback); - newDownloads_.push_back(dl); - dl->Start(); - return dl; -} - -void Downloader::Update() { - for (auto iter : newDownloads_) { - downloads_.push_back(iter); - } - newDownloads_.clear(); - - restart: - for (size_t i = 0; i < downloads_.size(); i++) { - auto dl = downloads_[i]; - if (dl->Done()) { - dl->RunCallback(); - dl->Join(); - downloads_.erase(downloads_.begin() + i); - goto restart; - } - } -} - -void Downloader::WaitForAll() { - // TODO: Should lock? Though, OK if called from main thread, where Update() is called from. - while (!downloads_.empty()) { - Update(); - sleep_ms(10); - } -} - -void Downloader::CancelAll() { - for (size_t i = 0; i < downloads_.size(); i++) { - downloads_[i]->Cancel(); - } - for (size_t i = 0; i < downloads_.size(); i++) { - downloads_[i]->Join(); - } - downloads_.clear(); -} - } // http diff --git a/Common/Net/HTTPClient.h b/Common/Net/HTTPClient.h index 4235d0e13c..10113c3a9c 100644 --- a/Common/Net/HTTPClient.h +++ b/Common/Net/HTTPClient.h @@ -8,6 +8,7 @@ #include "Common/File/Path.h" #include "Common/Net/NetBuffer.h" #include "Common/Net/Resolve.h" +#include "Common/Net/HTTPRequest.h" namespace net { @@ -89,65 +90,6 @@ protected: double dataTimeout_ = 900.0; }; -enum class RequestMethod { - GET, - POST, -}; - -enum class ProgressBarMode { - NONE, - VISIBLE, - DELAYED, -}; - -class Download { -public: - Download(const std::string &url, const std::string &name, bool *cancelled) : url_(url), name_(name), progress_(cancelled) {} - virtual ~Download() {} - - virtual void SetAccept(const char *mime) = 0; - virtual void SetUserAgent(const std::string &userAgent) = 0; - - // NOTE: Completion callbacks (which these are) are deferred until RunCallback is called. This is so that - // the call will end up on the thread that calls g_DownloadManager.Update(). - void SetCallback(std::function callback) { - callback_ = callback; - } - void RunCallback() { - if (callback_) { - callback_(*this); - } - } - - virtual void Start() = 0; - virtual void Join() = 0; - - virtual bool Done() const = 0; - virtual bool Failed() const = 0; - - virtual int ResultCode() const = 0; - - // Returns 1.0 when done. That one value can be compared exactly - or just use Done(). - float Progress() const { return progress_.progress; } - float SpeedKBps() const { return progress_.kBps; } - std::string url() const { return url_; } - virtual const Path &outfile() const = 0; - - virtual void Cancel() = 0; - virtual bool IsCancelled() const = 0; - - virtual Buffer &buffer() = 0; - virtual const Buffer &buffer() const = 0; - -protected: - std::function callback_; - std::string url_; - std::string name_; - net::RequestProgress progress_; - -private: -}; - // Really an asynchronous request. class HTTPDownload : public Download { public: @@ -208,48 +150,4 @@ private: bool joined_ = false; }; -using std::shared_ptr; - -class Downloader { -public: - ~Downloader() { - CancelAll(); - } - - std::shared_ptr StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime = nullptr); - - std::shared_ptr StartDownloadWithCallback( - const std::string &url, - const Path &outfile, - ProgressBarMode mode, - std::function callback, - const std::string &name = "", - const char *acceptMime = nullptr); - - std::shared_ptr AsyncPostWithCallback( - const std::string &url, - const std::string &postData, - const std::string &postMime, // Use postMime = "application/x-www-form-urlencoded" for standard form-style posts, such as used by retroachievements. For encoding form data manually we have MultipartFormDataEncoder. - ProgressBarMode mode, - std::function callback, - const std::string &name = ""); - - // Drops finished downloads from the list. - void Update(); - void CancelAll(); - - void WaitForAll(); - void SetUserAgent(const std::string &userAgent) { - userAgent_ = userAgent; - } - -private: - std::vector> downloads_; - // These get copied to downloads_ in Update(). It's so that callbacks can add new downloads - // while running. - std::vector> newDownloads_; - - std::string userAgent_; -}; - } // http diff --git a/Common/Net/HTTPRequest.cpp b/Common/Net/HTTPRequest.cpp new file mode 100644 index 0000000000..c993bd4566 --- /dev/null +++ b/Common/Net/HTTPRequest.cpp @@ -0,0 +1,89 @@ +#include "Common/Net/HTTPRequest.h" +#include "Common/Net/HTTPClient.h" +#include "Common/TimeUtil.h" + +namespace http { + +std::shared_ptr RequestManager::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) { + std::shared_ptr dl(new HTTPDownload(RequestMethod::GET, url, "", "", outfile, mode)); + + if (!userAgent_.empty()) + dl->SetUserAgent(userAgent_); + if (acceptMime) + dl->SetAccept(acceptMime); + newDownloads_.push_back(dl); + dl->Start(); + return dl; +} + +std::shared_ptr RequestManager::StartDownloadWithCallback( + const std::string &url, + const Path &outfile, + ProgressBarMode mode, + std::function callback, + const std::string &name, + const char *acceptMime) { + std::shared_ptr dl(new HTTPDownload(RequestMethod::GET, url, "", "", outfile, mode, name)); + if (!userAgent_.empty()) + dl->SetUserAgent(userAgent_); + if (acceptMime) + dl->SetAccept(acceptMime); + dl->SetCallback(callback); + newDownloads_.push_back(dl); + dl->Start(); + return dl; +} + +std::shared_ptr RequestManager::AsyncPostWithCallback( + const std::string &url, + const std::string &postData, + const std::string &postMime, + ProgressBarMode mode, + std::function callback, + const std::string &name) { + std::shared_ptr dl(new HTTPDownload(RequestMethod::POST, url, postData, postMime, Path(), mode, name)); + if (!userAgent_.empty()) + dl->SetUserAgent(userAgent_); + dl->SetCallback(callback); + newDownloads_.push_back(dl); + dl->Start(); + return dl; +} + +void RequestManager::Update() { + for (auto iter : newDownloads_) { + downloads_.push_back(iter); + } + newDownloads_.clear(); + +restart: + for (size_t i = 0; i < downloads_.size(); i++) { + auto dl = downloads_[i]; + if (dl->Done()) { + dl->RunCallback(); + dl->Join(); + downloads_.erase(downloads_.begin() + i); + goto restart; + } + } +} + +void RequestManager::WaitForAll() { + // TODO: Should lock? Though, OK if called from main thread, where Update() is called from. + while (!downloads_.empty()) { + Update(); + sleep_ms(10); + } +} + +void RequestManager::CancelAll() { + for (size_t i = 0; i < downloads_.size(); i++) { + downloads_[i]->Cancel(); + } + for (size_t i = 0; i < downloads_.size(); i++) { + downloads_[i]->Join(); + } + downloads_.clear(); +} + +} // namespace diff --git a/Common/Net/HTTPRequest.h b/Common/Net/HTTPRequest.h new file mode 100644 index 0000000000..ae09baa9ce --- /dev/null +++ b/Common/Net/HTTPRequest.h @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include + +#include "Common/File/Path.h" +#include "Common/Net/NetBuffer.h" + +namespace http { + +enum class RequestMethod { + GET, + POST, +}; + +enum class ProgressBarMode { + NONE, + VISIBLE, + DELAYED, +}; + +// Abstract request. +class Download { +public: + Download(const std::string &url, const std::string &name, bool *cancelled) : url_(url), name_(name), progress_(cancelled) {} + virtual ~Download() {} + + virtual void SetAccept(const char *mime) = 0; + virtual void SetUserAgent(const std::string &userAgent) = 0; + + // NOTE: Completion callbacks (which these are) are deferred until RunCallback is called. This is so that + // the call will end up on the thread that calls g_DownloadManager.Update(). + void SetCallback(std::function callback) { + callback_ = callback; + } + void RunCallback() { + if (callback_) { + callback_(*this); + } + } + + virtual void Start() = 0; + virtual void Join() = 0; + + virtual bool Done() const = 0; + virtual bool Failed() const = 0; + + virtual int ResultCode() const = 0; + + // Returns 1.0 when done. That one value can be compared exactly - or just use Done(). + float Progress() const { return progress_.progress; } + float SpeedKBps() const { return progress_.kBps; } + std::string url() const { return url_; } + virtual const Path &outfile() const = 0; + + virtual void Cancel() = 0; + virtual bool IsCancelled() const = 0; + + // Response + virtual Buffer &buffer() = 0; + virtual const Buffer &buffer() const = 0; + +protected: + std::function callback_; + std::string url_; + std::string name_; + net::RequestProgress progress_; + +private: +}; + +using std::shared_ptr; + +class RequestManager { +public: + ~RequestManager() { + CancelAll(); + } + + std::shared_ptr StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime = nullptr); + + std::shared_ptr StartDownloadWithCallback( + const std::string &url, + const Path &outfile, + ProgressBarMode mode, + std::function callback, + const std::string &name = "", + const char *acceptMime = nullptr); + + std::shared_ptr AsyncPostWithCallback( + const std::string &url, + const std::string &postData, + const std::string &postMime, // Use postMime = "application/x-www-form-urlencoded" for standard form-style posts, such as used by retroachievements. For encoding form data manually we have MultipartFormDataEncoder. + ProgressBarMode mode, + std::function callback, + const std::string &name = ""); + + // Drops finished downloads from the list. + void Update(); + void CancelAll(); + + void WaitForAll(); + void SetUserAgent(const std::string &userAgent) { + userAgent_ = userAgent; + } + +private: + std::vector> downloads_; + // These get copied to downloads_ in Update(). It's so that callbacks can add new downloads + // while running. + std::vector> newDownloads_; + + std::string userAgent_; +}; + +} // namespace net diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index e5a72c7d32..39bf0aece7 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -114,6 +114,7 @@ + @@ -273,6 +274,7 @@ + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 2dfc1ae397..49b74be9b8 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -444,6 +444,9 @@ System + + Net + @@ -841,6 +844,9 @@ System + + Net + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index bfb6874e63..cffe34f588 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -238,6 +238,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/Math/lin/matrix4x4.cpp.arm \ $(SRC)/Common/Net/HTTPClient.cpp \ $(SRC)/Common/Net/HTTPHeaders.cpp \ + $(SRC)/Common/Net/HTTPRequest.cpp \ $(SRC)/Common/Net/HTTPServer.cpp \ $(SRC)/Common/Net/NetBuffer.cpp \ $(SRC)/Common/Net/Resolve.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 29bc7de7e4..bad6f6c73c 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -351,6 +351,7 @@ SOURCES_CXX += \ $(COMMONDIR)/Net/HTTPClient.cpp \ $(COMMONDIR)/Net/HTTPHeaders.cpp \ $(COMMONDIR)/Net/HTTPServer.cpp \ + $(COMMONDIR)/Net/HTTPRequest.cpp \ $(COMMONDIR)/Net/NetBuffer.cpp \ $(COMMONDIR)/Net/Resolve.cpp \ $(COMMONDIR)/Net/Sinks.cpp \