<|start_filename|>Source/VaRest/Private/VaRestLibrary.cpp<|end_filename|>
// Copyright 2014-2019 <NAME>. All Rights Reserved.

#include "VaRestLibrary.h"

#include "VaRest.h"
#include "VaRestDefines.h"
#include "VaRestRequestJSON.h"

#include "Engine/World.h"
#include "GenericPlatform/GenericPlatformHttp.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/Base64.h"

UVaRestSettings* UVaRestLibrary::GetVaRestSettings()
{
	return FVaRestModule::Get().GetSettings();
}

FString UVaRestLibrary::PercentEncode(const FString& Source)
{
	return FGenericPlatformHttp::UrlEncode(Source);
}

FString UVaRestLibrary::Base64Encode(const FString& Source)
{
	TArray<uint8> ByteArray;
	const FTCHARToUTF8 StringSrc = FTCHARToUTF8(Source.GetCharArray().GetData());
	ByteArray.Append((uint8*)StringSrc.Get(), StringSrc.Length());

	return FBase64::Encode(ByteArray);
}

bool UVaRestLibrary::Base64Decode(const FString& Source, FString& Dest)
{
	TArray<uint8> ByteArray;
	const bool Success = FBase64::Decode(Source, ByteArray);

	const FUTF8ToTCHAR StringSrc = FUTF8ToTCHAR((const ANSICHAR*)ByteArray.GetData(), ByteArray.Num());
	Dest = FString();
	Dest.AppendChars(StringSrc.Get(), StringSrc.Length());

	return Success;
}

bool UVaRestLibrary::Base64EncodeData(const TArray<uint8>& Data, FString& Dest)
{
	if (Data.Num() > 0)
	{
		Dest = FBase64::Encode(Data);
		return true;
	}

	Dest = FString();
	return false;
}

bool UVaRestLibrary::Base64DecodeData(const FString& Source, TArray<uint8>& Dest)
{
	return FBase64::Decode(Source, Dest);
}

FString UVaRestLibrary::StringToMd5(const FString& StringToHash)
{
	return FMD5::HashAnsiString(*StringToHash);
}

FString UVaRestLibrary::StringToSha1(const FString& StringToHash)
{
	FSHA1 Sha1Gen;

	Sha1Gen.Update((unsigned char*)TCHAR_TO_ANSI(*StringToHash), FCString::Strlen(*StringToHash));
	Sha1Gen.Final();

	FString Sha1String;
	for (int32 i = 0; i < 20; i++)
	{
		Sha1String += FString::Printf(TEXT("%02x"), Sha1Gen.m_digest[i]);
	}

	return Sha1String;
}

FString UVaRestLibrary::GetVaRestVersion()
{
	const auto PluginRef = IPluginManager::Get().FindPlugin("VaRest");

	return !PluginRef.IsValid() ? FString("invalid") : PluginRef->GetDescriptor().VersionName;
}

FVaRestURL UVaRestLibrary::GetWorldURL(UObject* WorldContextObject)
{
	if (WorldContextObject)
	{
		if (UWorld* World = WorldContextObject->GetWorld())
		{
			return FVaRestURL(World->URL);
		}
	}

	return FVaRestURL();
}


<|start_filename|>Source/VaRest/Private/VaRestSubsystem.cpp<|end_filename|>
// Copyright 2014-2020 <NAME>. All Rights Reserved.

#include "VaRestSubsystem.h"

#include "VaRestDefines.h"
#include "VaRestJsonObject.h"
#include "VaRestJsonValue.h"

#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonSerializer.h"
#include "Subsystems/SubsystemBlueprintLibrary.h"

UVaRestSubsystem::UVaRestSubsystem()
	: UEngineSubsystem()
{
}

void UVaRestSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	UE_LOG(LogVaRest, Log, TEXT("%s: VaRest subsystem initialized"), *VA_FUNC_LINE);
}

void UVaRestSubsystem::Deinitialize()
{
	// Do nothing for now
	Super::Deinitialize();
}

void UVaRestSubsystem::CallURL(const FString& URL, EVaRestRequestVerb Verb, EVaRestRequestContentType ContentType, UVaRestJsonObject* VaRestJson, const FVaRestCallDelegate& Callback)
{
	// Check we have valid data json
	if (VaRestJson == nullptr)
	{
		VaRestJson = ConstructVaRestJsonObject();
	}

	UVaRestRequestJSON* Request = ConstructVaRestRequest();

	Request->SetVerb(Verb);
	Request->SetContentType(ContentType);
	Request->SetRequestObject(VaRestJson);

	FVaRestCallResponse Response;
	Response.Request = Request;
	Response.Callback = Callback;

	Response.CompleteDelegateHandle = Request->OnStaticRequestComplete.AddUObject(this, &UVaRestSubsystem::OnCallComplete);
	Response.FailDelegateHandle = Request->OnStaticRequestFail.AddUObject(this, &UVaRestSubsystem::OnCallComplete);

	RequestMap.Add(Request, Response);

	Request->ResetResponseData();
	Request->ProcessURL(URL);
}

