Files
o3de/Gems/HttpRequestor/Code/Source/HttpRequestManager.cpp
T
Esteban Papp 1f9b284de2 Merge branch 'development' into cmake/SPEC-7179
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

# Conflicts:
#	Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.h
#	Code/Editor/Plugins/EditorCommon/EditorCommon_precompiled.h
#	Code/Editor/Plugins/EditorCommon/stdafx.cpp
#	Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h
#	Code/Editor/Plugins/PerforcePlugin/PerforcePlugin_precompiled.h
#	Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.h
#	Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.h
#	Code/Tools/AssetProcessor/native/precompiled.h
#	Code/Tools/Standalone/StandaloneTools_precompiled.h
#	Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.h
#	Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.h
#	Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/Mac/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/iOS/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.h
#	Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake
#	Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.h
#	Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Android/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Linux/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Mac/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Windows/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.h
#	Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
#	Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake
#	Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h
#	Gems/Blast/Code/Source/StdAfx.cpp
#	Gems/Camera/Code/Source/Camera_precompiled.h
#	Gems/EMotionFX/Code/Source/EMotionFX_precompiled.h
#	Gems/FastNoise/Code/Source/FastNoise_precompiled.h
#	Gems/Gestures/Code/Source/Gestures_precompiled.h
#	Gems/GradientSignal/Code/Source/GradientSignal_precompiled.h
#	Gems/GraphCanvas/Code/precompiled.h
#	Gems/ImGui/Code/Source/ImGui_precompiled.h
#	Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.h
#	Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.h
#	Gems/LmbrCentral/Code/Tests/ShapeGeometryUtilTest.cpp
#	Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.h
#	Gems/LyShine/Code/Source/Animation/LyShine_precompiled.h
#	Gems/LyShine/Code/Source/LyShine_precompiled.h
#	Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.h
#	Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.h
#	Gems/Maestro/Code/Source/Maestro_precompiled.h
#	Gems/MessagePopup/Code/Source/MessagePopup_precompiled.h
#	Gems/Metastream/Code/Source/Metastream_precompiled.h
#	Gems/Microphone/Code/Source/Microphone_precompiled.h
#	Gems/Multiplayer/Code/Source/Multiplayer_precompiled.h
#	Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.h
#	Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.h
#	Gems/PhysX/Code/Source/PhysX_precompiled.h
#	Gems/PhysX/Code/physx_unsupported_files.cmake
#	Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.h
#	Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.h
#	Gems/ScriptCanvas/Code/Editor/precompiled.h
#	Gems/ScriptCanvas/Code/Source/precompiled.h
#	Gems/ScriptCanvasDeveloper/Code/Source/precompiled.h
#	Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.h
#	Gems/ScriptEvents/Code/Source/precompiled.h
#	Gems/ScriptEvents/Code/Tests/Editor/EditorTests.cpp
#	Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.h
#	Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.h
#	Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.h
#	Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.h
#	Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.h
#	Gems/SurfaceData/Code/Source/SurfaceData_precompiled.h
#	Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.h
#	Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.h
#	Gems/Twitch/Code/Source/Twitch_precompiled.h
#	Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBox_precompiled.h
2021-07-16 15:42:37 -07:00

