From f1d583926b417ea251914bdd25bc3e6efb5c2acc Mon Sep 17 00:00:00 2001 From: Ange-Marie MAURIN Date: Sat, 12 Jul 2025 16:07:37 +0200 Subject: [PATCH] Removed CachedRequest functionality + Fixed(Tested) PursuitSequence bug --- .../Private/DTFluxCoreSubsystem.cpp | 14 +- .../Private/DTFluxPursuitManager.cpp | 189 ++++++++++---- .../Public/DTFluxCoreSubsystem.h | 16 +- .../Public/DTFluxPursuitManager.h | 4 + .../Private/DTFluxQueuedManager.cpp | 240 ++---------------- .../Subsystems/DTFluxNetworkSubsystem.cpp | 44 +--- .../Public/DTFluxQueuedManager.h | 75 +----- .../Subsystems/DTFluxNetworkSubsystem.h | 8 +- 8 files changed, 190 insertions(+), 400 deletions(-) diff --git a/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp b/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp index a902fbb..4238f88 100644 --- a/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp +++ b/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp @@ -364,7 +364,7 @@ bool UDTFluxCoreSubsystem::GetSplitRankingsWithKey(const FDTFluxSplitKey SplitKe } } -TArray UDTFluxCoreSubsystem::TrackedRequestContestRankings(const TArray ForContests) +TArray UDTFluxCoreSubsystem::TrackedRequestContestRankings(const TArray ForContests, bool bEnableCache) { if (NetworkSubsystem) { @@ -390,7 +390,7 @@ TArray UDTFluxCoreSubsystem::TrackedRequestContestRankings(const TArraySendTrackedRequestWithCallbacks(EDTFluxApiDataType::ContestRanking, - ContestId, -1, -1, OnSuccess, OnError); + ContestId, -1, -1, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; @@ -398,7 +398,8 @@ TArray UDTFluxCoreSubsystem::TrackedRequestContestRankings(const TArray(); } -TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArray ForStages) +TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArray ForStages, + bool bEnableCache) { if (NetworkSubsystem) { @@ -424,7 +425,7 @@ TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArraySendTrackedRequestWithCallbacks(EDTFluxApiDataType::StageRanking, - StageKey.ContestId, StageKey.StageId, -1, OnSuccess, OnError); + StageKey.ContestId, StageKey.StageId, -1, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; @@ -432,7 +433,8 @@ TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArray(); } -TArray UDTFluxCoreSubsystem::TrackedRequestSplitRankings(const TArray ForSplits) +TArray UDTFluxCoreSubsystem::TrackedRequestSplitRankings(const TArray ForSplits, + bool bEnableCache) { if (NetworkSubsystem) { @@ -458,7 +460,7 @@ TArray UDTFluxCoreSubsystem::TrackedRequestSplitRankings(const TArraySendTrackedRequestWithCallbacks(EDTFluxApiDataType::SplitRanking, - SplitKey.ContestId, SplitKey.StageId, SplitKey.SplitId, OnSuccess, OnError); + SplitKey.ContestId, SplitKey.StageId, SplitKey.SplitId, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; diff --git a/Source/DTFluxCoreSubsystem/Private/DTFluxPursuitManager.cpp b/Source/DTFluxCoreSubsystem/Private/DTFluxPursuitManager.cpp index 38cb758..3df9da9 100644 --- a/Source/DTFluxCoreSubsystem/Private/DTFluxPursuitManager.cpp +++ b/Source/DTFluxCoreSubsystem/Private/DTFluxPursuitManager.cpp @@ -45,61 +45,136 @@ void UDTFluxPursuitManager::SetPursuitInfoIsMassStart(FDTFluxPursuitGroup NextFo } } +void UDTFluxPursuitManager::DebugFocusNext(const TArray& OutPursuitFocusNext) +{ + FString FocusBibs; + for (const auto& Pursuit : OutPursuitFocusNext) + { + FocusBibs += FString::Printf(TEXT("%d "), Pursuit.Bib); + } + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Focus Bibs: %s"), *FocusBibs); +} + +void UDTFluxPursuitManager::DebugOutPoursuitNext(const TArray& OutPursuitNext) +{ + FString NextBibs; + for (int32 i = 0; i < OutPursuitNext.Num(); i++) + { + NextBibs += FString::Printf(TEXT("%d "), OutPursuitNext[i].Bib); + } + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Next Bibs: %s"), *NextBibs); +} + void UDTFluxPursuitManager::GetPursuit(TArray& OutPursuitFocusNext, TArray& OutPursuitNext, bool& BIsFocusTruncate, const int MaxSimultaneousPursuit) { + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("=== GetPursuit CALLED ===")); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("MaxSimultaneousPursuit: %d"), MaxSimultaneousPursuit); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Available groups: %d"), GroupedPursuit.Num()); + + // Validation if (MaxSimultaneousPursuit <= 0) { - UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("MaxSimultaneousPursuit must be > 0")); - OutPursuitFocusNext = TArray(); - OutPursuitNext = TArray(); + UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Invalid MaxSimultaneousPursuit: %d"), MaxSimultaneousPursuit); + OutPursuitFocusNext.Reset(); + OutPursuitNext.Reset(); BIsFocusTruncate = false; return; } - if (bIsSequenceDone && MaxSimultaneousPursuit <= 0) + + if (bIsSequenceDone || GroupedPursuit.IsEmpty()) { - OutPursuitFocusNext = TArray(); - OutPursuitNext = TArray(); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("No groups available or sequence completed")); + OutPursuitFocusNext.Reset(); + OutPursuitNext.Reset(); BIsFocusTruncate = false; return; } + OutPursuitFocusNext.Reset(); OutPursuitNext.Reset(); - if (!GroupedPursuit.IsEmpty()) + + // === ÉTAPE 1: FOCUS = PREMIER GROUPE (et le supprimer) === + FDTFluxPursuitGroup FocusGroup = GroupedPursuit[0]; // Copie du premier groupe + GroupedPursuit.RemoveAt(0); // ✅ SUPPRIMER le premier groupe + + SetPursuitInfoIsMassStart(FocusGroup); + OutPursuitFocusNext = FocusGroup.PursuitGroup; + BIsFocusTruncate = FocusGroup.PursuitGroup.Num() > 1; + + UE_LOG(logDTFluxCoreSubsystem, Warning, + TEXT("Focus Group: StartTime=%s, Participants=%d"), + *FocusGroup.StartTimeGlobal.ToString(), + FocusGroup.PursuitGroup.Num()); + + // === ÉTAPE 2: NEXT = GROUPES SUIVANTS (SANS les supprimer) === + int32 TargetNextCount = MaxSimultaneousPursuit - 1; // -1 pour le focus + int32 AddedNextCount = 0; + + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Target Next Count: %d"), TargetNextCount); + + // ✅ PARCOURIR les groupes restants SANS les modifier + for (int32 GroupIndex = 0; + GroupIndex < GroupedPursuit.Num() && AddedNextCount < TargetNextCount; + GroupIndex++) { - FDTFluxPursuitGroup NextFocusGroup = GroupedPursuit[0]; - GroupedPursuit.RemoveAt(0); - SetPursuitInfoIsMassStart(NextFocusGroup); - OutPursuitFocusNext = NextFocusGroup.PursuitGroup; - bFocusIsTruncate = NextFocusGroup.PursuitGroup.Num() > 1; - for (int RemainingPursuitNum = MaxSimultaneousPursuit - 1; RemainingPursuitNum != 0;) + FDTFluxPursuitGroup& NextGroup = GroupedPursuit[GroupIndex]; // Référence (pour SetPursuitInfoIsMassStart) + + if (NextGroup.PursuitGroup.Num() == 0) { - if (!GroupedPursuit.IsEmpty()) - { - FDTFluxPursuitGroup NextGroup = GroupedPursuit[0]; - SetPursuitInfoIsMassStart(NextGroup); - if (NextGroup.PursuitGroup.Num() >= RemainingPursuitNum) - { - // extract the number we need - for (int i = 0; i < RemainingPursuitNum; i++) - { - FDTFluxPursuitInfo Pursuit = NextGroup.PursuitGroup[0]; - OutPursuitNext.Add(Pursuit); - } - break; - } - else - { - OutPursuitNext.Append(NextGroup.PursuitGroup); - RemainingPursuitNum -= NextGroup.PursuitGroup.Num(); - } - } - else - { - break; - } + continue; // Groupe vide } + + int32 AvailableInGroup = NextGroup.PursuitGroup.Num(); + int32 NeededFromGroup = FMath::Min(TargetNextCount - AddedNextCount, AvailableInGroup); + + UE_LOG(logDTFluxCoreSubsystem, Warning, + TEXT("Processing Next Group %d: StartTime=%s, Available=%d, Taking=%d"), + GroupIndex, + *NextGroup.StartTimeGlobal.ToString(), + AvailableInGroup, + NeededFromGroup); + + // ✅ COPIER les participants nécessaires (SANS les supprimer du groupe) + for (int32 ParticipantIndex = 0; ParticipantIndex < NeededFromGroup; ParticipantIndex++) + { + FDTFluxPursuitInfo NextParticipant = NextGroup.PursuitGroup[ParticipantIndex]; // Copie + + // Appliquer MassStart + NextParticipant.bIsMassStart = NextParticipant.StartTime >= MassStartTime; + + OutPursuitNext.Add(NextParticipant); + AddedNextCount++; + + UE_LOG(logDTFluxCoreSubsystem, VeryVerbose, + TEXT("Added to Next: Bib %d from Group %d"), + NextParticipant.Bib, GroupIndex); + } + } + + // === LOGS DE RÉSUMÉ === + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("=== PURSUIT RESULTS ===")); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Focus: %d participants"), OutPursuitFocusNext.Num()); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Next: %d participants"), OutPursuitNext.Num()); + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Remaining groups for future: %d"), GroupedPursuit.Num()); + + if (OutPursuitFocusNext.Num() > 0) + { + DebugFocusNext(OutPursuitFocusNext); + } + + // Log détaillé des Next (limité pour éviter spam) + if (OutPursuitNext.Num() > 0) + { + DebugOutPoursuitNext(OutPursuitNext); + } + + // Vérifier si la séquence est terminée + if (GroupedPursuit.IsEmpty()) + { + bIsSequenceDone = true; + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Pursuit sequence will be completed after this round")); } } @@ -119,7 +194,7 @@ bool UDTFluxPursuitManager::BindRankings() { if (!bIsRankingBounded) { - CoreSubsystem->OnRequestedStageRankings.AddDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived); + CoreSubsystem->OnStageRankings.AddDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived); bIsRankingBounded = true; } return bIsRankingBounded; @@ -134,7 +209,7 @@ void UDTFluxPursuitManager::UnbindRankings() { if (bIsRankingBounded) { - CoreSubsystem->OnRequestedStageRankings.RemoveDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived); + CoreSubsystem->OnStageRankings.RemoveDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived); bIsRankingBounded = false; return; } @@ -178,18 +253,30 @@ bool UDTFluxPursuitManager::LaunchPursuitSequence() AllPursuits.Add(PursuitInfo); } } + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("AllPursuits.Num() = %i"), AllPursuits.Num()); for (auto& Pursuit : AllPursuits) { if (TempGroups.Contains(Pursuit.StartTime)) { - TempGroups[Pursuit.StartTime].PursuitGroup.Add(Pursuit); + FDTFluxPursuitGroup& Group = TempGroups[Pursuit.StartTime]; + Group.PursuitGroup.Add(Pursuit); + UE_LOG(logDTFluxCoreSubsystem, Warning, + TEXT("Adding [%i] To PursuitGroup starting At %s, PursuitGroup.Num() %i"), + Pursuit.Bib, *Pursuit.StartTime.ToString(), Group.PursuitGroup.Num()); } else { - FDTFluxPursuitGroup Group; - Group.StartTimeGlobal = Pursuit.StartTime; - Group.PursuitGroup.Add(Pursuit); - TempGroups.Add(Pursuit.StartTime, Group); + FDTFluxPursuitGroup NewGroup; + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("New Group starting At %s, Adding Bib [%i]"), + *Pursuit.StartTime.ToString(), Pursuit.Bib); + NewGroup.StartTimeGlobal = Pursuit.StartTime; + NewGroup.PursuitGroup.Add(Pursuit); + TempGroups.Add(Pursuit.StartTime, NewGroup); + for (const auto& Group : TempGroups) + { + UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Group.StartTime = %s, Group.PursuitGroup.Num() = %i"), + *Group.Key.ToString(), Group.Value.PursuitGroup.Num()); + } } } TempGroups.KeySort([](const FDateTime& A, const FDateTime& B) @@ -199,18 +286,18 @@ bool UDTFluxPursuitManager::LaunchPursuitSequence() TMap StartTimeFrequency; int32 MaxFrequency = 0; GroupedPursuit.Reserve(TempGroups.Num()); + // parcours du TMap for (const auto& Pair : TempGroups) { if (Pair.Value.StartTimeGlobal != FDateTime::MinValue() && Pair.Value.StartTimeGlobal != FDateTime::MaxValue()) { - StartTimeFrequency.FindOrAdd(Pair.Value.StartTimeGlobal)++; - const FDateTime& PropertyValue = Pair.Value.StartTimeGlobal; // Votre propriété - int32& Count = StartTimeFrequency.FindOrAdd(PropertyValue, 0); - Count++; - if (Count > MaxFrequency) + // récuperation de la ref de la valeur actuel de la fréquence dans la TMap Freq + int& CurrentFreq = StartTimeFrequency.FindOrAdd(Pair.Value.StartTimeGlobal, 0); + CurrentFreq = Pair.Value.PursuitGroup.Num(); + if (CurrentFreq > MaxFrequency) { - MaxFrequency = Count; - MassStartTime = PropertyValue; + MaxFrequency = CurrentFreq; + MassStartTime = Pair.Value.StartTimeGlobal; } } GroupedPursuit.Add(Pair.Value); diff --git a/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h b/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h index 5d25c8d..9557d74 100644 --- a/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h +++ b/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h @@ -54,12 +54,8 @@ public: UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") FOnTeamStatusUpdate OnTeamStatusUpdate; - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnRequestedStageRankings, const FDTFluxStageKey, StageKey, - const FDTFluxStageRankings, StageRankings); - - UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") - FOnRequestedStageRankings OnRequestedStageRankings; - + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Core Subsystem") + UDTFluxPursuitManager* PursuitManager = nullptr; UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") bool GetContestRankings(const int ContestId, FDTFluxContestRankings& OutContestRankings); @@ -80,16 +76,14 @@ public: const bool bShouldUseCached = true); UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") - TArray TrackedRequestContestRankings(const TArray ForContests); + TArray TrackedRequestContestRankings(const TArray ForContests, bool bEnableCache = true); UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") - TArray TrackedRequestStageRankings(const TArray ForStages); + TArray TrackedRequestStageRankings(const TArray ForStages, bool bEnableCache = true); UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") - TArray TrackedRequestSplitRankings(const TArray ForSplits); + TArray TrackedRequestSplitRankings(const TArray ForSplits, bool bEnableCache = true); - UPROPERTY(BlueprintReadOnly, Category="DTFlux|Core Subsystem") - UDTFluxPursuitManager* PursuitManager = nullptr; UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") const FDTFluxParticipant GetParticipant(int InBib); diff --git a/Source/DTFluxCoreSubsystem/Public/DTFluxPursuitManager.h b/Source/DTFluxCoreSubsystem/Public/DTFluxPursuitManager.h index 28d9339..b01ed4a 100644 --- a/Source/DTFluxCoreSubsystem/Public/DTFluxPursuitManager.h +++ b/Source/DTFluxCoreSubsystem/Public/DTFluxPursuitManager.h @@ -108,6 +108,10 @@ public: UFUNCTION() void OnRankingsReceived(const FDTFluxStageKey NewStageKey, const FDTFluxStageRankings NewStageRankings); + + void DebugFocusNext(const TArray& OutPursuitFocusNext); + void DebugOutPoursuitNext(const TArray& OutPursuitNext); + private: TMap PendingStageRanking; TArray AllRankings; diff --git a/Source/DTFluxNetwork/Private/DTFluxQueuedManager.cpp b/Source/DTFluxNetwork/Private/DTFluxQueuedManager.cpp index 2217f11..bdb9bff 100644 --- a/Source/DTFluxNetwork/Private/DTFluxQueuedManager.cpp +++ b/Source/DTFluxNetwork/Private/DTFluxQueuedManager.cpp @@ -23,11 +23,6 @@ bool FDTFluxTrackedRequest::CanRetry() const (State == EDTFluxRequestState::Failed || State == EDTFluxRequestState::TimedOut); } -bool FDTFluxTrackedRequest::IsCacheValid() const -{ - if (State != EDTFluxRequestState::Cached) return false; - return (FDateTime::Now() - CompletedAt).GetTotalSeconds() < Config.CacheValiditySeconds; -} float FDTFluxTrackedRequest::GetRetryDelay() const { @@ -40,11 +35,6 @@ bool FDTFluxTrackedRequest::Matches(EDTFluxApiDataType InType, int32 InContestId return RequestType == InType && ContestId == InContestId && StageId == InStageId && SplitId == InSplitId; } -FString FDTFluxTrackedRequest::GetCacheKey() const -{ - return FString::Printf(TEXT("%s_%d_%d_%d"), - *UEnum::GetValueAsString(RequestType), ContestId, StageId, SplitId); -} void FDTFluxTrackedRequest::SetRawResponse(const FString& RawData) { @@ -118,8 +108,8 @@ void FDTFluxQueuedRequestManager::Initialize(const FDTFluxRequestConfig& InDefau DefaultConfig = InDefaultConfig; bIsInitialized.store(true); - UE_LOG(logDTFluxNetwork, Log, TEXT("RequestManager initialized with timeout=%.1fs, cache=%.1fs"), - DefaultConfig.TimeoutSeconds, DefaultConfig.CacheValiditySeconds); + UE_LOG(logDTFluxNetwork, Log, TEXT("RequestManager initialized with timeout=%.1fs"), + DefaultConfig.TimeoutSeconds); } void FDTFluxQueuedRequestManager::Shutdown() @@ -134,7 +124,6 @@ void FDTFluxQueuedRequestManager::Shutdown() FScopeLock CallbacksLock_Local(&CallbacksLock); AllRequests.Empty(); - CacheKeyToRequestId.Empty(); SuccessCallbacks.Empty(); ErrorCallbacks.Empty(); } @@ -154,37 +143,7 @@ FGuid FDTFluxQueuedRequestManager::CreateTrackedRequest( UE_LOG(logDTFluxNetwork, Error, TEXT("RequestManager not initialized")); return FGuid(); } - - // Vérifier le cache d'abord - FString CachedResponse; - if (CustomConfig.bEnableCache && GetFromCache(RequestType, CachedResponse, ContestId, StageId, SplitId)) - { - UE_LOG(logDTFluxNetwork, Log, TEXT("Request served from cache: Type=%s"), - *UEnum::GetValueAsString(RequestType)); - - // Créer une "fausse" requête pour représenter le hit cache - auto CachedRequest = MakeShared(); - CachedRequest->RequestType = RequestType; - CachedRequest->ContestId = ContestId; - CachedRequest->StageId = StageId; - CachedRequest->SplitId = SplitId; - CachedRequest->Config = CustomConfig.bEnableCache ? CustomConfig : DefaultConfig; - CachedRequest->State = EDTFluxRequestState::Cached; - CachedRequest->RawResponseData = CachedResponse; - CachedRequest->CompletedAt = FDateTime::Now(); - - FGuid CacheRequestId = CachedRequest->RequestId; - - { - FScopeLock Lock(&RequestsLock); - AllRequests.Add(CacheRequestId, CachedRequest); - } - - RecordCacheHit(); - return CacheRequestId; - } - - // Créer une nouvelle requête + // Create new request auto NewRequest = MakeShared(); NewRequest->RequestType = RequestType; NewRequest->ContestId = ContestId; @@ -199,12 +158,8 @@ FGuid FDTFluxQueuedRequestManager::CreateTrackedRequest( AllRequests.Add(RequestId, NewRequest); TotalRequests++; } - - RecordCacheMiss(); - UE_LOG(logDTFluxNetwork, Log, TEXT("Created tracked request %s: Type=%s, Contest=%d, Stage=%d, Split=%d"), *RequestId.ToString(), *UEnum::GetValueAsString(RequestType), ContestId, StageId, SplitId); - return RequestId; } @@ -257,7 +212,6 @@ bool FDTFluxQueuedRequestManager::CompleteRequest(const FGuid& RequestId, const { UE_LOG(logDTFluxNetwork, Log, TEXT("FDTFluxQueuedRequestManager::CompleteRequest() %s"), *RequestId.ToString()); TSharedPtr Request; - { FScopeLock Lock(&RequestsLock); if (TSharedPtr* RequestPtr = AllRequests.Find(RequestId)) @@ -265,19 +219,18 @@ bool FDTFluxQueuedRequestManager::CompleteRequest(const FGuid& RequestId, const Request = *RequestPtr; } } - if (!Request.IsValid()) { UE_LOG(logDTFluxNetwork, Warning, TEXT("Request %s not found"), *RequestId.ToString()); return false; } - // Stocker la réponse brute + // Store RawResponse Request->SetRawResponse(RawResponseData); Request->CompletedAt = FDateTime::Now(); UE_LOG(logDTFluxNetwork, Log, TEXT("Request %s completed at %s"), *RequestId.ToString(), *Request->CompletedAt.ToString()); - // Décider du parsing selon les callbacks et la configuration + // Decide to parse based upon config bool bHasCallbacks = false; { FScopeLock Lock(&CallbacksLock); @@ -292,7 +245,7 @@ bool FDTFluxQueuedRequestManager::CompleteRequest(const FGuid& RequestId, const bHasCallbacks ? TEXT("true") : TEXT("false"), bUseAsyncParsing ? TEXT("true") : TEXT("false"), RawResponseData.IsEmpty() ? TEXT("true") : TEXT("false")); - // Parsing asynchrone pour les callbacks + // Async parsing for Cb FOnParsingCompleted OnCompleted = FOnParsingCompleted::CreateRaw( this, &FDTFluxQueuedRequestManager::OnParsingCompleted ); @@ -300,9 +253,8 @@ bool FDTFluxQueuedRequestManager::CompleteRequest(const FGuid& RequestId, const FOnParsingFailed OnFailed = FOnParsingFailed::CreateRaw( this, &FDTFluxQueuedRequestManager::OnParsingFailed ); - + // Maybe send to parser in another place AsyncParser->ParseResponseAsync(RequestId, RawResponseData, OnCompleted, OnFailed); - // CleanupCallbacks(RequestId); UE_LOG(logDTFluxNetwork, Verbose, TEXT("Started async parsing for request %s"), *RequestId.ToString()); return true; } @@ -310,26 +262,21 @@ bool FDTFluxQueuedRequestManager::CompleteRequest(const FGuid& RequestId, const { UE_LOG(logDTFluxNetwork, Warning, TEXT("request %s completed without sync"), *RequestId.ToString()); // Compléter immédiatement sans parsing ou avec parsing sync - EDTFluxRequestState NewState = Request->Config.bEnableCache - ? EDTFluxRequestState::Cached - : EDTFluxRequestState::Completed; - + EDTFluxRequestState NewState = EDTFluxRequestState::Completed; ChangeRequestState(Request, NewState); - - if (Request->Config.bEnableCache) - { - FScopeLock Lock(&RequestsLock); - CacheKeyToRequestId.Add(Request->GetCacheKey(), RequestId); - } - // Déclencher les callbacks avec les données brutes TriggerCallbacks(*Request); CleanupCallbacks(RequestId); - return true; } } +/** + * @todo Check protocol errors ??? + * @param RequestId + * @param ErrorMessage + * @return + */ bool FDTFluxQueuedRequestManager::FailRequest(const FGuid& RequestId, const FString& ErrorMessage) { TSharedPtr Request; @@ -350,7 +297,6 @@ bool FDTFluxQueuedRequestManager::FailRequest(const FGuid& RequestId, const FStr Request->LastErrorMessage = ErrorMessage; ChangeRequestState(Request, EDTFluxRequestState::Failed); - // Déclencher les callbacks d'erreur TriggerCallbacks(*Request); CleanupCallbacks(RequestId); @@ -407,76 +353,6 @@ bool FDTFluxQueuedRequestManager::FindPendingRequest( return false; } -bool FDTFluxQueuedRequestManager::GetFromCache( - EDTFluxApiDataType RequestType, - FString& OutRawResponse, - int32 ContestId, - int32 StageId, - int32 SplitId) const -{ - FString CacheKey = GenerateCacheKey(RequestType, ContestId, StageId, SplitId); - - FScopeLock Lock(&RequestsLock); - - if (const FGuid* RequestId = CacheKeyToRequestId.Find(CacheKey)) - { - if (const TSharedPtr* RequestPtr = AllRequests.Find(*RequestId)) - { - const TSharedPtr& CachedRequest = *RequestPtr; - - if (CachedRequest->IsCacheValid() && !CachedRequest->RawResponseData.IsEmpty()) - { - OutRawResponse = CachedRequest->RawResponseData; - return true; - } - } - } - - return false; -} - -bool FDTFluxQueuedRequestManager::GetParsedFromCache( - EDTFluxApiDataType RequestType, - TSharedPtr& OutResponse, - int32 ContestId, - int32 StageId, - int32 SplitId) const -{ - FString CacheKey = GenerateCacheKey(RequestType, ContestId, StageId, SplitId); - - FScopeLock Lock(&RequestsLock); - - if (const FGuid* RequestId = CacheKeyToRequestId.Find(CacheKey)) - { - if (const TSharedPtr* RequestPtr = AllRequests.Find(*RequestId)) - { - const TSharedPtr& CachedRequest = *RequestPtr; - - if (CachedRequest->IsCacheValid()) - { - // Parsing lazy si nécessaire - if (!CachedRequest->ParsedResponse.IsSet() && !CachedRequest->RawResponseData.IsEmpty()) - { - OutResponse = AsyncParser->ParseResponseSync(CachedRequest->RawResponseData, 1.0f); - if (OutResponse.IsValid()) - { - CachedRequest->ParsedResponse = OutResponse; - const_cast(CachedRequest.Get())->bIsResponseParsed = true; - } - } - else if (CachedRequest->ParsedResponse.IsSet()) - { - OutResponse = CachedRequest->ParsedResponse.GetValue(); - } - - return OutResponse.IsValid(); - } - } - } - - return false; -} - // === ACCESSEURS === bool FDTFluxQueuedRequestManager::GetRequest(const FGuid& RequestId, FDTFluxTrackedRequest& OutRequest) const @@ -554,9 +430,6 @@ FDTFluxQueuedRequestManager::FRequestStatistics FDTFluxQueuedRequestManager::Get case EDTFluxRequestState::Retrying: Stats.Pending++; break; - case EDTFluxRequestState::Cached: - Stats.Cached++; - break; case EDTFluxRequestState::Completed: Stats.Completed++; break; @@ -568,46 +441,10 @@ FDTFluxQueuedRequestManager::FRequestStatistics FDTFluxQueuedRequestManager::Get } Stats.TotalRequests = TotalRequests; - Stats.CacheHits = CacheHits; - Stats.CacheMisses = CacheMisses; - - if (Stats.TotalRequests > 0) - { - Stats.HitRate = ((float)Stats.CacheHits / (float)Stats.TotalRequests) * 100.0f; - } - return Stats; } // === NETTOYAGE === - -int32 FDTFluxQueuedRequestManager::CleanupExpiredCache() -{ - FScopeLock Lock(&RequestsLock); - - TArray ExpiredRequests; - - for (const auto& [RequestId, Request] : AllRequests) - { - if (Request->State == EDTFluxRequestState::Cached && !Request->IsCacheValid()) - { - ExpiredRequests.Add(RequestId); - } - } - - for (const FGuid& RequestId : ExpiredRequests) - { - if (TSharedPtr* RequestPtr = AllRequests.Find(RequestId)) - { - const TSharedPtr& Request = *RequestPtr; - CacheKeyToRequestId.Remove(Request->GetCacheKey()); - AllRequests.Remove(RequestId); - } - } - - return ExpiredRequests.Num(); -} - int32 FDTFluxQueuedRequestManager::CleanupCompletedRequests(float OlderThanSeconds) { FScopeLock Lock(&RequestsLock); @@ -638,7 +475,6 @@ void FDTFluxQueuedRequestManager::ClearAllRequests() FScopeLock CallbacksLock_Local(&CallbacksLock); AllRequests.Empty(); - CacheKeyToRequestId.Empty(); SuccessCallbacks.Empty(); ErrorCallbacks.Empty(); @@ -652,7 +488,6 @@ void FDTFluxQueuedRequestManager::Tick(float DeltaTime) // Mise à jour des timers TimeSinceLastTimeoutCheck += DeltaTime; - TimeSinceLastCacheCleanup += DeltaTime; TimeSinceLastRetryCheck += DeltaTime; // Vérifier les timeouts @@ -668,13 +503,6 @@ void FDTFluxQueuedRequestManager::Tick(float DeltaTime) ProcessRetries(); TimeSinceLastRetryCheck = 0.0f; } - - // Nettoyage du cache - if (TimeSinceLastCacheCleanup >= CacheCleanupInterval) - { - ProcessCacheCleanup(); - TimeSinceLastCacheCleanup = 0.0f; - } } void FDTFluxQueuedRequestManager::ChangeRequestState(TSharedPtr Request, @@ -756,17 +584,11 @@ void FDTFluxQueuedRequestManager::ProcessRetries() } } -void FDTFluxQueuedRequestManager::ProcessCacheCleanup() -{ - CleanupExpiredCache(); - CleanupCompletedRequests(600.0f); -} - void FDTFluxQueuedRequestManager::TriggerCallbacks(const FDTFluxTrackedRequest& Request) { FScopeLock Lock(&CallbacksLock); - if (Request.State == EDTFluxRequestState::Completed || Request.State == EDTFluxRequestState::Cached) + if (Request.State == EDTFluxRequestState::Completed) { // Success Cb const FOnDTFluxRequestSuccess* SuccessCallback = SuccessCallbacks.Find(Request.RequestId); @@ -793,18 +615,6 @@ void FDTFluxQueuedRequestManager::CleanupCallbacks(const FGuid& RequestId) ErrorCallbacks.Remove(RequestId); } -void FDTFluxQueuedRequestManager::RecordCacheHit() const -{ - FScopeLock Lock(&MetricsLock); - CacheHits++; -} - -void FDTFluxQueuedRequestManager::RecordCacheMiss() const -{ - FScopeLock Lock(&MetricsLock); - CacheMisses++; -} - void FDTFluxQueuedRequestManager::OnParsingCompleted(const FGuid& RequestId, TSharedPtr ParsedResponse, bool bSuccess) { @@ -833,16 +643,9 @@ void FDTFluxQueuedRequestManager::OnParsingCompleted(const FGuid& RequestId, { Request->ParsedResponse = ParsedResponse; Request->bIsResponseParsed = true; - EDTFluxRequestState NewState = Request->Config.bEnableCache - ? EDTFluxRequestState::Cached - : EDTFluxRequestState::Completed; + EDTFluxRequestState NewState = EDTFluxRequestState::Completed; ChangeRequestState(Request, NewState); - if (Request->Config.bEnableCache) - { - FScopeLock Lock(&RequestsLock); - CacheKeyToRequestId.Add(Request->GetCacheKey(), RequestId); - } UE_LOG(logDTFluxNetwork, Log, TEXT("DTFluxQueuedRequestManager: Async parsing completed for request %s"), *RequestId.ToString()); @@ -854,7 +657,6 @@ void FDTFluxQueuedRequestManager::OnParsingCompleted(const FGuid& RequestId, UE_LOG(logDTFluxNetwork, Error, TEXT("Async parsing failed for request %s"), *RequestId.ToString()); } - // ✅ FIX: Déclencher les callbacks maintenant ! TriggerCallbacks(*Request); CleanupCallbacks(RequestId); } @@ -866,13 +668,3 @@ void FDTFluxQueuedRequestManager::OnParsingFailed(const FGuid& RequestId, const *ErrorMessage); FailRequest(RequestId, FString::Printf(TEXT("Parsing failed: %s"), *ErrorMessage)); } - -FString FDTFluxQueuedRequestManager::GenerateCacheKey(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, - int32 SplitId) -{ - return FString::Printf(TEXT("%s_%d_%d_%d"), - *UEnum::GetValueAsString(RequestType), - ContestId, - StageId, - SplitId); -} diff --git a/Source/DTFluxNetwork/Private/Subsystems/DTFluxNetworkSubsystem.cpp b/Source/DTFluxNetwork/Private/Subsystems/DTFluxNetworkSubsystem.cpp index c5c1248..77655f2 100644 --- a/Source/DTFluxNetwork/Private/Subsystems/DTFluxNetworkSubsystem.cpp +++ b/Source/DTFluxNetwork/Private/Subsystems/DTFluxNetworkSubsystem.cpp @@ -36,8 +36,6 @@ void UDTFluxNetworkSubsystem::Initialize(FSubsystemCollectionBase& Collection) DefaultConfig.TimeoutSeconds = 5.0f; DefaultConfig.MaxRetries = 3; DefaultConfig.RetryBackoffMultiplier = 1.5f; - DefaultConfig.bEnableCache = true; - DefaultConfig.CacheValiditySeconds = 60.0f; RequestManager->Initialize(DefaultConfig); @@ -143,8 +141,6 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequest( FDTFluxRequestConfig CustomConfig; CustomConfig.TimeoutSeconds = TimeoutSeconds; CustomConfig.MaxRetries = MaxRetries; - CustomConfig.bEnableCache = bEnableCache; - CustomConfig.CacheValiditySeconds = 60.0f; CustomConfig.RetryBackoffMultiplier = 1.5f; FGuid RequestId = RequestManager->CreateTrackedRequest(RequestType, ContestId, StageId, SplitId, CustomConfig); @@ -154,12 +150,8 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequest( // Récupérer la requête pour l'envoyer if (const FDTFluxTrackedRequest* Request = RequestManager->GetRequestPtr(RequestId)) { - // Si la requête est déjà en cache, pas besoin d'envoyer - if (Request->State != EDTFluxRequestState::Cached) - { - RequestManager->MarkRequestAsSent(RequestId); - SendQueuedRequest(*Request); - } + RequestManager->MarkRequestAsSent(RequestId); + SendQueuedRequest(*Request); } } @@ -174,8 +166,8 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallbacks( FOnDTFluxRequestSuccess& OnSuccess, FOnDTFluxRequestError& OnError, float TimeoutSeconds, - int32 MaxRetries, - bool bEnableCache) + int32 MaxRetries +) { if (!RequestManager.IsValid()) { @@ -186,8 +178,6 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallbacks( FDTFluxRequestConfig CustomConfig; CustomConfig.TimeoutSeconds = TimeoutSeconds; CustomConfig.MaxRetries = MaxRetries; - CustomConfig.bEnableCache = bEnableCache; - CustomConfig.CacheValiditySeconds = 60.0f; CustomConfig.RetryBackoffMultiplier = 1.5f; FGuid RequestId = RequestManager->CreateTrackedRequestWithCallbacks( @@ -197,11 +187,8 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallbacks( { if (const FDTFluxTrackedRequest* Request = RequestManager->GetRequestPtr(RequestId)) { - if (Request->State != EDTFluxRequestState::Cached) - { - RequestManager->MarkRequestAsSent(RequestId); - SendQueuedRequest(*Request); - } + RequestManager->MarkRequestAsSent(RequestId); + SendQueuedRequest(*Request); } } @@ -227,7 +214,6 @@ bool UDTFluxNetworkSubsystem::HasRequestReceivedResponse(const FGuid& RequestId) if (GetTrackedRequest(RequestId, Request)) { return Request.State == EDTFluxRequestState::Completed || - Request.State == EDTFluxRequestState::Cached || !Request.RawResponseData.IsEmpty(); } return false; @@ -264,22 +250,19 @@ int32 UDTFluxNetworkSubsystem::GetPendingRequestCount() const return 0; } -void UDTFluxNetworkSubsystem::GetRequestStatistics(int32& OutPending, int32& OutCached, int32& OutCompleted, - int32& OutFailed, float& OutHitRate) const +void UDTFluxNetworkSubsystem::GetRequestStatistics(int32& OutPending, int32& OutCompleted, + int32& OutFailed) const { if (RequestManager.IsValid()) { FDTFluxQueuedRequestManager::FRequestStatistics Stats = RequestManager->GetStatistics(); OutPending = Stats.Pending; - OutCached = Stats.Cached; OutCompleted = Stats.Completed; OutFailed = Stats.Failed; - OutHitRate = Stats.HitRate; } else { - OutPending = OutCached = OutCompleted = OutFailed = 0; - OutHitRate = 0.0f; + OutPending = OutCompleted = OutFailed = 0; } } @@ -362,7 +345,7 @@ void UDTFluxNetworkSubsystem::RegisterWebSocketEvents() &UDTFluxNetworkSubsystem::OnWebSocketMessageSentEvent_Subsystem); } -void UDTFluxNetworkSubsystem::UnregisterWebSocketEvents() +void UDTFluxNetworkSubsystem::UnregisterWebSocketEvents() const { if (!WsClient.IsValid()) return; @@ -794,11 +777,10 @@ void UDTFluxNetworkSubsystem::SendQueuedRequest(const FDTFluxTrackedRequest& Que bool UDTFluxNetworkSubsystem::ShouldUseAsyncParsing(const FString& JsonData) const { - // Critères pour décider du parsing asynchrone : + // Critère pour décider du parsing asynchrone : // - Taille des données (> 1KB par défaut) - // - Charge actuelle du système - // - Type de données (certains types sont plus complexes à parser) + // Pour le moment uniquement taille - const int32 AsyncThreshold = 1024; // 1KB + constexpr int32 AsyncThreshold = 1024; // 1KB return JsonData.Len() > AsyncThreshold; } diff --git a/Source/DTFluxNetwork/Public/DTFluxQueuedManager.h b/Source/DTFluxNetwork/Public/DTFluxQueuedManager.h index d299bb3..3f696bb 100644 --- a/Source/DTFluxNetwork/Public/DTFluxQueuedManager.h +++ b/Source/DTFluxNetwork/Public/DTFluxQueuedManager.h @@ -26,7 +26,6 @@ enum class EDTFluxRequestState : uint8 Completed UMETA(DisplayName = "Completed"), Failed UMETA(DisplayName = "Failed"), TimedOut UMETA(DisplayName = "TimedOut"), - Cached UMETA(DisplayName = "Cached"), Retrying UMETA(DisplayName = "Retrying") }; @@ -43,12 +42,6 @@ struct DTFLUXNETWORK_API FDTFluxRequestConfig UPROPERTY(EditAnywhere, BlueprintReadWrite) float RetryBackoffMultiplier = 1.5f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite) - bool bEnableCache = true; - - UPROPERTY(EditAnywhere, BlueprintReadWrite) - float CacheValiditySeconds = 60.0f; }; USTRUCT(BlueprintType) @@ -112,10 +105,8 @@ struct DTFLUXNETWORK_API FDTFluxTrackedRequest bool HasTimedOut() const; bool CanRetry() const; - bool IsCacheValid() const; float GetRetryDelay() const; bool Matches(EDTFluxApiDataType InType, int32 InContestId = -1, int32 InStageId = -1, int32 InSplitId = -1) const; - FString GetCacheKey() const; void SetRawResponse(const FString& RawData); FString Serialize() const; }; @@ -137,7 +128,7 @@ DECLARE_MULTICAST_DELEGATE_OneParam(FOnRequestFailedNative, const FDTFluxTracked // ================================================================================================ /** - * Gestionnaire de requêtes trackées avec cache, timeout, retry et parsing asynchrone + * 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 @@ -229,7 +220,7 @@ public: */ bool RetryRequest(const FGuid& RequestId); - // === RECHERCHE ET CACHE === + // === RECHERCHE === /** * Chercher une requête en attente correspondant aux critères @@ -242,28 +233,6 @@ public: int32 SplitId = -1 ) const; - /** - * Récupérer une réponse depuis le cache (données brutes) - */ - bool GetFromCache( - EDTFluxApiDataType RequestType, - FString& OutRawResponse, - int32 ContestId = -1, - int32 StageId = -1, - int32 SplitId = -1 - ) const; - - /** - * Récupérer une réponse parsée depuis le cache - */ - bool GetParsedFromCache( - EDTFluxApiDataType RequestType, - TSharedPtr& OutResponse, - int32 ContestId = -1, - int32 StageId = -1, - int32 SplitId = -1 - ) const; - // === ACCESSEURS === /** @@ -294,25 +263,15 @@ public: struct FRequestStatistics { int32 Pending = 0; - int32 Cached = 0; int32 Completed = 0; int32 Failed = 0; int32 TotalRequests = 0; - int32 CacheHits = 0; - int32 CacheMisses = 0; - float HitRate = 0.0f; }; FRequestStatistics GetStatistics() const; // === NETTOYAGE === - /** - * Nettoyer les entrées de cache expirées - * @return Nombre d'entrées supprimées - */ - int32 CleanupExpiredCache(); - /** * Nettoyer les requêtes terminées anciennes * @param OlderThanSeconds Supprimer les requêtes plus anciennes que ce délai @@ -321,7 +280,7 @@ public: int32 CleanupCompletedRequests(float OlderThanSeconds = 300.0f); /** - * Vider toutes les requêtes et le cache + * Vider toutes les requêtes */ void ClearAllRequests(); @@ -353,17 +312,14 @@ private: // === TIMING POUR LE TICK === float TimeSinceLastTimeoutCheck = 0.0f; - float TimeSinceLastCacheCleanup = 0.0f; float TimeSinceLastRetryCheck = 0.0f; static constexpr float TimeoutCheckInterval = 1.0f; - static constexpr float CacheCleanupInterval = 30.0f; static constexpr float RetryCheckInterval = 0.5f; // === STOCKAGE THREAD-SAFE === mutable FCriticalSection RequestsLock; TMap> AllRequests; - TMap CacheKeyToRequestId; // === CALLBACKS C++ === mutable FCriticalSection CallbacksLock; @@ -373,8 +329,6 @@ private: // === MÉTRIQUES === mutable FCriticalSection MetricsLock; mutable int32 TotalRequests = 0; - mutable int32 CacheHits = 0; - mutable int32 CacheMisses = 0; // === PARSER ASYNCHRONE === @@ -397,11 +351,6 @@ private: */ void ProcessRetries(); - /** - * Nettoyer le cache périodiquement - */ - void ProcessCacheCleanup(); - /** * Déclencher les callbacks pour une requête */ @@ -412,17 +361,6 @@ private: */ void CleanupCallbacks(const FGuid& RequestId); - /** - * Enregistrer un hit cache dans les métriques - */ - void RecordCacheHit() const; - - /** - * Enregistrer un miss cache dans les métriques - */ - void RecordCacheMiss() const; - - // === CALLBACKS POUR LE PARSING ASYNCHRONE === /** @@ -434,11 +372,4 @@ private: * Callback appelé quand le parsing asynchrone échoue */ void OnParsingFailed(const FGuid& RequestId, const FString& ErrorMessage); - - // === UTILITAIRES STATIQUES === - - /** - * Générer une clé de cache unique pour une requête - */ - static FString GenerateCacheKey(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId); }; diff --git a/Source/DTFluxNetwork/Public/Subsystems/DTFluxNetworkSubsystem.h b/Source/DTFluxNetwork/Public/Subsystems/DTFluxNetworkSubsystem.h index 4d9a365..c2f2cac 100644 --- a/Source/DTFluxNetwork/Public/Subsystems/DTFluxNetworkSubsystem.h +++ b/Source/DTFluxNetwork/Public/Subsystems/DTFluxNetworkSubsystem.h @@ -125,8 +125,7 @@ public: FOnDTFluxRequestSuccess& OnSuccess, FOnDTFluxRequestError& OnError, float TimeoutSeconds = 5.0f, - int32 MaxRetries = 3, - bool bEnableCache = true + int32 MaxRetries = 3 ); // === ACCESSEURS BLUEPRINT POUR LES REQUÊTES TRACKÉES === @@ -166,8 +165,7 @@ public: * Récupérer les statistiques du gestionnaire de requêtes */ UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests") - void GetRequestStatistics(int32& OutPending, int32& OutCached, int32& OutCompleted, int32& OutFailed, - float& OutHitRate) const; + void GetRequestStatistics(int32& OutPending, int32& OutCompleted, int32& OutFailed) const; // === REQUÊTES LEGACY (Compatibilité totale) === @@ -249,7 +247,7 @@ private: // === GESTION DES ÉVÉNEMENTS WEBSOCKET === void RegisterWebSocketEvents(); - void UnregisterWebSocketEvents(); + void UnregisterWebSocketEvents() const; void OnWebSocketConnected_Subsystem(); void OnWebSocketConnectionError_Subsystem(const FString& Error); void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean);