From e5ed9300028dbb9a3c5c403a9f437ed5b85e6c91 Mon Sep 17 00:00:00 2001 From: Ange-Marie MAURIN Date: Sat, 8 Jun 2024 09:41:08 +0200 Subject: [PATCH] First Commit with code --- Config/DefaultDTFluxAPI.ini | 3 + DTFluxAPI.uplugin | 30 ++ Resources/Icon128.png | Bin 0 -> 12699 bytes Source/DTFluxAPI/DTFluxAPI.Build.cs | 36 ++ Source/DTFluxAPI/Private/DTFluxAPI.cpp | 22 + .../Private/DTFluxModel/DTFluxModel.cpp | 4 + .../DTFluxProjectSettings.cpp | 73 +++ .../DTFluxSubsystem/DTFluxSubsystem.cpp | 331 ++++++++++++++ .../DTFluxUtils/DTFluxHttpServerStruct.cpp | 38 ++ Source/DTFluxAPI/Public/DTFluxAPI.h | 15 + Source/DTFluxAPI/Public/DTFluxAPILog.h | 6 + .../Public/DTFluxModel/DTFluxModel.h | 423 ++++++++++++++++++ .../DTFluxProjectSettings.h | 154 +++++++ .../Public/DTFluxSubsystem/DTFluxSubsystem.h | 153 +++++++ .../DTFluxUtils/DTFluxHttpServerStruct.h | 68 +++ 15 files changed, 1356 insertions(+) create mode 100644 Config/DefaultDTFluxAPI.ini create mode 100644 DTFluxAPI.uplugin create mode 100644 Resources/Icon128.png create mode 100644 Source/DTFluxAPI/DTFluxAPI.Build.cs create mode 100644 Source/DTFluxAPI/Private/DTFluxAPI.cpp create mode 100644 Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp create mode 100644 Source/DTFluxAPI/Private/DTFluxProjectSettings/DTFluxProjectSettings.cpp create mode 100644 Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp create mode 100644 Source/DTFluxAPI/Private/DTFluxUtils/DTFluxHttpServerStruct.cpp create mode 100644 Source/DTFluxAPI/Public/DTFluxAPI.h create mode 100644 Source/DTFluxAPI/Public/DTFluxAPILog.h create mode 100644 Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h create mode 100644 Source/DTFluxAPI/Public/DTFluxProjectSettings/DTFluxProjectSettings.h create mode 100644 Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h create mode 100644 Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h diff --git a/Config/DefaultDTFluxAPI.ini b/Config/DefaultDTFluxAPI.ini new file mode 100644 index 0000000..ed9b8f0 --- /dev/null +++ b/Config/DefaultDTFluxAPI.ini @@ -0,0 +1,3 @@ +[CoreRedirects] ++ClassRedirects=(OldName="/Script/DTFluxAPI.DTHttpServerObject",NewName="/Script/DTFluxAPI.DTFluxHttpServerObject") ++StructRedirects=(OldName="/Script/DTFluxAPI.DTHttpServerParams",NewName="/Script/DTFluxAPI.DTFluxHttpServerParams") \ No newline at end of file diff --git a/DTFluxAPI.uplugin b/DTFluxAPI.uplugin new file mode 100644 index 0000000..a278bb5 --- /dev/null +++ b/DTFluxAPI.uplugin @@ -0,0 +1,30 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "DTFluxAPI", + "Description": "DTFlux API plugin", + "Category": "Other", + "CreatedBy": "Ange-Marie MAURIN", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": true, + "IsBetaVersion": false, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "DTFluxAPI", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ], + "Plugins": [ + { + "Name": "Avalanche", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/Resources/Icon128.png b/Resources/Icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..1231d4aad4d0d462fb7b178eb5b30aa61a10df0b GIT binary patch literal 12699 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 a;7#~yJh_ha>A&A^fRdb=Y>l)<=>Gxy=2LS3 literal 0 HcmV?d00001 diff --git a/Source/DTFluxAPI/DTFluxAPI.Build.cs b/Source/DTFluxAPI/DTFluxAPI.Build.cs new file mode 100644 index 0000000..771917a --- /dev/null +++ b/Source/DTFluxAPI/DTFluxAPI.Build.cs @@ -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", + } + ); + } +} diff --git a/Source/DTFluxAPI/Private/DTFluxAPI.cpp b/Source/DTFluxAPI/Private/DTFluxAPI.cpp new file mode 100644 index 0000000..dacdf82 --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxAPI.cpp @@ -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) \ No newline at end of file diff --git a/Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp b/Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp new file mode 100644 index 0000000..cb85533 --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxModel/DTFluxModel.cpp @@ -0,0 +1,4 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DTFluxModel/DTFluxModel.h" diff --git a/Source/DTFluxAPI/Private/DTFluxProjectSettings/DTFluxProjectSettings.cpp b/Source/DTFluxAPI/Private/DTFluxProjectSettings/DTFluxProjectSettings.cpp new file mode 100644 index 0000000..ada8355 --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxProjectSettings/DTFluxProjectSettings.cpp @@ -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 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 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 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() +{ + SectionName = "DTFlux Settings"; +} diff --git a/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp new file mode 100644 index 0000000..8dcc7aa --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp @@ -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 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(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 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 Payload; + if(!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(ModifiedData), Payload)) + { + UE_LOG(LogDTFluxAPI, Error, TEXT("unable to parse JSON Payload****")); + }else + { + FDTFluxStartListPayload StartList; + if (FJsonObjectConverter::JsonObjectToUStruct(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 UDTFluxSubsystem::CreateHttpServerResponse() const +{ + // Create a Response to be returned by the server + TUniquePtr Response = MakeUnique(); + 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 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 UDTFluxSubsystem::GetMountedRoutes() const +{ + TArray Mounted = TArray(); + 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 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 EmptyTeam; + return EmptyTeam; + } + +} + +TArray 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 EmptyTeam; + return EmptyTeam; + } +} + +FString UDTFluxSubsystem::GetContestName(const int ContestId) +{ + if(Contests.GetContestName(ContestId) != "") + { + return Contests.GetContestName(ContestId); + } + return TEXT(""); +} + +void UDTFluxSubsystem::UpdateStartList() +{ + const TSharedRef 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 UDTFluxSubsystem::GetClassification(const int& ContestId, const int& StageId) +{ + return TArray(); +} + +void UDTFluxSubsystem::StopServer() +{ + FHttpServerModule::Get().StopAllListeners(); + bIsListening = false; + OnServerStopped.Broadcast(); +} diff --git a/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxHttpServerStruct.cpp b/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxHttpServerStruct.cpp new file mode 100644 index 0000000..4bcaf86 --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxHttpServerStruct.cpp @@ -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& 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& Headers) +{ + Headers = HttpServerHeaders.Headers; +} + +void UDTFluxHttpServerBPFn::BreakBody(const FDTFluxHttpServerBody& HttpBody, TArray 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; + } +} + diff --git a/Source/DTFluxAPI/Public/DTFluxAPI.h b/Source/DTFluxAPI/Public/DTFluxAPI.h new file mode 100644 index 0000000..a805861 --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxAPI.h @@ -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; +}; diff --git a/Source/DTFluxAPI/Public/DTFluxAPILog.h b/Source/DTFluxAPI/Public/DTFluxAPILog.h new file mode 100644 index 0000000..30d3703 --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxAPILog.h @@ -0,0 +1,6 @@ +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogDTFluxAPI, Log, All); \ No newline at end of file diff --git a/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h new file mode 100644 index 0000000..3183ddd --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h @@ -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 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 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 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 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) + TMapContests; + + 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 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 Stages; + + UPROPERTY(Blueprintable, Category="DTFlux|Model", BlueprintReadOnly) + TArray 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 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 Datas; + +}; \ No newline at end of file diff --git a/Source/DTFluxAPI/Public/DTFluxProjectSettings/DTFluxProjectSettings.h b/Source/DTFluxAPI/Public/DTFluxProjectSettings/DTFluxProjectSettings.h new file mode 100644 index 0000000..0c40be1 --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxProjectSettings/DTFluxProjectSettings.h @@ -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 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 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 RouteType, const FString& Filters = TEXT("") ) const; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Config") + FString GetAPIPathFiltered(const TEnumAsByte RouteType, const FSearchFilters& Filters ) const; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Config") + FString GetProxyPath(const TEnumAsByte RouteType, const int& InContest = -1, const int& InStage = -1) const; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Config") + static const UDTFluxProjectSettings* GetDTFluxAPIProjectSettings(); + +protected: + + +private: + UDTFluxProjectSettings(); +}; + \ No newline at end of file diff --git a/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h new file mode 100644 index 0000000..2e3e920 --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h @@ -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 + +#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 FHttpRequestPtr; +typedef TSharedPtr 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 HttpMountedMap; + TSharedPtr HttpRouter; + // Stop The Server + void StopServer(); + // Create the server response + TUniquePtr 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 GetMountedRoutes() const; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem") + void StartServer(); + + UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Events") + TArray GetParticipantsByContestId(const int ContestId ); + + UFUNCTION(BlueprintCallable, Category="DTFlux|Subsystem|Events") + TArray 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 GetClassification(const int& ContestId, const int& StageId = -1); + +}; + diff --git a/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h new file mode 100644 index 0000000..d21770c --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxHttpServerStruct.h @@ -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 Headers; +}; + +USTRUCT(BlueprintType, Category="DTFlux|Server", meta=(HasNativeBreak = "DTFluxAPI.DTFluxHttpServerBPFn.BreakBody")) +struct FDTFluxHttpServerBody +{ + GENERATED_BODY() + TArray 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 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& 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& 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 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 ); +};