// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "UObject/Object.h" #include "Containers/Queue.h" #include "Tickable.h" #include "Struct/DTFluxRequestStructs.h" #include "Struct/DTFluxServerResponseStruct.h" #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); /** * @brief Classe Tickable gérant les requêtes WebSockets qui ne sont pas traçables nativement par l'API. * Cette classe utilise TQueue pour gérer efficacement les requêtes en attente et vérifie leur état dans le tick. */ UCLASS() class DTFLUXNETWORK_API UDTFluxQueuedManager : public UObject, public FTickableGameObject { GENERATED_BODY() public: /** Constructeur par défaut */ UDTFluxQueuedManager(); virtual ~UDTFluxQueuedManager() override; void Initialize(); FGuid QueueRequest(EDTFluxRequestType RequestType, int32 ContestId = -1, int32 StageId = -1, int32 SplitId = -1, const FString& RawMessage = ""); bool MarkRequestAsResponded(const FGuid& TargetRequestGuid); bool MarkRequestAsResponded(const FDTFluxQueuedRequest& TargetRequest); bool IsRequestPending(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); int32 GetPendingRequestCount(); int32 CleanupTimedOutRequests(); int32 CleanCashedRequests(); void ClearAllRequests(); // bool TryProcessResponse(const FDTFluxServerResponse& Response); // Interface FTickableGameObject virtual void Tick(float DeltaTime) override; virtual bool IsTickable() const override; virtual TStatId GetStatId() const override; virtual bool IsTickableWhenPaused() const override { return true; } virtual bool IsTickableInEditor() const override { return true; } // Interface ~FTickableGameObject UPROPERTY(BlueprintAssignable, Category = "DTFlux|Network") FOnRequestTimedOut OnRequestTimedOut; private: TQueue PendingRequestsQueue; TQueue CompletedRequestsQueue; TQueue TimedOutRequestsQueue; bool bIsInitialized; float CheckInterval; float TimeSinceLastCheck; };