Files
DTFluxAPI/Source/DTFluxNetwork/Public/DTFluxQueuedManager.h

376 lines
11 KiB
C++

// ================================================================================================
// DTFluxRequestManager.h - Gestionnaire C++ optimisé avec cache, timeout et retry
// ================================================================================================
#pragma once
#include "CoreMinimal.h"
#include "Tickable.h"
#include "HAL/CriticalSection.h"
#include "Struct/DTFluxServerResponseStruct.h"
#include "Types/Enum/DTFluxCoreEnum.h"
#include "DTFluxQueuedManager.generated.h"
class FDTFluxAsyncParser;
// ================================================================================================
// ENUMS ET STRUCTURES POUR LES REQUÊTES
// ================================================================================================
UENUM(BlueprintType)
enum class EDTFluxRequestState : uint8
{
Pending UMETA(DisplayName = "Pending"),
Sent UMETA(DisplayName = "Sent"),
Completed UMETA(DisplayName = "Completed"),
Failed UMETA(DisplayName = "Failed"),
TimedOut UMETA(DisplayName = "TimedOut"),
Retrying UMETA(DisplayName = "Retrying")
};
USTRUCT(BlueprintType)
struct DTFLUXNETWORK_API FDTFluxRequestConfig
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float TimeoutSeconds = 5.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MaxRetries = 3;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float RetryBackoffMultiplier = 1.5f;
};
USTRUCT(BlueprintType)
struct DTFLUXNETWORK_API FDTFluxTrackedRequest
{
GENERATED_BODY()
// === IDENTIFICATION ===
UPROPERTY(BlueprintReadOnly)
FGuid RequestId = FGuid::NewGuid();
UPROPERTY(BlueprintReadOnly)
EDTFluxApiDataType RequestType = EDTFluxApiDataType::None;
UPROPERTY(BlueprintReadOnly)
int32 ContestId = -1;
UPROPERTY(BlueprintReadOnly)
int32 StageId = -1;
UPROPERTY(BlueprintReadOnly)
int32 SplitId = -1;
// === ÉTAT ET TIMING ===
UPROPERTY(BlueprintReadOnly)
EDTFluxRequestState State = EDTFluxRequestState::Pending;
UPROPERTY(BlueprintReadOnly)
FDateTime CreatedAt = FDateTime::Now();
UPROPERTY(BlueprintReadOnly)
FDateTime SentAt = FDateTime::MinValue();
UPROPERTY(BlueprintReadOnly)
FDateTime CompletedAt = FDateTime::MinValue();
UPROPERTY(BlueprintReadOnly)
FDateTime LastAttemptTime = FDateTime::Now();
// === CONFIGURATION ===
FDTFluxRequestConfig Config;
// === RETRY LOGIC ===
UPROPERTY(BlueprintReadOnly)
int32 CurrentRetries = 0;
// === DONNÉES DE RÉPONSE ===
UPROPERTY(BlueprintReadOnly)
FString RawResponseData;
// Réponse parsée (lazy loading)
mutable TOptional<TSharedPtr<FDTFluxServerResponse>> ParsedResponse;
UPROPERTY(BlueprintReadOnly)
bool bIsResponseParsed = false;
UPROPERTY(BlueprintReadOnly)
FString LastErrorMessage;
// === MÉTHODES UTILITAIRES ===
bool HasTimedOut() const;
bool CanRetry() const;
float GetRetryDelay() const;
bool Matches(EDTFluxApiDataType InType, int32 InContestId = -1, int32 InStageId = -1, int32 InSplitId = -1) const;
void SetRawResponse(const FString& RawData);
FString Serialize() const;
};
// ================================================================================================
// DELEGATES POUR LES CALLBACKS
// ================================================================================================
DECLARE_DELEGATE_OneParam(FOnDTFluxRequestSuccess, const FDTFluxTrackedRequest&);
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestError, const FDTFluxTrackedRequest&, const FString& /*ErrorMessage*/);
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnRequestStateChangedNative, const FGuid& /*RequestId*/,
EDTFluxRequestState& /*NewState*/);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnRequestCompletedNative, const FDTFluxTrackedRequest& /*CompletedRequest*/);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnRequestFailedNative, const FDTFluxTrackedRequest& /*FailedRequest*/);
// ================================================================================================
// REQUEST MANAGER - Classe C++ principale avec SmartPointers
// ================================================================================================
/**
* Gestionnaire de requêtes trackées timeout, retry et parsing asynchrone
* Implémentation C++ pure avec SmartPointers pour des performances optimales
*/
class DTFLUXNETWORK_API FDTFluxQueuedRequestManager : public FTickableGameObject
{
public:
FDTFluxQueuedRequestManager();
virtual ~FDTFluxQueuedRequestManager();
// === LIFECYCLE ===
/**
* Initialiser le gestionnaire de requêtes
* @param DefaultConfig Configuration par défaut pour les nouvelles requêtes
*/
void Initialize(const FDTFluxRequestConfig& DefaultConfig = FDTFluxRequestConfig());
/**
* Arrêter le gestionnaire et nettoyer toutes les ressources
*/
void Shutdown();
/**
* Vérifier si le gestionnaire est initialisé
*/
bool IsInitialized() const { return bIsInitialized.load(); }
// === CRÉATION DE REQUÊTES ===
/**
* Créer une nouvelle requête trackée
* @param RequestType Type de requête (ContestRanking, StageRanking, etc.)
* @param ContestId ID du contest (-1 si non applicable)
* @param StageId ID du stage (-1 si non applicable)
* @param SplitId ID du split (-1 si non applicable)
* @param CustomConfig Configuration spécifique pour cette requête
* @return GUID de la requête créée
*/
FGuid CreateTrackedRequest(
EDTFluxApiDataType RequestType,
int32 ContestId = -1,
int32 StageId = -1,
int32 SplitId = -1,
const FDTFluxRequestConfig& CustomConfig = FDTFluxRequestConfig()
);
/**
* Créer une requête trackée avec callbacks C++
* @param RequestType Type de requête
* @param ContestId ID du contest
* @param StageId ID du stage
* @param SplitId ID du split
* @param OnSuccess Callback appelé en cas de succès
* @param OnError Callback appelé en cas d'erreur
* @param CustomConfig Configuration spécifique
* @return GUID de la requête créée
*/
FGuid CreateTrackedRequestWithCallbacks(
EDTFluxApiDataType RequestType,
int32 ContestId,
int32 StageId,
int32 SplitId,
FOnDTFluxRequestSuccess OnSuccess,
FOnDTFluxRequestError OnError,
const FDTFluxRequestConfig& CustomConfig = FDTFluxRequestConfig()
);
// === GESTION DES REQUÊTES ===
/**
* Marquer une requête comme envoyée
*/
bool MarkRequestAsSent(const FGuid& RequestId);
/**
* Compléter une requête avec la réponse reçue
* @param RequestId ID de la requête
* @param RawResponseData Données JSON brutes de la réponse
* @param bUseAsyncParsing Utiliser le parsing asynchrone (recommandé)
*/
bool CompleteRequest(const FGuid& RequestId, const FString& RawResponseData, bool bUseAsyncParsing = true);
/**
* Marquer une requête comme échouée
*/
bool FailRequest(const FGuid& RequestId, const FString& ErrorMessage);
/**
* Relancer une requête (si retry possible)
*/
bool RetryRequest(const FGuid& RequestId);
// === RECHERCHE ===
/**
* Chercher une requête en attente correspondant aux critères
*/
bool FindPendingRequest(
FGuid& OutRequestId,
EDTFluxApiDataType RequestType,
int32 ContestId = -1,
int32 StageId = -1,
int32 SplitId = -1
) const;
// === ACCESSEURS ===
/**
* Récupérer une requête par son ID
*/
bool GetRequest(const FGuid& RequestId, FDTFluxTrackedRequest& OutRequest) const;
/**
* Récupérer un pointeur vers une requête (plus efficace)
*/
const FDTFluxTrackedRequest* GetRequestPtr(const FGuid& RequestId) const;
/**
* Récupérer toutes les requêtes dans un état donné
*/
TArray<FDTFluxTrackedRequest> GetRequestsByState(EDTFluxRequestState State) const;
/**
* Compter les requêtes dans un état donné
*/
int32 GetRequestCount(EDTFluxRequestState State = EDTFluxRequestState::Pending) const;
// === STATISTIQUES ===
/**
* Statistiques complètes du gestionnaire de requêtes
*/
struct FRequestStatistics
{
int32 Pending = 0;
int32 Completed = 0;
int32 Failed = 0;
int32 TotalRequests = 0;
};
FRequestStatistics GetStatistics() const;
// === NETTOYAGE ===
/**
* Nettoyer les requêtes terminées anciennes
* @param OlderThanSeconds Supprimer les requêtes plus anciennes que ce délai
* @return Nombre de requêtes supprimées
*/
int32 CleanupCompletedRequests(float OlderThanSeconds = 300.0f);
/**
* Vider toutes les requêtes
*/
void ClearAllRequests();
// === EVENTS ===
FOnRequestStateChangedNative OnRequestStateChanged;
FOnRequestCompletedNative OnRequestCompleted;
FOnRequestFailedNative OnRequestFailed;
// === INTERFACE TICKABLE ===
virtual void Tick(float DeltaTime) override;
virtual bool IsTickable() const override { return true; };
virtual TStatId GetStatId() const override
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FDTFluxQueuedRequestManager, STATGROUP_Tickables);
};
virtual bool IsTickableWhenPaused() const override { return true; }
virtual bool IsTickableInEditor() const override { return true; }
// === ACCESSEUR POUR LE PARSER (debug/stats) ===
const FDTFluxAsyncParser* GetAsyncParser() const { return AsyncParser.Get(); }
private:
// === CONFIGURATION ===
FDTFluxRequestConfig DefaultConfig;
std::atomic<bool> bIsInitialized{false};
// === TIMING POUR LE TICK ===
float TimeSinceLastTimeoutCheck = 0.0f;
float TimeSinceLastRetryCheck = 0.0f;
static constexpr float TimeoutCheckInterval = 1.0f;
static constexpr float RetryCheckInterval = 0.5f;
// === STOCKAGE THREAD-SAFE ===
mutable FCriticalSection RequestsLock;
TMap<FGuid, TSharedPtr<FDTFluxTrackedRequest>> AllRequests;
// === CALLBACKS C++ ===
mutable FCriticalSection CallbacksLock;
TMap<FGuid, FOnDTFluxRequestSuccess> SuccessCallbacks;
TMap<FGuid, FOnDTFluxRequestError> ErrorCallbacks;
// === MÉTRIQUES ===
mutable FCriticalSection MetricsLock;
mutable int32 TotalRequests = 0;
// === PARSER ASYNCHRONE ===
TUniquePtr<FDTFluxAsyncParser> AsyncParser;
// === MÉTHODES PRIVÉES ===
/**
* Changer l'état d'une requête et notifier les observers
*/
void ChangeRequestState(TSharedPtr<FDTFluxTrackedRequest> Request, EDTFluxRequestState NewState);
/**
* Traiter les requêtes en timeout (appelé périodiquement)
*/
void ProcessTimeouts();
/**
* Traiter les requêtes à relancer (appelé périodiquement)
*/
void ProcessRetries();
/**
* Déclencher les callbacks pour une requête
*/
void TriggerCallbacks(const FDTFluxTrackedRequest& Request);
/**
* Nettoyer les callbacks d'une requête
*/
void CleanupCallbacks(const FGuid& RequestId);
// === CALLBACKS POUR LE PARSING ASYNCHRONE ===
/**
* Callback appelé quand le parsing asynchrone réussit
*/
void OnParsingCompleted(const FGuid& RequestId, TSharedPtr<FDTFluxServerResponse> ParsedResponse, bool bSuccess);
/**
* Callback appelé quand le parsing asynchrone échoue
*/
void OnParsingFailed(const FGuid& RequestId, const FString& ErrorMessage);
};