FrontendCommon: Add HTTPDownloaderUWP
This commit is contained in:
parent
99018b51b4
commit
b0adcb5ea6
|
@ -18,6 +18,9 @@
|
||||||
<ClCompile Include="game_list.cpp" />
|
<ClCompile Include="game_list.cpp" />
|
||||||
<ClCompile Include="game_settings.cpp" />
|
<ClCompile Include="game_settings.cpp" />
|
||||||
<ClCompile Include="http_downloader.cpp" />
|
<ClCompile Include="http_downloader.cpp" />
|
||||||
|
<ClCompile Include="http_downloader_uwp.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(BuildingForUWP)'!='true'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="http_downloader_winhttp.cpp">
|
<ClCompile Include="http_downloader_winhttp.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -67,6 +70,9 @@
|
||||||
<ClInclude Include="game_list.h" />
|
<ClInclude Include="game_list.h" />
|
||||||
<ClInclude Include="game_settings.h" />
|
<ClInclude Include="game_settings.h" />
|
||||||
<ClInclude Include="http_downloader.h" />
|
<ClInclude Include="http_downloader.h" />
|
||||||
|
<ClInclude Include="http_downloader_uwp.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(BuildingForUWP)'!='true'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="http_downloader_winhttp.h">
|
<ClInclude Include="http_downloader_winhttp.h">
|
||||||
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<ClCompile Include="xaudio2_audio_stream.cpp" />
|
<ClCompile Include="xaudio2_audio_stream.cpp" />
|
||||||
<ClCompile Include="d3d12_host_display.cpp" />
|
<ClCompile Include="d3d12_host_display.cpp" />
|
||||||
<ClCompile Include="imgui_impl_dx12.cpp" />
|
<ClCompile Include="imgui_impl_dx12.cpp" />
|
||||||
|
<ClCompile Include="http_downloader_uwp.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="icon.h" />
|
<ClInclude Include="icon.h" />
|
||||||
|
@ -73,6 +74,7 @@
|
||||||
<ClInclude Include="xaudio2_audio_stream.h" />
|
<ClInclude Include="xaudio2_audio_stream.h" />
|
||||||
<ClInclude Include="d3d12_host_display.h" />
|
<ClInclude Include="d3d12_host_display.h" />
|
||||||
<ClInclude Include="imgui_impl_dx12.h" />
|
<ClInclude Include="imgui_impl_dx12.h" />
|
||||||
|
<ClInclude Include="http_downloader_uwp.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="font_roboto_regular.inl" />
|
<None Include="font_roboto_regular.inl" />
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include "http_downloader_uwp.h"
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "common/timer.h"
|
||||||
|
#include <algorithm>
|
||||||
|
Log_SetChannel(HTTPDownloaderWinHttp);
|
||||||
|
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.Storage.Streams.h>
|
||||||
|
#include <winrt/Windows.Web.Http.Headers.h>
|
||||||
|
|
||||||
|
using namespace winrt::Windows::Foundation;
|
||||||
|
using namespace winrt::Windows::Web::Http;
|
||||||
|
|
||||||
|
namespace FrontendCommon {
|
||||||
|
|
||||||
|
HTTPDownloaderUWP::HTTPDownloaderUWP(std::string user_agent) : HTTPDownloader(), m_user_agent(std::move(user_agent)) {}
|
||||||
|
|
||||||
|
HTTPDownloaderUWP::~HTTPDownloaderUWP() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(const char* user_agent)
|
||||||
|
{
|
||||||
|
std::string user_agent_str;
|
||||||
|
if (user_agent)
|
||||||
|
user_agent_str = user_agent;
|
||||||
|
|
||||||
|
return std::make_unique<HTTPDownloaderUWP>(user_agent ? std::string(user_agent) : std::string());
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPDownloader::Request* HTTPDownloaderUWP::InternalCreateRequest()
|
||||||
|
{
|
||||||
|
Request* req = new Request();
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPDownloaderUWP::InternalPollRequests()
|
||||||
|
{
|
||||||
|
// noop - uses async
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPDownloaderUWP::StartRequest(HTTPDownloader::Request* request)
|
||||||
|
{
|
||||||
|
Request* req = static_cast<Request*>(request);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const std::wstring url_wide(StringUtil::UTF8StringToWideString(req->url));
|
||||||
|
const Uri uri(url_wide);
|
||||||
|
|
||||||
|
if (!m_user_agent.empty() &&
|
||||||
|
!req->client.DefaultRequestHeaders().UserAgent().TryParseAdd(StringUtil::UTF8StringToWideString(m_user_agent)))
|
||||||
|
{
|
||||||
|
Log_WarningPrintf("Failed to set user agent to '%s'", m_user_agent.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->type == Request::Type::Post)
|
||||||
|
{
|
||||||
|
const winrt::Windows::Storage::Streams::Buffer post_buf(static_cast<u32>(req->post_data.size()));
|
||||||
|
std::memcpy(post_buf.data(), req->post_data.data(), req->post_data.size());
|
||||||
|
|
||||||
|
const HttpBufferContent post_content(post_buf);
|
||||||
|
req->request_async = req->client.PostAsync(uri, post_content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
req->request_async = req->client.GetAsync(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
req->request_async.Completed(
|
||||||
|
[req](const IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress>& operation, AsyncStatus status) {
|
||||||
|
if (status == AsyncStatus::Completed)
|
||||||
|
{
|
||||||
|
Log_DevPrintf("Request for '%s' completed start portion", req->url.c_str());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
req->state.store(Request::State::Receiving);
|
||||||
|
req->start_time = Common::Timer::GetValue();
|
||||||
|
|
||||||
|
const HttpResponseMessage response(req->request_async.get());
|
||||||
|
req->status_code = static_cast<s32>(response.StatusCode());
|
||||||
|
|
||||||
|
const IHttpContent content(response.Content());
|
||||||
|
req->receive_async = content.ReadAsBufferAsync();
|
||||||
|
req->receive_async.Completed(
|
||||||
|
[req](
|
||||||
|
const IAsyncOperationWithProgress<winrt::Windows::Storage::Streams::IBuffer, uint64_t>& inner_operation,
|
||||||
|
AsyncStatus inner_status) {
|
||||||
|
if (inner_status == AsyncStatus::Completed)
|
||||||
|
{
|
||||||
|
const winrt::Windows::Storage::Streams::IBuffer buffer(inner_operation.get());
|
||||||
|
if (buffer && buffer.Length() > 0)
|
||||||
|
{
|
||||||
|
req->data.resize(buffer.Length());
|
||||||
|
std::memcpy(req->data.data(), buffer.data(), req->data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_DevPrintf("End of request '%s', %zu bytes received", req->url.c_str(), req->data.size());
|
||||||
|
req->state.store(Request::State::Complete);
|
||||||
|
}
|
||||||
|
else if (inner_status == AsyncStatus::Canceled)
|
||||||
|
{
|
||||||
|
// don't do anything, the request has been freed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Request for '%s' failed during recieve phase: %08X", req->url.c_str(),
|
||||||
|
inner_operation.ErrorCode().value);
|
||||||
|
req->status_code = -1;
|
||||||
|
req->state.store(Request::State::Complete);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (const winrt::hresult_error& err)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to receive HTTP request for '%s': %08X %s", req->url.c_str(), err.code(),
|
||||||
|
StringUtil::WideStringToUTF8String(err.message()).c_str());
|
||||||
|
req->status_code = -1;
|
||||||
|
req->state.store(Request::State::Complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
req->receive_async = nullptr;
|
||||||
|
}
|
||||||
|
else if (status == AsyncStatus::Canceled)
|
||||||
|
{
|
||||||
|
// don't do anything, the request has been freed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Request for '%s' failed during start phase: %08X", req->url.c_str(),
|
||||||
|
operation.ErrorCode().value);
|
||||||
|
req->status_code = -1;
|
||||||
|
req->state.store(Request::State::Complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
req->request_async = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (const winrt::hresult_error& err)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to start HTTP request for '%s': %08X %s", req->url.c_str(), err.code(),
|
||||||
|
StringUtil::WideStringToUTF8String(err.message()).c_str());
|
||||||
|
req->callback(-1, req->data);
|
||||||
|
delete req;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_DevPrintf("Started HTTP request for '%s'", req->url.c_str());
|
||||||
|
req->state = Request::State::Started;
|
||||||
|
req->start_time = Common::Timer::GetValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPDownloaderUWP::CloseRequest(HTTPDownloader::Request* request)
|
||||||
|
{
|
||||||
|
Request* req = static_cast<Request*>(request);
|
||||||
|
if (req->request_async)
|
||||||
|
req->request_async.Cancel();
|
||||||
|
if (req->receive_async)
|
||||||
|
req->receive_async.Cancel();
|
||||||
|
|
||||||
|
req->client.Close();
|
||||||
|
delete req;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace FrontendCommon
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
#include "http_downloader.h"
|
||||||
|
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
|
||||||
|
#include <winrt/windows.Web.Http.h>
|
||||||
|
|
||||||
|
namespace FrontendCommon {
|
||||||
|
|
||||||
|
class HTTPDownloaderUWP final : public HTTPDownloader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HTTPDownloaderUWP(std::string user_agent);
|
||||||
|
~HTTPDownloaderUWP() override;
|
||||||
|
|
||||||
|
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;
|
||||||
|
winrt::Windows::Web::Http::HttpClient client;
|
||||||
|
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Web::Http::HttpResponseMessage,
|
||||||
|
winrt::Windows::Web::Http::HttpProgress>
|
||||||
|
request_async{nullptr};
|
||||||
|
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Storage::Streams::IBuffer, uint64_t>
|
||||||
|
receive_async{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string m_user_agent;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace FrontendCommon
|
Loading…
Reference in New Issue