198 lines
7.3 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzFramework/AzFramework_Traits_Platform.h>
#include <AzCore/PlatformDef.h>
// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly.
// AWSAllocator.h(70): warning C4996: 'std::allocator<T>::pointer': warning STL4010: Various members of std::allocator are deprecated in C++17.
// Use std::allocator_traits instead of accessing these members directly.
// You can define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning.
AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option")
#include <aws/core/http/HttpClient.h>
#include <aws/core/http/HttpClientFactory.h>
#include <aws/core/http/HttpRequest.h>
#include <aws/core/http/HttpResponse.h>
#include <aws/core/client/ClientConfiguration.h>
AZ_POP_DISABLE_WARNING
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
#include <AzCore/std/string/conversions.h>
#include "HttpRequestManager.h"
namespace HttpRequestor
{
const char* Manager::s_loggingName = "GemHttpRequestManager";
Manager::Manager()
{
AZStd::thread_desc desc;
desc.m_name = s_loggingName;
desc.m_cpuId = AFFINITY_MASK_USERTHREADS;
m_runThread = true;
// Shutdown will be handled by the InitializationManager - no need to call in the destructor
AWSNativeSDKInit::InitializationManager::InitAwsApi();
auto function = AZStd::bind(&Manager::ThreadFunction, this);
m_thread = AZStd::thread(function, &desc);
}
Manager::~Manager()
{
// NativeSDK Shutdown does not need to be called here - will be taken care of by the InitializationManager
m_runThread = false;
m_requestConditionVar.notify_all();
if (m_thread.joinable())
{
m_thread.join();
}
}
void Manager::AddRequest(Parameters && httpRequestParameters)
{
{
AZStd::lock_guard<AZStd::mutex> lock(m_requestMutex);
m_requestsToHandle.push(AZStd::move(httpRequestParameters));
}
m_requestConditionVar.notify_all();
}
void Manager::AddTextRequest(TextParameters && httpTextRequestParameters)
{
{
AZStd::lock_guard<AZStd::mutex> lock(m_requestMutex);
m_textRequestsToHandle.push(AZStd::move(httpTextRequestParameters));
}
m_requestConditionVar.notify_all();
}
void Manager::ThreadFunction()
{
// Run the thread as long as directed
while (m_runThread)
{
HandleRequestBatch();
}
}
void Manager::HandleRequestBatch()
{
// Lock mutex and wait for work to be signalled via the condition variable
AZStd::unique_lock<AZStd::mutex> lock(m_requestMutex);
m_requestConditionVar.wait(lock, [&] { return !m_runThread || !m_requestsToHandle.empty() || !m_textRequestsToHandle.empty(); });
// Swap queues
AZStd::queue<Parameters> requestsToHandle;
requestsToHandle.swap(m_requestsToHandle);
AZStd::queue<TextParameters> textRequestsToHandle;
textRequestsToHandle.swap(m_textRequestsToHandle);
// Release lock
lock.unlock();
// Handle requests
while (!requestsToHandle.empty())
{
HandleRequest(requestsToHandle.front());
requestsToHandle.pop();
}
while (!textRequestsToHandle.empty())
{
HandleTextRequest(textRequestsToHandle.front());
textRequestsToHandle.pop();
}
}
void Manager::HandleRequest(const Parameters& httpRequestParameters)
{
Aws::Client::ClientConfiguration config;
config.enableTcpKeepAlive = AZ_TRAIT_AZFRAMEWORK_AWS_ENABLE_TCP_KEEP_ALIVE_SUPPORTED;
std::shared_ptr<Aws::Http::HttpClient> httpClient = Aws::Http::CreateHttpClient(config);
auto httpRequest = Aws::Http::CreateHttpRequest(httpRequestParameters.GetURI(), httpRequestParameters.GetMethod(), Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
AZ_Assert(httpRequest, "HttpRequest not created!");
for (const auto & it : httpRequestParameters.GetHeaders())
{
httpRequest->SetHeaderValue(it.first.c_str(), it.second.c_str());
}
if( httpRequestParameters.GetBodyStream() != nullptr)
{
httpRequest->AddContentBody(httpRequestParameters.GetBodyStream());
httpRequest->SetContentLength(AZStd::to_string(httpRequestParameters.GetBodyStream()->str().length()).c_str());
}
auto httpResponse = httpClient->MakeRequest(httpRequest);
if (!httpResponse)
{
httpRequestParameters.GetCallback()(Aws::Utils::Json::JsonValue(), Aws::Http::HttpResponseCode::INTERNAL_SERVER_ERROR);
return;
}
if (httpResponse->GetResponseCode() != Aws::Http::HttpResponseCode::OK)
{
httpRequestParameters.GetCallback()(Aws::Utils::Json::JsonValue(), httpResponse->GetResponseCode());
return;
}
Aws::Utils::Json::JsonValue json(httpResponse->GetResponseBody());
if (json.WasParseSuccessful())
{
httpRequestParameters.GetCallback()(AZStd::move(json), httpResponse->GetResponseCode());
}
else
{
httpRequestParameters.GetCallback()(Aws::Utils::Json::JsonValue(), Aws::Http::HttpResponseCode::INTERNAL_SERVER_ERROR);
}
}
void Manager::HandleTextRequest(const TextParameters & httpRequestParameters)
{
Aws::Client::ClientConfiguration config;
config.enableTcpKeepAlive = AZ_TRAIT_AZFRAMEWORK_AWS_ENABLE_TCP_KEEP_ALIVE_SUPPORTED;
std::shared_ptr<Aws::Http::HttpClient> httpClient = Aws::Http::CreateHttpClient(config);
auto httpRequest = Aws::Http::CreateHttpRequest(httpRequestParameters.GetURI(), httpRequestParameters.GetMethod(), Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
for (const auto & it : httpRequestParameters.GetHeaders())
{
httpRequest->SetHeaderValue(it.first.c_str(), it.second.c_str());
}
if (httpRequestParameters.GetBodyStream() != nullptr)
{
httpRequest->AddContentBody(httpRequestParameters.GetBodyStream());
}
auto httpResponse = httpClient->MakeRequest(httpRequest);
if (!httpResponse)
{
httpRequestParameters.GetCallback()(AZStd::string(), Aws::Http::HttpResponseCode::INTERNAL_SERVER_ERROR);
return;
}
if (httpResponse->GetResponseCode() != Aws::Http::HttpResponseCode::OK)
{
httpRequestParameters.GetCallback()(AZStd::string(), httpResponse->GetResponseCode());
return;
}
// load up the raw output into a string
// TODO(aaj): it feels like there should be some limit maybe 1 MB?
std::istreambuf_iterator<char> eos;
AZStd::string data(std::istreambuf_iterator<char>(httpResponse->GetResponseBody()), eos);
httpRequestParameters.GetCallback()(AZStd::move(data), httpResponse->GetResponseCode());
}
}