void UVaRestSubsystem::OnCallComplete(UVaRestRequestJSON* Request)
{
	if (!RequestMap.Contains(Request))
	{
		return;
	}

	const auto Response = RequestMap.Find(Request);
	Request->OnStaticRequestComplete.Remove(Response->CompleteDelegateHandle);
	Request->OnStaticRequestFail.Remove(Response->FailDelegateHandle);

	Response->Callback.ExecuteIfBound(Request);
	Response->Request = nullptr;
	RequestMap.Remove(Request);
}

UVaRestRequestJSON* UVaRestSubsystem::ConstructVaRestRequest()
{
	return NewObject<UVaRestRequestJSON>(this);
}

UVaRestRequestJSON* UVaRestSubsystem::ConstructVaRestRequestExt(EVaRestRequestVerb Verb, EVaRestRequestContentType ContentType)
{
	UVaRestRequestJSON* Request = ConstructVaRestRequest();

	Request->SetVerb(Verb);
	Request->SetContentType(ContentType);

	return Request;
}

UVaRestJsonObject* UVaRestSubsystem::ConstructVaRestJsonObject()
{
	return NewObject<UVaRestJsonObject>(this);
}

UVaRestJsonObject* UVaRestSubsystem::StaticConstructVaRestJsonObject()
{
	auto SelfSystem = CastChecked<UVaRestSubsystem>(USubsystemBlueprintLibrary::GetEngineSubsystem(UVaRestSubsystem::StaticClass()), ECastCheckedType::NullChecked);
	return SelfSystem->ConstructVaRestJsonObject();
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValueNumber(float Number)
{
	TSharedPtr<FJsonValue> NewVal = MakeShareable(new FJsonValueNumber(Number));

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValueString(const FString& StringValue)
{
	TSharedPtr<FJsonValue> NewVal = MakeShareable(new FJsonValueString(StringValue));

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValueBool(bool InValue)
{
	TSharedPtr<FJsonValue> NewVal = MakeShareable(new FJsonValueBoolean(InValue));

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValueArray(const TArray<UVaRestJsonValue*>& InArray)
{
	// Prepare data array to create new value
	TArray<TSharedPtr<FJsonValue>> ValueArray;
	for (auto InVal : InArray)
	{
		ValueArray.Add(InVal->GetRootValue());
	}

	TSharedPtr<FJsonValue> NewVal = MakeShareable(new FJsonValueArray(ValueArray));

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValueObject(UVaRestJsonObject* JsonObject)
{
	TSharedPtr<FJsonValue> NewVal = MakeShareable(new FJsonValueObject(JsonObject->GetRootObject()));

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::ConstructJsonValue(const TSharedPtr<FJsonValue>& InValue)
{
	TSharedPtr<FJsonValue> NewVal = InValue;

	UVaRestJsonValue* NewValue = NewObject<UVaRestJsonValue>(this);
	NewValue->SetRootValue(NewVal);

	return NewValue;
}

UVaRestJsonValue* UVaRestSubsystem::DecodeJsonValue(const FString& JsonString)
{
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(*JsonString);
	TSharedPtr<FJsonValue> OutJsonValue;
	if (FJsonSerializer::Deserialize(Reader, OutJsonValue))
	{
		return ConstructJsonValue(OutJsonValue);
	}

	return nullptr;
}

UVaRestJsonObject* UVaRestSubsystem::DecodeJsonObject(const FString& JsonString)
{
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(*JsonString);
	TSharedPtr<FJsonObject> OutJsonObj;
	if (FJsonSerializer::Deserialize(Reader, OutJsonObj))
	{
		auto NewJsonObj = NewObject<UVaRestJsonObject>(this);
		NewJsonObj->SetRootObject(OutJsonObj);
		return NewJsonObj;
	}

	return nullptr;
}

class UVaRestJsonObject* UVaRestSubsystem::LoadJsonFromFile(const FString& Path, const bool bIsRelativeToContentDir)
{
	auto* Json = ConstructVaRestJsonObject();

	FString JSONString;
	if (FFileHelper::LoadFileToString(JSONString, *(bIsRelativeToContentDir ? FPaths::ProjectContentDir() / Path : Path)))
	{
		if (Json->DecodeJson(JSONString))
		{
			return Json;
		}
		else
		{
			UE_LOG(LogVaRest, Error, TEXT("%s: Can't decode json from file %s"), *VA_FUNC_LINE, *Path);
		}
	}
	else
	{
		UE_LOG(LogVaRest, Error, TEXT("%s: Can't open file %s"), *VA_FUNC_LINE, *Path);
	}

	return nullptr;
}
