First Commit with code
This commit is contained in:
36
Source/DTFluxAPI/DTFluxAPI.Build.cs
Normal file
36
Source/DTFluxAPI/DTFluxAPI.Build.cs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class DTFluxAPI : ModuleRules
|
||||
{
|
||||
public DTFluxAPI(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core"
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"HTTPServer",
|
||||
"HTTP",
|
||||
"DeveloperToolSettings",
|
||||
"DeveloperSettings",
|
||||
"Json",
|
||||
"JsonUtilities",
|
||||
"AvalancheCore",
|
||||
"AvalancheMedia",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
22
Source/DTFluxAPI/Private/DTFluxAPI.cpp
Normal file
22
Source/DTFluxAPI/Private/DTFluxAPI.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "DTFluxAPI.h"
|
||||
#include "DTFluxAPILog.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FDTFluxAPIModule"
|
||||
DEFINE_LOG_CATEGORY(LogDTFluxAPI);
|
||||
|
||||
void FDTFluxAPIModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
}
|
||||
|
||||
void FDTFluxAPIModule::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FDTFluxAPIModule, DTFluxAPI)
|
||||
4
Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp
Normal file
4
Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "DTFluxModel/DTFluxModel.h"
|
||||
@ -0,0 +1,73 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "DTFluxProjectSettings/DTFluxProjectSettings.h"
|
||||
|
||||
FString UDTFluxProjectSettings::GetAPIPath(const TEnumAsByte<EDTFluxAPIRoute> RouteType, const FString& Filters) const
|
||||
{
|
||||
FString ApiAccessRoute;
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Filters in GetApiPath settings\nGot %s"), *Filters);
|
||||
|
||||
if (bAccessIsLocal)
|
||||
{
|
||||
// http://localhost/_246158/api/8O8JMI2739JS58R8KRJGJEZUSQXF807O
|
||||
ApiAccessRoute += RaceResultPort != 80 ? FString::Printf(TEXT("%s:%i/_%s/api/"), *ProxyUrl, RaceResultPort, *APIToken) :
|
||||
FString::Printf(TEXT("%s/_%s/api/"), *ProxyUrl, *APIToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://api.raceresult.com/246158/8O8JMI2739JS58R8KRJGJEZUSQXF807O
|
||||
ApiAccessRoute += FString::Printf(TEXT("https://api.raceresult.com/%s/"), *APIToken);
|
||||
}
|
||||
switch(RouteType)
|
||||
{
|
||||
case (EDTFluxAPIRoute::Results):
|
||||
return ApiAccessRoute + LiveStageResultsAccessToken + Filters;
|
||||
break;
|
||||
case (EDTFluxAPIRoute::FinalClassification):
|
||||
return ApiAccessRoute + GeneralClassificationAccessToken + Filters;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ApiAccessRoute + StartListAccessToken + Filters;
|
||||
}
|
||||
}
|
||||
|
||||
FString UDTFluxProjectSettings::GetAPIPathFiltered(const TEnumAsByte<EDTFluxAPIRoute> RouteType,
|
||||
const FSearchFilters& Filters) const
|
||||
{
|
||||
const FString Filter = Filters.GetFilter();
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Filters in Project settings\nGot %s"), *Filter);
|
||||
return GetAPIPath(RouteType, Filter );
|
||||
}
|
||||
|
||||
FString UDTFluxProjectSettings::GetProxyPath(const TEnumAsByte<EDTFluxProxyRoute> RouteType,
|
||||
const int& InContest, const int& InStage ) const
|
||||
{
|
||||
switch(RouteType)
|
||||
{
|
||||
case (EDTFluxProxyRoute::ProxyRankingContest):
|
||||
return FString::Printf(TEXT("%s:%i%s/ranking/contest/%i/"), *ProxyAddress, ProxyPort, *ProxyRootPath, InContest);
|
||||
break;
|
||||
case (EDTFluxProxyRoute::ProxyRankingStage):
|
||||
return FString::Printf(TEXT("%s:%i%s/ranking/contest/%i/stage?id=%i"),
|
||||
*ProxyAddress, ProxyPort, *ProxyRootPath, InContest, InStage);
|
||||
break;
|
||||
case (EDTFluxProxyRoute::ProxyTeams):
|
||||
return FString::Printf(TEXT("%s:%i%s/teams/"), *ProxyAddress, ProxyPort, *ProxyRootPath);
|
||||
break;
|
||||
default :
|
||||
return FString::Printf(TEXT("%s:%i%s/race/datas/"), *ProxyAddress, ProxyPort, *ProxyRootPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const UDTFluxProjectSettings* UDTFluxProjectSettings::GetDTFluxAPIProjectSettings()
|
||||
{
|
||||
return GetDefault<UDTFluxProjectSettings>();
|
||||
}
|
||||
|
||||
UDTFluxProjectSettings::UDTFluxProjectSettings()
|
||||
{
|
||||
SectionName = "DTFlux Settings";
|
||||
}
|
||||
331
Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp
Normal file
331
Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "DTFluxSubsystem/DTFluxSubsystem.h"
|
||||
#include "DTFluxProjectSettings/DTFluxProjectSettings.h"
|
||||
#include "DTFluxModel/DTFluxModel.h"
|
||||
#include "HttpServerModule.h"
|
||||
#include "HttpRouteHandle.h"
|
||||
#include "DTFluxAPILog.h"
|
||||
#include "IHttpRouter.h"
|
||||
#include "HttpModule.h"
|
||||
#include "JsonObjectConverter.h"
|
||||
#include "Interfaces/IHttpResponse.h"
|
||||
|
||||
// TODO: Not implemented
|
||||
bool UDTFluxSubsystem::OnRequest(const FHttpServerRequest& Request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// TODO: Not implemented
|
||||
void UDTFluxSubsystem::HandleRequest(const FString& Route,const FHttpServerRequest& Request, FHttpResultCallback OnComplete)
|
||||
{
|
||||
// creating payload string
|
||||
FString ReqPayload;
|
||||
if (Request.Body.Num() > 0)
|
||||
{
|
||||
const std::string RawBody((char*)Request.Body.GetData(), Request.Body.Num());
|
||||
ReqPayload = UTF8_TO_TCHAR(RawBody.c_str());
|
||||
}
|
||||
TSharedPtr<FJsonObject> JsonPayload;
|
||||
if(!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(ReqPayload), JsonPayload))
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("unable to parse JSON Payload\n%s"), *ReqPayload);
|
||||
}
|
||||
//Checking path
|
||||
|
||||
UE_LOG(LogDTFluxAPI,Log, TEXT("Request Received for Route %s"), *Route);
|
||||
|
||||
// EventStart
|
||||
if(Route == TEXT("/event/start"))
|
||||
{
|
||||
FDTFluxStartStagePayload StartStagePayload;
|
||||
FJsonObjectConverter::JsonObjectToUStruct<FDTFluxStartStagePayload>(JsonPayload.ToSharedRef(), &StartStagePayload, 0, 0);
|
||||
OnEventStartReceived.Broadcast(StartStagePayload);
|
||||
}
|
||||
else if(Route == TEXT("/team/create"))
|
||||
{
|
||||
// /team/create route
|
||||
}
|
||||
else if(Route == TEXT("/team/update"))
|
||||
{
|
||||
// /team/create route
|
||||
} else if(Route == TEXT("/team/create"))
|
||||
{
|
||||
// /team/create route
|
||||
}
|
||||
// Default Route
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//Preparing Response Header
|
||||
TUniquePtr<FHttpServerResponse> Response = CreateHttpServerResponse();
|
||||
|
||||
// Adding Response Body
|
||||
FDTFluxResponseBody RespBody;
|
||||
RespBody.Success = TEXT("OK");
|
||||
std::string RespBody_c;
|
||||
RespBody_c = TCHAR_TO_UTF8(*RespBody.Deserialize());
|
||||
Response->Body.Append((const uint8*)RespBody_c.c_str(), RespBody_c.length());
|
||||
// Return the response
|
||||
OnComplete(MoveTemp(Response));
|
||||
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::OnUpdateStartList(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful || !Response.IsValid())
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("RaceResult Request failed"));
|
||||
return;
|
||||
}
|
||||
// Tricks because Payload root is an array
|
||||
const FString ModifiedData = FString::Printf(TEXT("{\"Participants\":%s}"), *Response->GetContentAsString());
|
||||
TSharedPtr<FJsonObject> Payload;
|
||||
if(!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(ModifiedData), Payload))
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("unable to parse JSON Payload****"));
|
||||
}else
|
||||
{
|
||||
FDTFluxStartListPayload StartList;
|
||||
if (FJsonObjectConverter::JsonObjectToUStruct<FDTFluxStartListPayload>(Payload.ToSharedRef(), &StartList, 0, 0))
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Success Reading"))
|
||||
|
||||
for(const auto& Participant : StartList.Participants)
|
||||
{
|
||||
// Creating a new Contest
|
||||
if(!Contests.Contests.Contains(Participant.ContestName))
|
||||
{
|
||||
FDTFluxContest NewContest;
|
||||
NewContest.ContestID = Participant.ContestID;
|
||||
NewContest.ContestName = Participant.ContestName;
|
||||
Contests.Contests.Add(Participant.ContestName, NewContest);
|
||||
}
|
||||
FDTFluxContest* CurrentContest = Contests.Contests.Find(Participant.ContestName);
|
||||
|
||||
FDTFluxTeam Team;
|
||||
Team.Bib = Participant.Bib;
|
||||
FDTFluxParticipant ContestParticipant;
|
||||
ContestParticipant.FirstName = Participant.FirstName;
|
||||
ContestParticipant.LastName = Participant.LastName;
|
||||
ContestParticipant.Gender = Participant.Gender;
|
||||
ContestParticipant.Club = Participant.Club;
|
||||
ContestParticipant.Category = Participant.Category;
|
||||
|
||||
Team.Participants.Add(ContestParticipant);
|
||||
// if we have LastName2 it is a two personne Team
|
||||
if(Participant.LastName2 != "")
|
||||
{
|
||||
FDTFluxParticipant ContestParticipant2;
|
||||
ContestParticipant2.FirstName = Participant.FirstName2;
|
||||
ContestParticipant2.LastName = Participant.LastName2;
|
||||
ContestParticipant2.Gender = Participant.Gender2;
|
||||
ContestParticipant2.Club = Participant.Club2;
|
||||
ContestParticipant2.Category = Participant.Category;
|
||||
Team.Participants.Add(ContestParticipant);
|
||||
Team.TeamName = Participant.TeamName;
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Participant is a team : TeamName \"%s\" "), *Team.TeamName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Team.TeamName = Participant.FirstName + TEXT(" ") + Participant.LastName.ToUpper();
|
||||
}
|
||||
// check if Participant already exists
|
||||
|
||||
if(!CurrentContest->TeamAlreadyExist(Team))
|
||||
{
|
||||
// Add it to the TeamList
|
||||
CurrentContest->AddTeam(Team);
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Adding Team \"%s\" "), *Team.TeamName);
|
||||
}
|
||||
|
||||
}
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Contest has now %i elements"), Contests.Contests.Num());
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("Error Deserializing Payload \n*%s*\n"), *ModifiedData);
|
||||
|
||||
}
|
||||
}
|
||||
for(const auto& Element : Contests.Contests)
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Contest %s"), *Element.Key);
|
||||
FDTFluxContest Contest = Element.Value;
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Number of participants in this contest %i"), Contest.TeamParticipants.Num());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TUniquePtr<FHttpServerResponse> UDTFluxSubsystem::CreateHttpServerResponse() const
|
||||
{
|
||||
// Create a Response to be returned by the server
|
||||
TUniquePtr<FHttpServerResponse> Response = MakeUnique<FHttpServerResponse>();
|
||||
Response->Code = EHttpServerResponseCodes::Ok;
|
||||
// Response Header
|
||||
Response->Headers.Add(TEXT("Content-Type"), { TEXT("application/json;charset=utf-8") });
|
||||
Response->Headers.Add(TEXT("Access-Control-Allow-Origin"), { TEXT("*") });
|
||||
Response->Headers.Add(TEXT("Access-Control-Allow-Methods"), { TEXT("GET,POST,PUT,PATCH,DELETE,OPTIONS") });
|
||||
Response->Headers.Add(TEXT("Access-Control-Allow-Headers"), { TEXT("Origin,X-Requested-With,Content-Type,Accept") });
|
||||
Response->Headers.Add(TEXT("Access-Control-Max-Age"), { TEXT("600") });
|
||||
Response->Headers.Add(TEXT("Access-Control-Allow-Credentials"), { TEXT("true") });
|
||||
Response->Headers.Add(TEXT("Server"), { TEXT("UE 5.4.1 EMBBEDED") });
|
||||
|
||||
return Response;
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
mSettings = UDTFluxProjectSettings::GetDTFluxAPIProjectSettings();
|
||||
if(mSettings)
|
||||
{
|
||||
// Setting up request
|
||||
HttpRequest = &FHttpModule::Get();
|
||||
HttpRouter = FHttpServerModule::Get().GetHttpRouter(mSettings->InPort);
|
||||
if(!HttpRouter)
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Type::Error, TEXT("Invalid Http Router for port : %i"), mSettings->InPort)
|
||||
}
|
||||
// Setting Up Routes
|
||||
for(const TArray<FString> Routes = mSettings->Endpoints; const FString& Route : Routes)
|
||||
{
|
||||
const FHttpRequestHandler OptionRequestHandler = FHttpRequestHandler::CreateLambda([this](const FHttpServerRequest &Request, const FHttpResultCallback& OnComplete)
|
||||
{
|
||||
OnComplete(CreateHttpServerResponse());
|
||||
return true;
|
||||
});
|
||||
FHttpRouteHandle OptionRouteHandle = HttpRouter->BindRoute(Route, EHttpServerRequestVerbs::VERB_OPTIONS, OptionRequestHandler);
|
||||
HttpMountedMap.Add(Route + TEXT("HTTPOption"), OptionRouteHandle);
|
||||
|
||||
const FHttpRequestHandler RequestHandler = FHttpRequestHandler::CreateLambda([this, Route](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete)
|
||||
{
|
||||
// Processing Request to Raw OnRequestReceived firing
|
||||
FDTFluxHttpServerHeaders Headers;
|
||||
for(const auto &Header: Request.Headers)
|
||||
{
|
||||
Headers.Headers.Add(Header.Key, FString::Join(Header.Value, TEXT(",")));
|
||||
}
|
||||
FDTFluxHttpServerParams Params;
|
||||
Params.Params = Request.QueryParams;
|
||||
|
||||
FDTFluxHttpServerBody Payload;
|
||||
Payload.ReqBody = Request.Body;
|
||||
|
||||
// Raw broadcasting Received event
|
||||
OnRequestReceived.Broadcast(Headers, Params, Payload);
|
||||
HandleRequest(Route, Request, OnComplete);
|
||||
return true;
|
||||
});
|
||||
// Binding Routes
|
||||
FHttpRouteHandle RouteHandle = HttpRouter->BindRoute(Route, EHttpServerRequestVerbs::VERB_POST, RequestHandler);
|
||||
HttpMountedMap.Add(Route, RouteHandle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::Deinitialize()
|
||||
{
|
||||
StopServer();
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Route Num %i"), HttpMountedMap.Num());
|
||||
for( auto const& Route: HttpMountedMap)
|
||||
{
|
||||
HttpRouter->UnbindRoute(Route.Value);
|
||||
}
|
||||
HttpMountedMap.Empty();
|
||||
HttpRouter.Reset();
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
TArray<FString> UDTFluxSubsystem::GetMountedRoutes() const
|
||||
{
|
||||
TArray<FString> Mounted = TArray<FString>();
|
||||
for(const auto Route : HttpMountedMap)
|
||||
{
|
||||
Mounted.Add(Route.Key);
|
||||
}
|
||||
return Mounted;
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::StartServer()
|
||||
{
|
||||
if(bIsListening){return ;}
|
||||
FHttpServerModule::Get().StartAllListeners();
|
||||
bIsListening = true;
|
||||
OnServerListening.Broadcast();
|
||||
}
|
||||
|
||||
TArray<FDTFluxTeam> UDTFluxSubsystem::GetParticipantsByContestId(const int ContestId)
|
||||
{
|
||||
if(Contests.Contests.Num() != 0)
|
||||
{
|
||||
FString ContestName = Contests.GetContestName(ContestId);
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("Getting Participants for Contest %s"), *ContestName);
|
||||
return GetParticipantsByContestName(ContestName);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("No Contest Yet !!!!"));
|
||||
TArray<FDTFluxTeam> EmptyTeam;
|
||||
return EmptyTeam;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TArray<FDTFluxTeam> UDTFluxSubsystem::GetParticipantsByContestName(const FString ContestName)
|
||||
{
|
||||
if(Contests.Contests.Num() != 0)
|
||||
{
|
||||
return Contests.Contests[ContestName].TeamParticipants;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Error, TEXT("No Contest Yet !!!!"));
|
||||
TArray<FDTFluxTeam> EmptyTeam;
|
||||
return EmptyTeam;
|
||||
}
|
||||
}
|
||||
|
||||
FString UDTFluxSubsystem::GetContestName(const int ContestId)
|
||||
{
|
||||
if(Contests.GetContestName(ContestId) != "")
|
||||
{
|
||||
return Contests.GetContestName(ContestId);
|
||||
}
|
||||
return TEXT("");
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::UpdateStartList()
|
||||
{
|
||||
const TSharedRef<IHttpRequest> Req = HttpRequest->CreateRequest();
|
||||
Req->SetVerb("GET");
|
||||
Req->SetURL(mSettings->GetAPIPath(EDTFluxAPIRoute::Starters));
|
||||
Req->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
|
||||
Req->OnProcessRequestComplete().BindUObject(this, &UDTFluxSubsystem::OnUpdateStartList);
|
||||
|
||||
Req->ProcessRequest();
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::UpdateClassification(const int& ContestId, const int& StageId)
|
||||
{
|
||||
}
|
||||
|
||||
TArray<FDTFluxParticipant> UDTFluxSubsystem::GetClassification(const int& ContestId, const int& StageId)
|
||||
{
|
||||
return TArray<FDTFluxParticipant>();
|
||||
}
|
||||
|
||||
void UDTFluxSubsystem::StopServer()
|
||||
{
|
||||
FHttpServerModule::Get().StopAllListeners();
|
||||
bIsListening = false;
|
||||
OnServerStopped.Broadcast();
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
// Copyright 2023 Dexter.Wan. All Rights Reserved.
|
||||
// EMail: 45141961@qq.com
|
||||
|
||||
#include "DTFluxUtils/DTFluxHttpServerStruct.h"
|
||||
|
||||
void UDTFluxHttpServerBPFn::BreakParams(const FDTFluxHttpServerParams& HttpServerParams, TMap<FString, FString>& Params)
|
||||
{
|
||||
Params = HttpServerParams.Params;
|
||||
}
|
||||
|
||||
void UDTFluxHttpServerBPFn::FindParam(const FDTFluxHttpServerParams& HttpServerParams, const FString& Key, FString& Param)
|
||||
{
|
||||
Param.Empty();
|
||||
if ( const FString * pParam = HttpServerParams.Params.Find(Key) )
|
||||
{
|
||||
Param = *pParam;
|
||||
}
|
||||
}
|
||||
|
||||
void UDTFluxHttpServerBPFn::BreakHeaders(const FDTFluxHttpServerHeaders& HttpServerHeaders, TMap<FString, FString>& Headers)
|
||||
{
|
||||
Headers = HttpServerHeaders.Headers;
|
||||
}
|
||||
|
||||
void UDTFluxHttpServerBPFn::BreakBody(const FDTFluxHttpServerBody& HttpBody, TArray<uint8> RawBody)
|
||||
{
|
||||
RawBody = HttpBody.ReqBody;
|
||||
}
|
||||
|
||||
void UDTFluxHttpServerBPFn::FindHeader(const FDTFluxHttpServerHeaders& HttpServerHeaders, const FString& Key, FString& Header)
|
||||
{
|
||||
Header.Empty();
|
||||
if ( const FString * pHeader = HttpServerHeaders.Headers.Find(Key) )
|
||||
{
|
||||
Header = *pHeader;
|
||||
}
|
||||
}
|
||||
|
||||
15
Source/DTFluxAPI/Public/DTFluxAPI.h
Normal file
15
Source/DTFluxAPI/Public/DTFluxAPI.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class FDTFluxAPIModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
6
Source/DTFluxAPI/Public/DTFluxAPILog.h
Normal file
6
Source/DTFluxAPI/Public/DTFluxAPILog.h
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogDTFluxAPI, Log, All);
|
||||
423
Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h
Normal file
423
Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h
Normal file
@ -0,0 +1,423 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "DTFluxModel.generated.h"
|
||||
|
||||
|
||||
// Forward declarations
|
||||
struct FDTFluxTeam;
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFLuxStartStageData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Type;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Contest;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Stage;
|
||||
|
||||
// Maybe this one can be made DATETIME
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString RealStartTime;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxStartStagePayload
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Description;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Trigger;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Type;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FDTFLuxStartStageData> Datas;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxStartListItemPayload
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// "Report": "Start List",
|
||||
// "ContestID": 0,
|
||||
// "ContestName": "",
|
||||
// "Bib": 1039,
|
||||
// "Firstname": "Mystère",
|
||||
// "Lastname": "Mystère",
|
||||
// "Gender": "",
|
||||
// "Club": "",
|
||||
// "Firstname2": "",
|
||||
// "Lastname2": "",
|
||||
// "Gender2": "",
|
||||
// "Club2": "",
|
||||
// "TeamName": "",
|
||||
// "Category": "",
|
||||
// "Elite": false
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int ContestID;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString ContestName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Bib;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString FirstName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString LastName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gender;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Club;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString FirstName2;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString LastName2;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gender2;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Club2;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TeamName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Category;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
bool Elite;
|
||||
};
|
||||
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxStartListPayload
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FDTFluxStartListItemPayload> Participants;
|
||||
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxParticipant
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString FirstName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString LastName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Club;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gender;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Category;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxTeam
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FDTFluxParticipant> Participants;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TeamName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Bib;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FDTFluxContest
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int ContestID;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString ContestName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FDTFluxTeam> TeamParticipants;
|
||||
|
||||
bool AddTeam(FDTFluxTeam Team)
|
||||
{
|
||||
TeamParticipants.Add(Team);
|
||||
return true;
|
||||
}
|
||||
bool TeamAlreadyExist(FDTFluxTeam Team)
|
||||
{
|
||||
for(const auto& MyTeam : TeamParticipants)
|
||||
{
|
||||
// Compare Bib
|
||||
if(MyTeam.Bib == Team.Bib )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct DTFLUXAPI_API FDTFluxContestList
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TMap<FString, FDTFluxContest>Contests;
|
||||
|
||||
int GetContestId(const FString& ContestName) const
|
||||
{
|
||||
const FDTFluxContest* Contest = Contests.Find(ContestName);
|
||||
if(Contest)
|
||||
{
|
||||
return Contest->ContestID;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
FString GetContestName(const int& ContestId) const
|
||||
{
|
||||
for (const auto& Contest : Contests)
|
||||
{
|
||||
if (Contest.Value.ContestID == ContestId)
|
||||
{
|
||||
return Contest.Key;
|
||||
}
|
||||
}
|
||||
return FString();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
UCLASS(Blueprintable, Category="DTFlux|Model")
|
||||
class DTFLUXAPI_API UDTFluxContestBPFn : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "DT Http Server|Params")
|
||||
static int GetContestId(const FDTFluxContestList& ContestList, const FString& ContestName)
|
||||
{
|
||||
return ContestList.GetContestId(ContestName);
|
||||
}
|
||||
UFUNCTION(BlueprintPure, Category = "DT Http Server|Params")
|
||||
static FString GetContestName(const FDTFluxContestList& ContestList, const int& ContestId)
|
||||
{
|
||||
return ContestList.GetContestName(ContestId);
|
||||
}
|
||||
};
|
||||
|
||||
// TeamListItem Response from proxy Containing Team definition
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FResponseTeamListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Contest;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Bib;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString FirstName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString LastName;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gender;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
bool Elite;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Club;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Team;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Category;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Status;
|
||||
};
|
||||
// TeamList Response from proxy Containing List of Team
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseTeamList
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FResponseTeamListItem> Datas;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseStageListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Id;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Name;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString StartTime;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString EndTime;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseSplitsListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Id;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Name;
|
||||
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseRaceListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Id;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Name;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Date;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FProxyResponseStageListItem> Stages;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FProxyResponseSplitsListItem> Splits;
|
||||
|
||||
};
|
||||
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseContestRankingListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Bib;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Rank;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Time;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gap;
|
||||
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseContestRankingList
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int ContestId;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FProxyResponseContestRankingListItem> Datas;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseStageRankingListItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Bib;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int Rank;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Time;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Gap;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TimeSwim;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TimeTransition;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TimeRun;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString TimeStart;
|
||||
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Model")
|
||||
struct FProxyResponseStageRankingList
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int ContestId;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
int StageId;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
TArray<FProxyResponseStageRankingListItem> Datas;
|
||||
|
||||
};
|
||||
@ -0,0 +1,154 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DeveloperSettings.h"
|
||||
#include "DTFluxAPILog.h"
|
||||
#include "DTFluxProjectSettings.generated.h"
|
||||
|
||||
UENUM()
|
||||
enum EDTFluxAPIRoute: uint8
|
||||
{
|
||||
Root UMETA(DisplayName="API Root"),
|
||||
Results UMETA(DisplayName="Results Route"),
|
||||
Starters UMETA(DisplayName="Starters List Route"),
|
||||
FinalClassification UMETA(DisplayName="Final Classification Route"),
|
||||
|
||||
};
|
||||
|
||||
|
||||
UENUM()
|
||||
enum EDTFluxProxyRoute : uint8
|
||||
{
|
||||
ProxyRaceData UMETA(DisplayName="Proxy Race Data"),
|
||||
ProxyRankingContest UMETA(DisplayName="Proxy Ranking Contest Data"),
|
||||
ProxyRankingStage UMETA(DisplayName="Proxy Ranking Stage Data"),
|
||||
ProxyTeams UMETA(DisplayName="Proxy Teams Data"),
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FSearchFilters
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Config", EditAnywhere)
|
||||
int ContestId = 0;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Config", EditAnywhere)
|
||||
int StageId = 0;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Config", EditAnywhere)
|
||||
int GenderId = 0;
|
||||
|
||||
FString GetFilter() const
|
||||
{
|
||||
if(ContestId == 0 && StageId == 0 && GenderId == 0)
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Gender Test -> %i"), GenderId);
|
||||
return FString();
|
||||
}
|
||||
TArray<FString> Filters;
|
||||
Filters.Add(FString("?"));
|
||||
if (ContestId > 0)
|
||||
{
|
||||
Filters.Add(FString::Printf(TEXT("Contest=%i"), ContestId) );
|
||||
}
|
||||
if (StageId > 0)
|
||||
{
|
||||
Filters.Add(FString::Printf(TEXT("SelectorResult=%i"), StageId) );
|
||||
}
|
||||
if (GenderId > 0)
|
||||
{
|
||||
switch(GenderId)
|
||||
{
|
||||
case (2):
|
||||
// default is male
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Gender Female -> %i"), GenderId);
|
||||
|
||||
Filters.Add(FString(TEXT("filter=[Gender]=\"f\"") ) );
|
||||
break;
|
||||
default:
|
||||
// default is male
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Gender male -> %i"), GenderId);
|
||||
Filters.Add(FString(TEXT("filter=[Gender]=\"m\"") ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(const auto& Element : Filters)
|
||||
{
|
||||
UE_LOG(LogDTFluxAPI, Type::Log, TEXT("Element : %s"), *Element);
|
||||
|
||||
}
|
||||
FString FinalFilters = FString::Join(Filters, TEXT("&"));
|
||||
FinalFilters.RemoveAt(1);
|
||||
return FinalFilters;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(Blueprintable, Config=Engine, DefaultConfig, meta=(DisplayName="DTFlux Project Settings"))
|
||||
class DTFLUXAPI_API UDTFluxProjectSettings : public UDeveloperSettings
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
|
||||
UPROPERTY(Category="DTFlux|Server Config", Config, EditAnywhere, BlueprintReadOnly)
|
||||
int InPort = 8080;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
int RaceResultPort = 80;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Server Config", Config, EditAnywhere, BlueprintReadOnly)
|
||||
TArray<FString> Endpoints;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString ProxyUrl = "http://localhost";
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString APIToken;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
bool bAccessIsLocal = true;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString StartListAccessToken;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString GeneralClassificationAccessToken;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Race Result API", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString LiveStageResultsAccessToken ;
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Chrono Proxy", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString ProxyAddress = "http://localhost";
|
||||
|
||||
UPROPERTY(Category="DTFlux|Config|Chrono Proxy", Config, EditAnywhere, BlueprintReadOnly)
|
||||
FString ProxyRootPath = "/endpoints";
|
||||
|
||||
UPROPERTY(Category="DTFlux|Chrono Proxy", Config, EditAnywhere, BlueprintReadOnly)
|
||||
int ProxyPort = 8000;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Config")
|
||||
FString GetAPIPath(const TEnumAsByte<EDTFluxAPIRoute> RouteType, const FString& Filters = TEXT("") ) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Config")
|
||||
FString GetAPIPathFiltered(const TEnumAsByte<EDTFluxAPIRoute> RouteType, const FSearchFilters& Filters ) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Config")
|
||||
FString GetProxyPath(const TEnumAsByte<EDTFluxProxyRoute> RouteType, const int& InContest = -1, const int& InStage = -1) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Config")
|
||||
static const UDTFluxProjectSettings* GetDTFluxAPIProjectSettings();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
UDTFluxProjectSettings();
|
||||
};
|
||||
|
||||
153
Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h
Normal file
153
Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h
Normal file
@ -0,0 +1,153 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Runtime/Engine/Public/Subsystems/EngineSubsystem.h"
|
||||
#include "HttpServerRequest.h"
|
||||
#include "HttpResultCallback.h"
|
||||
#include "HttpRouteHandle.h"
|
||||
#include <string>
|
||||
|
||||
#include "DTFluxUtils/DTFluxHttpServerStruct.h"
|
||||
#include "DTFluxAPILog.h"
|
||||
#include "DTFluxModel/DTFluxModel.h"
|
||||
|
||||
#include "DTFluxSubsystem.generated.h"
|
||||
|
||||
|
||||
class UDTFluxProjectSettings;
|
||||
class IHttpRouter;
|
||||
|
||||
class IHttpRequest;
|
||||
class IHttpResponse;
|
||||
|
||||
class FHttpModule;
|
||||
typedef TSharedPtr<IHttpRequest, ESPMode::ThreadSafe> FHttpRequestPtr;
|
||||
typedef TSharedPtr<IHttpResponse, ESPMode::ThreadSafe> FHttpResponsePtr;
|
||||
|
||||
UENUM(BlueprintType, Category="DTFlux|Server")
|
||||
enum EDTFluxResponseErrorCode
|
||||
{
|
||||
Unknown_Error UMETA(DisplayName="Unknown Error"),
|
||||
InvalidBody_Error UMETA(DisplayName="Invalid Body"),
|
||||
InvalidRequest_Error UMETA(DisplayName="Invalid Request"),
|
||||
Internal_Error UMETA(DisplayName="Internal Server Error")
|
||||
};
|
||||
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Server")
|
||||
struct FDTFluxResponseBody
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Error;
|
||||
|
||||
UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly)
|
||||
FString Success;
|
||||
|
||||
FString Deserialize()
|
||||
{
|
||||
FString JSONObject;
|
||||
JSONObject += TEXT("{");
|
||||
JSONObject += TEXT("\"error\":\"");
|
||||
JSONObject += Error.IsEmpty() ? TEXT("") : Error;
|
||||
JSONObject += TEXT("\",\"success\":\"");
|
||||
JSONObject += Success.IsEmpty() ? TEXT("") : Success;
|
||||
JSONObject += TEXT("\"}");
|
||||
UE_LOG(LogDTFluxAPI, Log, TEXT("JSONObject : %s"), *JSONObject);
|
||||
return JSONObject;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDTFluxOnRequestReceived, FDTFluxHttpServerHeaders, HttpServerHeaders,
|
||||
FDTFluxHttpServerParams, HttpServerParams, FDTFluxHttpServerBody, HttpRequestBody);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDTFluxOnServerListening);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDTFluxOnServerStopped);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDTFluxOnEventStartReceived, FDTFluxStartStagePayload, Payload);
|
||||
|
||||
/**
|
||||
* DTFlux API Subsystem
|
||||
*
|
||||
* This Subsystem Mount HTTP routes to be listened and an HTTP poller to retrieve basic information.
|
||||
*/
|
||||
UCLASS()
|
||||
class DTFLUXAPI_API UDTFluxSubsystem : public UEngineSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
|
||||
bool bIsListening = false;
|
||||
const UDTFluxProjectSettings* mSettings;
|
||||
|
||||
bool OnRequest(const FHttpServerRequest& Request);
|
||||
|
||||
void HandleRequest(const FString& Route, const FHttpServerRequest& Request, FHttpResultCallback OnComplete);
|
||||
// // StartList Payload;
|
||||
// FDTFluxStartListPayload StartList;
|
||||
// Contest storage
|
||||
FDTFluxContestList Contests;
|
||||
|
||||
void OnUpdateStartList(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
|
||||
protected:
|
||||
|
||||
TMap<FString, FHttpRouteHandle> HttpMountedMap;
|
||||
TSharedPtr<IHttpRouter> HttpRouter;
|
||||
// Stop The Server
|
||||
void StopServer();
|
||||
// Create the server response
|
||||
TUniquePtr<FHttpServerResponse> CreateHttpServerResponse() const;
|
||||
FHttpModule* HttpRequest;
|
||||
|
||||
|
||||
public:
|
||||
/** Implement this for initialization of instances of the system */
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
|
||||
/** Implement this for deinitialization of instances of the system */
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category="DTFlux|Subsystem|Events")
|
||||
FDTFluxOnRequestReceived OnRequestReceived;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category="DTFlux|Subsystem|Events")
|
||||
FDTFluxOnServerListening OnServerListening;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category="DTFlux|Subsystem|Events")
|
||||
FDTFluxOnServerStopped OnServerStopped;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category="DTFlux|Subsystem|Events")
|
||||
FDTFluxOnEventStartReceived OnEventStartReceived;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem")
|
||||
TArray<FString> GetMountedRoutes() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem")
|
||||
void StartServer();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Events")
|
||||
TArray<FDTFluxTeam> GetParticipantsByContestId(const int ContestId );
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Events")
|
||||
TArray<FDTFluxTeam> GetParticipantsByContestName(const FString ContestName);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Events")
|
||||
FString GetContestName(const int ContestId);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Race Result Call")
|
||||
void UpdateStartList();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Race Result Call")
|
||||
void UpdateClassification(const int& ContestId, const int& StageId = -1);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Race Result Call")
|
||||
TArray<FDTFluxParticipant> GetClassification(const int& ContestId, const int& StageId = -1);
|
||||
|
||||
};
|
||||
|
||||
68
Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h
Normal file
68
Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2023 Dexter.Wan. All Rights Reserved.
|
||||
// EMail: 45141961@qq.com
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "DTFluxHttpServerStruct.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum EDTFluxHttpServerVerbs : uint8
|
||||
{
|
||||
HTTP_GET,
|
||||
HTTP_POST,
|
||||
HTTP_PUT,
|
||||
HTTP_PATCH,
|
||||
HTTP_DELETE,
|
||||
};
|
||||
|
||||
// USTRUCT(BlueprintType, meta=(DisplayName="DT Http Server Headers", HasNativeBreak = "DTHttpServer.DTHttpServerBPLib.BreakHeaders"))
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Server", meta=(HasNativeBreak = "DTFluxAPI.DTFluxHttpServerBPFn.BreakHeaders"))
|
||||
struct FDTFluxHttpServerHeaders
|
||||
{
|
||||
GENERATED_BODY()
|
||||
TMap<FString, FString> Headers;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Server", meta=(HasNativeBreak = "DTFluxAPI.DTFluxHttpServerBPFn.BreakBody"))
|
||||
struct FDTFluxHttpServerBody
|
||||
{
|
||||
GENERATED_BODY()
|
||||
TArray<uint8> ReqBody;
|
||||
};
|
||||
|
||||
// USTRUCT(BlueprintType, meta=(DisplayName="DTFlux Server Params", HasNativeBreak = "DTHttpServer.DTHttpServerBPLib.BreakParams"))
|
||||
USTRUCT(BlueprintType, Category="DTFlux|Server", meta=(HasNativeBreak = "DTFluxAPI.DTFluxHttpServerBPFn.BreakParams"))
|
||||
struct FDTFluxHttpServerParams
|
||||
{
|
||||
GENERATED_BODY()
|
||||
TMap<FString, FString> Params;
|
||||
};
|
||||
|
||||
UCLASS(NotBlueprintable, NotBlueprintType)
|
||||
class DTFLUXAPI_API UDTFluxHttpServerBPFn : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Break DTFlux Http Server Params
|
||||
UFUNCTION(BlueprintPure, meta = (DisplayName="Break Http Server Params"), Category = "DT Http Server|Params")
|
||||
static void BreakParams(const FDTFluxHttpServerParams& HttpServerParams, TMap<FString, FString>& Params);
|
||||
|
||||
// Find DTFlux Http Server Params
|
||||
UFUNCTION(BlueprintPure, meta = (DisplayName="Find Http Server Params"), Category = "DT Http Server|Params")
|
||||
static void FindParam(const FDTFluxHttpServerParams& HttpServerParams, const FString & Key, FString & Param );
|
||||
|
||||
// Break DTFlux Http Server Headers
|
||||
UFUNCTION(BlueprintPure, meta = (DisplayName="Break Http Server Headers"), Category = "DT Http Server|Headers")
|
||||
static void BreakHeaders(const FDTFluxHttpServerHeaders& HttpServerHeaders, TMap<FString, FString>& Headers);
|
||||
|
||||
// Break DTFlux Request Body
|
||||
UFUNCTION(BlueprintPure, meta = (DisplayName="Break Http Server Headers"), Category = "DT Http Server|Headers")
|
||||
static void BreakBody(const FDTFluxHttpServerBody& HttpBody, TArray<uint8> RawBody);
|
||||
|
||||
// Find DTFlux Http Server Headers
|
||||
UFUNCTION(BlueprintPure, meta = (DisplayName="Find Http Server Headers"), Category = "DT Http Server|Headers")
|
||||
static void FindHeader(const FDTFluxHttpServerHeaders& HttpServerHeaders, const FString & Key, FString & Header );
|
||||
};
|
||||
Reference in New Issue
Block a user