Added Pursuit functionality (Untested and not fully implemented) + Global TrackedRequestSending check
This commit is contained in:
@ -90,6 +90,38 @@ FGuid UDTFluxQueuedManager::QueueRequest(EDTFluxRequestType RequestType, int32 C
|
||||
return NewRequest.RequestId;
|
||||
}
|
||||
|
||||
bool UDTFluxQueuedManager::MarkRequestAsError(const FGuid& TargetRequestGuid)
|
||||
{
|
||||
// TODO: Implement a retry mechanism
|
||||
// For now we simply suppress the request and log a message
|
||||
bool bFoundMatch = false;
|
||||
FDTFluxQueuedRequest Request;
|
||||
TQueue<FDTFluxQueuedRequest, EQueueMode::Mpsc> TempQueue;
|
||||
while (PendingRequestsQueue.Dequeue(Request))
|
||||
{
|
||||
if (Request.RequestId == TargetRequestGuid)
|
||||
{
|
||||
UE_LOG(logDTFluxNetwork, Error,
|
||||
TEXT("Marked request %s as error: Type=%d, ContestId=%d, StageId=%d, SplitId=%d"),
|
||||
*Request.RequestId.ToString(), (int32)Request.RequestType, Request.ContestId, Request.StageId,
|
||||
Request.SplitId);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempQueue.Enqueue(Request);
|
||||
}
|
||||
}
|
||||
while (TempQueue.Dequeue(Request))
|
||||
{
|
||||
PendingRequestsQueue.Enqueue(Request);
|
||||
}
|
||||
if (bFoundMatch)
|
||||
{
|
||||
UE_LOG(logDTFluxNetwork, Error, TEXT("No Request Found with GUID %s"), *TargetRequestGuid.ToString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UDTFluxQueuedManager::MarkRequestAsResponded(const FGuid& TargetRequestGuid)
|
||||
{
|
||||
TQueue<FDTFluxQueuedRequest, EQueueMode::Mpsc> TempQueue;
|
||||
@ -134,7 +166,8 @@ bool UDTFluxQueuedManager::MarkRequestAsResponded(const FDTFluxQueuedRequest& Ta
|
||||
return MarkRequestAsResponded(TargetRequest.RequestId);
|
||||
}
|
||||
|
||||
bool UDTFluxQueuedManager::IsRequestPending(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId,
|
||||
bool UDTFluxQueuedManager::IsRequestPending(FGuid& OutRequestId, EDTFluxApiDataType RequestType, int32 ContestId,
|
||||
int32 StageId,
|
||||
int32 SplitId)
|
||||
{
|
||||
TQueue<FDTFluxQueuedRequest, EQueueMode::Mpsc> TempQueue;
|
||||
@ -148,6 +181,11 @@ bool UDTFluxQueuedManager::IsRequestPending(EDTFluxApiDataType RequestType, int3
|
||||
if (!bFoundMatch && Request.Matches(RequestType, ContestId, StageId, SplitId))
|
||||
{
|
||||
bFoundMatch = true;
|
||||
OutRequestId = Request.RequestId;
|
||||
UE_LOG(logDTFluxNetwork, Verbose,
|
||||
TEXT("Found pending request %s: Type=%d, ContestId=%d, StageId=%d, SplitId=%d"),
|
||||
*Request.RequestId.ToString(), (int32)Request.RequestType, Request.ContestId, Request.StageId,
|
||||
Request.SplitId);
|
||||
}
|
||||
|
||||
// Remettre dans la queue temporaire
|
||||
|
||||
@ -370,13 +370,13 @@ bool FDTFluxServerResponse::ParseContestRanking(FDTFluxContestRankings& OutConte
|
||||
|
||||
bool FDTFluxServerResponse::ParseStageRankingResponse(FDTFluxStageRankings& OutStageRankings)
|
||||
{
|
||||
// UE_LOG(logDTFluxNetwork, Log, TEXT("Response is stage-ranking type %s"), *RawMessage);
|
||||
if (!ValidateResponseType(TEXT("stage-ranking")))
|
||||
{
|
||||
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a stage-ranking type"));
|
||||
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
||||
return false;
|
||||
}
|
||||
|
||||
FDTFluxStageRankingResponse RankingResponse;
|
||||
if (!FJsonObjectConverter::JsonObjectStringToUStruct<FDTFluxStageRankingResponse>(RawMessage, &RankingResponse))
|
||||
{
|
||||
@ -384,6 +384,7 @@ bool FDTFluxServerResponse::ParseStageRankingResponse(FDTFluxStageRankings& OutS
|
||||
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
||||
return false;
|
||||
}
|
||||
UE_LOG(logDTFluxNetwork, Log, TEXT("Reponse Update"));
|
||||
|
||||
OutStageRankings.ContestId = ContestID;
|
||||
OutStageRankings.StageId = StageID;
|
||||
|
||||
@ -81,8 +81,9 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallback(
|
||||
int32 ContestId,
|
||||
int32 StageId,
|
||||
int32 SplitId,
|
||||
FOnDTFluxRequestResponse OnCompleted,
|
||||
FOnDTFluxRequestTimeout OnTimeout,
|
||||
FOnDTFluxTrackedRequestResponse OnCompleted,
|
||||
FOnDTFluxTrackedRequestTimeout OnTimeout,
|
||||
TOptional<FOnDTFluxRequestResponseError> OnError,
|
||||
float TimeoutSeconds)
|
||||
{
|
||||
FGuid RequestId = SendTrackedRequest(RequestType, ContestId, StageId, SplitId, TimeoutSeconds);
|
||||
@ -98,11 +99,16 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallback(
|
||||
{
|
||||
PendingTimeoutCallbacks.Add(RequestId, OnTimeout);
|
||||
}
|
||||
if (OnError.IsSet() && OnError.GetValue().IsBound())
|
||||
{
|
||||
PendingErrorCallbacks.Add(RequestId, OnError.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
return RequestId;
|
||||
}
|
||||
|
||||
|
||||
bool UDTFluxNetworkSubsystem::GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const
|
||||
{
|
||||
if (!QueueManager)
|
||||
@ -155,7 +161,8 @@ bool UDTFluxNetworkSubsystem::IsRequestPending(EDTFluxRequestType RequestType, i
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return QueueManager->IsRequestPending(RequestType, ContestId, StageId, SplitId);
|
||||
FGuid OutRequestId;
|
||||
return QueueManager->IsRequestPending(OutRequestId, RequestType, ContestId, StageId, SplitId);
|
||||
}
|
||||
|
||||
int32 UDTFluxNetworkSubsystem::GetPendingRequestCount() const
|
||||
@ -583,8 +590,6 @@ void UDTFluxNetworkSubsystem::Parse(FDTFluxServerResponse& Response)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO reforge API to keep track of Requests
|
||||
void UDTFluxNetworkSubsystem::OnWebSocketMessageEvent_Subsystem(const FString& MessageString)
|
||||
{
|
||||
// UE_LOG(logDTFluxNetwork, Warning, TEXT("Client %s :\nMessage Received : %s"), *WsClient->GetAddress(), *MessageString);
|
||||
@ -600,8 +605,11 @@ void UDTFluxNetworkSubsystem::OnWebSocketMessageEvent_Subsystem(const FString& M
|
||||
UE_LOG(logDTFluxNetwork, Warning, TEXT("Not a push message"));
|
||||
// Legacy
|
||||
Parse(Response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// // if we are here we have a tracked Message
|
||||
// QueueManager->MarkRequestAsResponded()
|
||||
}
|
||||
|
||||
void UDTFluxNetworkSubsystem::OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent)
|
||||
@ -609,6 +617,29 @@ void UDTFluxNetworkSubsystem::OnWebSocketMessageSentEvent_Subsystem(const FStrin
|
||||
UE_LOG(logDTFluxNetwork, Warning, TEXT("Ws %s :\nMessage Sent: %s"), *WsClient->GetAddress(), *MessageSent);
|
||||
}
|
||||
|
||||
bool UDTFluxNetworkSubsystem::CleanRequestCallbacks(const FGuid& RequestId)
|
||||
{
|
||||
bool bCbSuppressSuccess = false;
|
||||
bool bErrorCbSuppressSuccess = false;
|
||||
bool bTimeoutCbSuppressSuccess = false;
|
||||
if (PendingCallbacks.Contains(RequestId))
|
||||
{
|
||||
PendingCallbacks.Remove(RequestId);
|
||||
bCbSuppressSuccess = true;
|
||||
}
|
||||
if (PendingTimeoutCallbacks.Contains(RequestId))
|
||||
{
|
||||
PendingTimeoutCallbacks.Remove(RequestId);
|
||||
bTimeoutCbSuppressSuccess = true;
|
||||
}
|
||||
if (PendingTimeoutCallbacks.Contains(RequestId))
|
||||
{
|
||||
PendingTimeoutCallbacks.Remove(RequestId);
|
||||
bErrorCbSuppressSuccess = true;
|
||||
}
|
||||
return bCbSuppressSuccess && bErrorCbSuppressSuccess && bTimeoutCbSuppressSuccess;
|
||||
}
|
||||
|
||||
void UDTFluxNetworkSubsystem::OnRequestTimedOut_Internal(const FDTFluxQueuedRequest& TimedOutRequest)
|
||||
{
|
||||
UE_LOG(logDTFluxNetwork, Warning, TEXT("Request %s timed out: Type=%d, Contest=%d, Stage=%d, Split=%d"),
|
||||
@ -619,7 +650,7 @@ void UDTFluxNetworkSubsystem::OnRequestTimedOut_Internal(const FDTFluxQueuedRequ
|
||||
TimedOutRequest.SplitId);
|
||||
|
||||
// Appeler le callback de timeout si présent
|
||||
if (FOnDTFluxRequestTimeout* TimeoutCallback = PendingTimeoutCallbacks.Find(TimedOutRequest.RequestId))
|
||||
if (FOnDTFluxTrackedRequestTimeout* TimeoutCallback = PendingTimeoutCallbacks.Find(TimedOutRequest.RequestId))
|
||||
{
|
||||
if (TimeoutCallback->IsBound())
|
||||
{
|
||||
@ -635,32 +666,28 @@ void UDTFluxNetworkSubsystem::OnRequestTimedOut_Internal(const FDTFluxQueuedRequ
|
||||
OnTrackedRequestFailed.Broadcast(TimedOutRequest.RequestId, TimedOutRequest.RequestType, TEXT("Request timeout"));
|
||||
}
|
||||
|
||||
bool UDTFluxNetworkSubsystem::TryMatchResponseToQueuedRequest(const FDTFluxServerResponse& Response)
|
||||
bool UDTFluxNetworkSubsystem::TryMatchResponseToQueuedRequest(FDTFluxServerResponse& Response)
|
||||
{
|
||||
if (!QueueManager)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Essayer de trouver une requête correspondante
|
||||
// Note: Cette méthode nécessiterait une modification de UDTFluxQueuedManager pour supporter le matching par type et paramètres
|
||||
|
||||
// Pour l'instant, on utilise une approche simple : chercher la première requête du bon type
|
||||
// Vous devrez probablement modifier UDTFluxQueuedManager pour ajouter une méthode comme FindMatchingRequest()
|
||||
|
||||
|
||||
// Implémentation temporaire : on assume qu'il n'y a qu'une requête de chaque type en cours
|
||||
if (QueueManager->IsRequestPending(Response.GetResponseType(), Response.ContestID, Response.StageID,
|
||||
FGuid FoundRequestId;
|
||||
if (QueueManager->IsRequestPending(FoundRequestId, Response.GetResponseType(), Response.ContestID, Response.StageID,
|
||||
Response.SplitID))
|
||||
{
|
||||
// Marquer comme répondu - vous devrez adapter cette méthode selon votre logique de matching
|
||||
// Pour l'instant, on va faire un workaround simple
|
||||
|
||||
UE_LOG(logDTFluxNetwork, Log,
|
||||
TEXT("Matched response to queued request: Type=%s, Contest=%d, Stage=%d, Split=%d"),
|
||||
*UEnum::GetValueAsString(Response.GetResponseType()), Response.ContestID, Response.StageID,
|
||||
Response.SplitID);
|
||||
|
||||
return true;
|
||||
if (PendingCallbacks.Contains(FoundRequestId))
|
||||
{
|
||||
FOnDTFluxTrackedRequestResponse* SuccessCallback = PendingCallbacks.Find(FoundRequestId);
|
||||
SuccessCallback->ExecuteIfBound(FoundRequestId, Response);
|
||||
//Suppress Callback;
|
||||
return CleanRequestCallbacks(FoundRequestId);
|
||||
}
|
||||
return QueueManager->MarkRequestAsResponded(FoundRequestId);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -676,13 +703,26 @@ void UDTFluxNetworkSubsystem::CompleteTrackedRequest(const FGuid& RequestId, con
|
||||
}
|
||||
|
||||
// Appeler le callback de succès si présent
|
||||
if (FOnDTFluxRequestResponse* SuccessCallback = PendingCallbacks.Find(RequestId))
|
||||
if (FOnDTFluxTrackedRequestResponse* SuccessCallback = PendingCallbacks.Find(RequestId))
|
||||
{
|
||||
if (SuccessCallback->IsBound())
|
||||
{
|
||||
SuccessCallback->Execute(RequestId, ResponseData);
|
||||
EDTFluxResponseStatus ResponseStatus;
|
||||
FDTFluxServerResponse Response(ResponseData, ResponseStatus);
|
||||
if (ResponseStatus == EDTFluxResponseStatus::Success)
|
||||
{
|
||||
SuccessCallback->Execute(RequestId, Response);
|
||||
QueueManager->MarkRequestAsResponded(RequestId);
|
||||
PendingCallbacks.Remove(RequestId);
|
||||
PendingTimeoutCallbacks.Remove(RequestId);
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueManager->MarkRequestAsError(RequestId);
|
||||
// Fail
|
||||
// FailTrackedRequest()
|
||||
}
|
||||
}
|
||||
PendingCallbacks.Remove(RequestId);
|
||||
}
|
||||
|
||||
// Nettoyer le callback de timeout
|
||||
@ -698,11 +738,11 @@ void UDTFluxNetworkSubsystem::FailTrackedRequest(const FGuid& RequestId, const F
|
||||
EDTFluxRequestType RequestType)
|
||||
{
|
||||
// Appeler le callback d'erreur si présent
|
||||
if (FOnDTFluxRequestTimeout* ErrorCallback = PendingTimeoutCallbacks.Find(RequestId))
|
||||
if (FOnDTFluxTrackedRequestTimeout* ErrorCallback = PendingTimeoutCallbacks.Find(RequestId))
|
||||
{
|
||||
if (ErrorCallback->IsBound())
|
||||
{
|
||||
ErrorCallback->Execute(RequestId, ErrorMessage);
|
||||
ErrorCallback->ExecuteIfBound(RequestId, ErrorMessage);
|
||||
}
|
||||
PendingTimeoutCallbacks.Remove(RequestId);
|
||||
}
|
||||
|
||||
@ -11,107 +11,6 @@
|
||||
#include "Types/Enum/DTFluxCoreEnum.h"
|
||||
#include "DTFluxQueuedManager.generated.h"
|
||||
|
||||
/**
|
||||
* @brief Structure représentant une requête en file d'attente avec ses métadonnées
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FDTFluxQueuedRequest : public FDTFluxRequestBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** L'identifiant unique de la requête */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FGuid RequestId;
|
||||
|
||||
/** L'heure à laquelle la requête a été envoyée */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FDateTime CreatedAt;
|
||||
|
||||
/** Le type de requête */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
EDTFluxApiDataType RequestType = EDTFluxRequestType::None;
|
||||
|
||||
/** Identifiant de la compétition (ContestId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 ContestId = -1;
|
||||
|
||||
/** Identifiant de l'étape (StageId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 StageId = -1;
|
||||
|
||||
/** Identifiant du split (SplitId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 SplitId = -1;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FString RawResponse = "";
|
||||
|
||||
/** Délai maximum avant que la requête soit considérée comme expirée (en secondes) */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
float TimeoutSeconds = 2.0f;
|
||||
|
||||
/** Determine si la requête peut être mise en cache */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
bool bIsCacheable = false;
|
||||
|
||||
/** Validité du cache si bIsCacheable est mis à true après reception de la réponse (en secondes) */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
float CachedValidity = 50.0f;
|
||||
|
||||
/** Indicateur si la requête a reçu une réponse */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
bool bHasReceivedResponse = false;
|
||||
|
||||
/** Constructeur par défaut */
|
||||
FDTFluxQueuedRequest()
|
||||
{
|
||||
RequestId = FGuid::NewGuid();
|
||||
CreatedAt = FDateTime::Now();
|
||||
}
|
||||
|
||||
/** Constructeur avec paramètres */
|
||||
FDTFluxQueuedRequest(EDTFluxRequestType InRequestType, int32 InContestId = -1, int32 InStageId = -1,
|
||||
int32 InSplitId = -1)
|
||||
: RequestType(InRequestType)
|
||||
, ContestId(InContestId)
|
||||
, StageId(InStageId)
|
||||
, SplitId(InSplitId)
|
||||
{
|
||||
RequestId = FGuid::NewGuid();
|
||||
CreatedAt = FDateTime::Now();
|
||||
}
|
||||
|
||||
bool operator==(const FDTFluxQueuedRequest& Left) const
|
||||
{
|
||||
return RequestId == Left.RequestId;
|
||||
}
|
||||
|
||||
bool operator!=(const FDTFluxQueuedRequest& Left) const
|
||||
{
|
||||
return RequestId != Left.RequestId;
|
||||
}
|
||||
|
||||
|
||||
const FString Serialize() const;
|
||||
|
||||
/** Vérifie si la requête a expiré */
|
||||
bool HasTimedOut() const
|
||||
{
|
||||
return (FDateTime::Now() - CreatedAt).GetTotalSeconds() > TimeoutSeconds;
|
||||
}
|
||||
|
||||
|
||||
/** Vérifie si cette requête correspond aux paramètres spécifiés */
|
||||
bool Matches(EDTFluxRequestType InRequestType, int32 InContestId = -1, int32 InStageId = -1,
|
||||
int32 InSplitId = -1) const
|
||||
{
|
||||
return RequestType == InRequestType &&
|
||||
(InContestId == -1 || ContestId == InContestId) &&
|
||||
(InStageId == -1 || StageId == InStageId) &&
|
||||
(InSplitId == -1 || SplitId == InSplitId);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRequestTimedOut, const FDTFluxQueuedRequest&, TimedOutRequest);
|
||||
|
||||
/**
|
||||
@ -130,9 +29,11 @@ public:
|
||||
void Initialize();
|
||||
FGuid QueueRequest(EDTFluxRequestType RequestType, int32 ContestId = -1, int32 StageId = -1, int32 SplitId = -1,
|
||||
const FString& RawMessage = "");
|
||||
bool MarkRequestAsError(const FGuid& TargetRequestGuid);
|
||||
bool MarkRequestAsResponded(const FGuid& TargetRequestGuid);
|
||||
bool MarkRequestAsResponded(const FDTFluxQueuedRequest& TargetRequest);
|
||||
bool IsRequestPending(EDTFluxRequestType RequestType, int32 ContestId = -1, int32 StageId = -1, int32 SplitId = -1);
|
||||
bool IsRequestPending(FGuid& OutRequestId, EDTFluxRequestType RequestType, int32 ContestId = -1, int32 StageId = -1,
|
||||
int32 SplitId = -1);
|
||||
FDTFluxQueuedRequest* GetRequestPending(EDTFluxRequestType RequestType, int32 ContestId = -1, int32 StageId = -1,
|
||||
int32 SplitId = -1);
|
||||
const FDTFluxQueuedRequest* GetRequest(const FGuid& SearchedGuid);
|
||||
@ -142,7 +43,6 @@ public:
|
||||
void ClearAllRequests();
|
||||
// bool TryProcessResponse(const FDTFluxServerResponse& Response);
|
||||
|
||||
|
||||
// Interface FTickableGameObject
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
virtual bool IsTickable() const override;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Types/Enum/DTFluxCoreEnum.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "DTFluxRequestStructs.generated.h"
|
||||
|
||||
@ -139,3 +140,104 @@ public:
|
||||
SplitID = InSplitId;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure représentant une requête en file d'attente avec ses métadonnées
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FDTFluxQueuedRequest : public FDTFluxRequestBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** L'identifiant unique de la requête */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FGuid RequestId;
|
||||
|
||||
/** L'heure à laquelle la requête a été envoyée */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FDateTime CreatedAt;
|
||||
|
||||
/** Le type de requête */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
EDTFluxApiDataType RequestType = EDTFluxRequestType::None;
|
||||
|
||||
/** Identifiant de la compétition (ContestId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 ContestId = -1;
|
||||
|
||||
/** Identifiant de l'étape (StageId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 StageId = -1;
|
||||
|
||||
/** Identifiant du split (SplitId) */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
int32 SplitId = -1;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Request")
|
||||
FString RawResponse = "";
|
||||
|
||||
/** Délai maximum avant que la requête soit considérée comme expirée (en secondes) */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
float TimeoutSeconds = 2.0f;
|
||||
|
||||
/** Determine si la requête peut être mise en cache */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
bool bIsCacheable = false;
|
||||
|
||||
/** Validité du cache si bIsCacheable est mis à true après reception de la réponse (en secondes) */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
float CachedValidity = 50.0f;
|
||||
|
||||
/** Indicateur si la requête a reçu une réponse */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "DTFlux|Request")
|
||||
bool bHasReceivedResponse = false;
|
||||
|
||||
/** Constructeur par défaut */
|
||||
FDTFluxQueuedRequest()
|
||||
{
|
||||
RequestId = FGuid::NewGuid();
|
||||
CreatedAt = FDateTime::Now();
|
||||
}
|
||||
|
||||
/** Constructeur avec paramètres */
|
||||
FDTFluxQueuedRequest(EDTFluxRequestType InRequestType, int32 InContestId = -1, int32 InStageId = -1,
|
||||
int32 InSplitId = -1)
|
||||
: RequestType(InRequestType)
|
||||
, ContestId(InContestId)
|
||||
, StageId(InStageId)
|
||||
, SplitId(InSplitId)
|
||||
{
|
||||
RequestId = FGuid::NewGuid();
|
||||
CreatedAt = FDateTime::Now();
|
||||
}
|
||||
|
||||
bool operator==(const FDTFluxQueuedRequest& Left) const
|
||||
{
|
||||
return RequestId == Left.RequestId;
|
||||
}
|
||||
|
||||
bool operator!=(const FDTFluxQueuedRequest& Left) const
|
||||
{
|
||||
return RequestId != Left.RequestId;
|
||||
}
|
||||
|
||||
|
||||
const FString Serialize() const;
|
||||
|
||||
/** Vérifie si la requête a expiré */
|
||||
bool HasTimedOut() const
|
||||
{
|
||||
return (FDateTime::Now() - CreatedAt).GetTotalSeconds() > TimeoutSeconds;
|
||||
}
|
||||
|
||||
|
||||
/** Vérifie si cette requête correspond aux paramètres spécifiés */
|
||||
bool Matches(EDTFluxRequestType InRequestType, int32 InContestId = -1, int32 InStageId = -1,
|
||||
int32 InSplitId = -1) const
|
||||
{
|
||||
return RequestType == InRequestType &&
|
||||
(InContestId == -1 || ContestId == InContestId) &&
|
||||
(InStageId == -1 || StageId == InStageId) &&
|
||||
(InSplitId == -1 || SplitId == InSplitId);
|
||||
}
|
||||
};
|
||||
|
||||
@ -117,4 +117,27 @@ private:
|
||||
bool ParseJsonObject(TSharedPtr<FJsonObject>& OutJsonObject) const;
|
||||
bool ValidateResponseType(const FString& ExpectedType) const;
|
||||
EDTFluxResponseStatus InitializeFromJson(const FString& JsonMessage, bool bLogErrors);
|
||||
|
||||
static FString GetJsonType(const EJson Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case EJson::None:
|
||||
return TEXT("None");
|
||||
case EJson::Null:
|
||||
return TEXT("Null");
|
||||
case EJson::String:
|
||||
return TEXT("String");
|
||||
case EJson::Number:
|
||||
return TEXT("Number");
|
||||
case EJson::Boolean:
|
||||
return TEXT("Boolean");
|
||||
case EJson::Array:
|
||||
return TEXT("Array");
|
||||
case EJson::Object:
|
||||
return TEXT("Object");
|
||||
default:
|
||||
return TEXT("Unknown");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -23,8 +23,9 @@ typedef TSharedPtr<FDTFluxHttpClient> FDTFluxHttpClientSP;
|
||||
|
||||
|
||||
// Delegates pour les requêtes avec callback
|
||||
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestResponse, const FGuid&, const FString&);
|
||||
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestTimeout, const FGuid&, const FString&);
|
||||
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestResponseError, const FGuid&, const FString&);
|
||||
DECLARE_DELEGATE_TwoParams(FOnDTFluxTrackedRequestResponse, const FGuid&, FDTFluxServerResponse&);
|
||||
DECLARE_DELEGATE_TwoParams(FOnDTFluxTrackedRequestTimeout, const FGuid&, const FString& /*ErrorMessage*/);
|
||||
// Delegates Blueprint pour les requêtes avec tracking
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestCompleted, const FGuid&, RequestId,
|
||||
EDTFluxApiDataType, RequestType, const FString&, ResponseData);
|
||||
@ -128,9 +129,14 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
|
||||
FGuid SendTrackedRequest(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1,
|
||||
int32 SplitId = -1, float TimeoutSeconds = 30.0f);
|
||||
|
||||
FGuid SendTrackedRequestWithCallback(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId,
|
||||
FOnDTFluxRequestResponse OnCompleted, FOnDTFluxRequestTimeout OnTimeout,
|
||||
FOnDTFluxTrackedRequestResponse OnCompleted,
|
||||
FOnDTFluxTrackedRequestTimeout OnTimeout,
|
||||
TOptional<FOnDTFluxRequestResponseError> OnError = TOptional<
|
||||
FOnDTFluxRequestResponseError>(),
|
||||
float TimeoutSeconds = 30.0f);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
|
||||
bool GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const;
|
||||
const FDTFluxQueuedRequest* GetTrackedRequestPtr(const FGuid& RequestId) const;
|
||||
@ -175,8 +181,9 @@ private:
|
||||
UDTFluxQueuedManager* QueueManager;
|
||||
|
||||
// === MAPPING DES CALLBACKS C++ ===
|
||||
TMap<FGuid, FOnDTFluxRequestResponse> PendingCallbacks;
|
||||
TMap<FGuid, FOnDTFluxRequestTimeout> PendingTimeoutCallbacks;
|
||||
TMap<FGuid, FOnDTFluxTrackedRequestResponse> PendingCallbacks;
|
||||
TMap<FGuid, FOnDTFluxTrackedRequestTimeout> PendingTimeoutCallbacks;
|
||||
TMap<FGuid, FOnDTFluxRequestResponseError> PendingErrorCallbacks;
|
||||
|
||||
// === CLIENTS RÉSEAU ===
|
||||
FDTFluxWebSocketClientSP WsClient = nullptr;
|
||||
@ -221,11 +228,12 @@ private:
|
||||
void Parse(FDTFluxServerResponse& Response);
|
||||
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
|
||||
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
|
||||
bool CleanRequestCallbacks(const FGuid& RequestId);
|
||||
|
||||
// === GESTION DES REQUÊTES TRACKÉES ===
|
||||
UFUNCTION()
|
||||
void OnRequestTimedOut_Internal(const FDTFluxQueuedRequest& TimedOutRequest);
|
||||
bool TryMatchResponseToQueuedRequest(const FDTFluxServerResponse& Response);
|
||||
bool TryMatchResponseToQueuedRequest(FDTFluxServerResponse& Response);
|
||||
void CompleteTrackedRequest(const FGuid& RequestId, const FString& ResponseData, EDTFluxRequestType RequestType);
|
||||
void FailTrackedRequest(const FGuid& RequestId, const FString& ErrorMessage, EDTFluxRequestType RequestType);
|
||||
void SendQueuedRequest(const FDTFluxQueuedRequest& QueuedRequest);
|
||||
|
||||
Reference in New Issue
Block a user