Break out Download and RequestManager into its own file

This commit is contained in:
Henrik Rydgård committed 2023-07-21 10:27:40 +02:00
1 parent 64eff0dc0b
commit f13a07f19b
11 files changed
+228 -186

No files matched your search

+2
View File
@@ -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
+2
View File
@@ -494,6 +494,7 @@
<ClInclude Include="Net\HTTPClient.h" />
<ClInclude Include="Net\HTTPHeaders.h" />
<ClInclude Include="Net\HTTPServer.h" />
<ClInclude Include="Net\HTTPRequest.h" />
<ClInclude Include="Net\Resolve.h" />
<ClInclude Include="Net\Sinks.h" />
<ClInclude Include="Net\URL.h" />
@@ -938,6 +939,7 @@
<ClCompile Include="Net\HTTPClient.cpp" />
<ClCompile Include="Net\HTTPHeaders.cpp" />
<ClCompile Include="Net\HTTPServer.cpp" />
<ClCompile Include="Net\HTTPRequest.cpp" />
<ClCompile Include="Net\Resolve.cpp" />
<ClCompile Include="Net\Sinks.cpp" />
<ClCompile Include="Net\URL.cpp" />
+7 -1
View File
@@ -512,6 +512,9 @@
<ClInclude Include="System\OSD.h">
<Filter>System</Filter>
</ClInclude>
<ClInclude Include="Net\HTTPRequest.h">
<Filter>Net</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
@@ -959,6 +962,9 @@
<ClCompile Include="System\OSD.cpp">
<Filter>System</Filter>
</ClCompile>
<ClCompile Include="Net\HTTPRequest.cpp">
<Filter>Net</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Crypto">
@@ -1107,4 +1113,4 @@
<Filter>ext\basis_universal</Filter>
</None>
</ItemGroup>
</Project>
</Project>
-82
View File
@@ -589,86 +589,4 @@ void HTTPDownload::Do() {
completed_ = true;
}
std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) {
std::shared_ptr<Download> 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<Download> Downloader::StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name,
const char *acceptMime) {
std::shared_ptr<Download> 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<Download> Downloader::AsyncPostWithCallback(
const std::string &url,
const std::string &postData,
const std::string &postMime,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name) {
std::shared_ptr<Download> 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
+1 -103
View File
@@ -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<void(Download &)> 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<void(Download &)> 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<Download> StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime = nullptr);
std::shared_ptr<Download> StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name = "",
const char *acceptMime = nullptr);
std::shared_ptr<Download> 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<void(Download &)> 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<std::shared_ptr<Download>> downloads_;
// These get copied to downloads_ in Update(). It's so that callbacks can add new downloads
// while running.
std::vector<std::shared_ptr<Download>> newDownloads_;
std::string userAgent_;
};
} // http
+89
View File
@@ -0,0 +1,89 @@
#include "Common/Net/HTTPRequest.h"
#include "Common/Net/HTTPClient.h"
#include "Common/TimeUtil.h"
namespace http {
std::shared_ptr<Download> RequestManager::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) {
std::shared_ptr<Download> 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<Download> RequestManager::StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name,
const char *acceptMime) {
std::shared_ptr<Download> 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<Download> RequestManager::AsyncPostWithCallback(
const std::string &url,
const std::string &postData,
const std::string &postMime,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name) {
std::shared_ptr<Download> 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
+117
View File
@@ -0,0 +1,117 @@
#pragma once
#include <string>
#include <functional>
#include <memory>
#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<void(Download &)> 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<void(Download &)> callback_;
std::string url_;
std::string name_;
net::RequestProgress progress_;
private:
};
using std::shared_ptr;
class RequestManager {
public:
~RequestManager() {
CancelAll();
}
std::shared_ptr<Download> StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime = nullptr);
std::shared_ptr<Download> StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const std::string &name = "",
const char *acceptMime = nullptr);
std::shared_ptr<Download> 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<void(Download &)> 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<std::shared_ptr<Download>> downloads_;
// These get copied to downloads_ in Update(). It's so that callbacks can add new downloads
// while running.
std::vector<std::shared_ptr<Download>> newDownloads_;
std::string userAgent_;
};
} // namespace net
+2
View File
@@ -114,6 +114,7 @@
<ClInclude Include="..\..\Common\GPU\GPUBackendCommon.h" />
<ClInclude Include="..\..\Common\GPU\Vulkan\VulkanLoader.h" />
<ClInclude Include="..\..\Common\Math\Statistics.h" />
<ClInclude Include="..\..\Common\Net\HTTPRequest.h" />
<ClInclude Include="..\..\Common\Net\NetBuffer.h" />
<ClInclude Include="..\..\Common\Data\Collections\ConstMap.h" />
<ClInclude Include="..\..\Common\Data\Collections\FixedSizeQueue.h" />
@@ -273,6 +274,7 @@
<ClCompile Include="..\..\Common\GPU\GPUBackendCommon.cpp" />
<ClCompile Include="..\..\Common\GPU\Vulkan\VulkanLoader.cpp" />
<ClCompile Include="..\..\Common\Math\Statistics.cpp" />
<ClCompile Include="..\..\Common\Net\HTTPRequest.cpp" />
<ClCompile Include="..\..\Common\Net\NetBuffer.cpp" />
<ClCompile Include="..\..\Common\Data\Color\RGBAUtil.cpp" />
<ClCompile Include="..\..\Common\Data\Convert\SmallDataConvert.cpp" />
+6
View File
@@ -444,6 +444,9 @@
<ClCompile Include="..\..\Common\System\OSD.cpp">
<Filter>System</Filter>
</ClCompile>
<ClCompile Include="..\..\Common\Net\HTTPRequest.cpp">
<Filter>Net</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="targetver.h" />
@@ -841,6 +844,9 @@
<ClInclude Include="..\..\Common\System\OSD.h">
<Filter>System</Filter>
</ClInclude>
<ClInclude Include="..\..\Common\Net\HTTPRequest.h">
<Filter>Net</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Common\Math\fast\fast_matrix_neon.S">
+1
View File
@@ -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 \
+1
View File
@@ -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 \