2025-07-11 19:04:37 +02:00
|
|
|
|
// ================================================================================================
|
|
|
|
|
|
// DTFluxNetworkSubsystem.h - Interface UObject avec compatibilité Blueprint
|
|
|
|
|
|
// ================================================================================================
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
#include "CoreMinimal.h"
|
|
|
|
|
|
#include "Subsystems/EngineSubsystem.h"
|
|
|
|
|
|
#include "Types/DTFluxNetworkSettingsTypes.h"
|
2025-07-03 17:28:51 +02:00
|
|
|
|
#include "Types/Enum/DTFluxCoreEnum.h"
|
2025-07-11 19:04:37 +02:00
|
|
|
|
#include "DTFluxQueuedManager.h"
|
2025-06-29 19:04:36 +02:00
|
|
|
|
#include "DTFluxNetworkSubsystem.generated.h"
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
// Forward declarations
|
2025-06-29 19:04:36 +02:00
|
|
|
|
class FDTFluxWebSocketClient;
|
2025-07-11 19:04:37 +02:00
|
|
|
|
class FDTFluxQueuedRequestManager;
|
|
|
|
|
|
|
2025-06-29 19:04:36 +02:00
|
|
|
|
typedef TSharedPtr<FDTFluxWebSocketClient> FDTFluxWebSocketClientSP;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestCompleted, const FGuid&, RequestId,
|
|
|
|
|
|
EDTFluxApiDataType, RequestType, const FString&, ResponseData);
|
|
|
|
|
|
|
|
|
|
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestFailed, const FGuid&, RequestId,
|
|
|
|
|
|
EDTFluxApiDataType, RequestType, const FString&, ErrorMessage);
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnRaceDataReceived, const FDTFluxRaceData& /*RaceDataDefinition*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnTeamListReceived, const FDTFluxTeamListDefinition& /*TeamListDefinition*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnStageRankingReceived, const FDTFluxStageRankings& /*StageRankings*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnSplitRankingReceived, const FDTFluxSplitRankings& /*SplitRankings*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnContestRankingReceived, const FDTFluxContestRankings& /*ContestRankings*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnSplitSensorReceived, const FDTFluxSplitSensorInfo& /*SplitSensorInfo*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnTeamUpdateReceived, const FDTFluxTeamListDefinition& /*ParticipantToUpdate*/);
|
|
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnTeamStatusUpdateReceived, const FDTFluxTeamStatusUpdate& /*TeamToUpdate*/);
|
|
|
|
|
|
|
|
|
|
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWebSocketConnected);
|
|
|
|
|
|
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-06-29 19:04:36 +02:00
|
|
|
|
UCLASS(Blueprintable)
|
2025-07-03 17:28:51 +02:00
|
|
|
|
class DTFLUXNETWORK_API UDTFluxNetworkSubsystem : public UEngineSubsystem
|
2025-06-29 19:04:36 +02:00
|
|
|
|
{
|
|
|
|
|
|
GENERATED_BODY()
|
|
|
|
|
|
|
2025-07-08 16:50:31 +02:00
|
|
|
|
public:
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UPROPERTY(BlueprintReadOnly, Category = "DTFlux|Network")
|
2025-06-29 19:04:36 +02:00
|
|
|
|
EDTFluxConnectionStatus WsStatus = EDTFluxConnectionStatus::Unset;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Se connecter au serveur WebSocket
|
|
|
|
|
|
*/
|
|
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Network")
|
|
|
|
|
|
void Connect();
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Se déconnecter du serveur WebSocket
|
|
|
|
|
|
*/
|
|
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Network")
|
|
|
|
|
|
void Disconnect();
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Reconnecter au serveur WebSocket
|
|
|
|
|
|
*/
|
|
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Network")
|
|
|
|
|
|
void Reconnect();
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Envoyer une requête trackée avec cache, timeout et retry
|
|
|
|
|
|
* @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 TimeoutSeconds Timeout en secondes
|
|
|
|
|
|
* @param MaxRetries Nombre maximum de tentatives
|
|
|
|
|
|
* @param bEnableCache Activer le cache pour cette requête
|
|
|
|
|
|
* @return GUID de la requête pour le suivi
|
|
|
|
|
|
*/
|
|
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
FGuid SendTrackedRequest(
|
|
|
|
|
|
EDTFluxApiDataType RequestType,
|
|
|
|
|
|
int32 ContestId = -1,
|
|
|
|
|
|
int32 StageId = -1,
|
|
|
|
|
|
int32 SplitId = -1,
|
|
|
|
|
|
float TimeoutSeconds = 5.0f,
|
|
|
|
|
|
int32 MaxRetries = 3,
|
|
|
|
|
|
bool bEnableCache = true
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Envoyer une requête trackée avec callbacks C++ (non Blueprint)
|
|
|
|
|
|
* @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 TimeoutSeconds Timeout en secondes
|
|
|
|
|
|
* @param MaxRetries Nombre maximum de tentatives
|
|
|
|
|
|
* @param bEnableCache Activer le cache
|
|
|
|
|
|
* @return GUID de la requête
|
|
|
|
|
|
*/
|
|
|
|
|
|
FGuid SendTrackedRequestWithCallbacks(
|
|
|
|
|
|
EDTFluxApiDataType RequestType,
|
|
|
|
|
|
int32 ContestId,
|
|
|
|
|
|
int32 StageId,
|
|
|
|
|
|
int32 SplitId,
|
|
|
|
|
|
FOnDTFluxRequestSuccess& OnSuccess,
|
|
|
|
|
|
FOnDTFluxRequestError& OnError,
|
|
|
|
|
|
float TimeoutSeconds = 5.0f,
|
2025-07-12 16:07:37 +02:00
|
|
|
|
int32 MaxRetries = 3
|
2025-07-11 19:04:37 +02:00
|
|
|
|
);
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
bool GetTrackedRequest(const FGuid& RequestId, FDTFluxTrackedRequest& OutRequest) const;
|
|
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
bool HasRequestReceivedResponse(const FGuid& RequestId) const;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
FString GetRequestResponseData(const FGuid& RequestId) const;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
bool IsRequestPending(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1,
|
|
|
|
|
|
int32 SplitId = -1) const;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
int32 GetPendingRequestCount() const;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Tracked Requests")
|
2025-07-12 16:07:37 +02:00
|
|
|
|
void GetRequestStatistics(int32& OutPending, int32& OutCompleted, int32& OutFailed) const;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-06-30 19:02:19 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Legacy")
|
|
|
|
|
|
void SendRequest(const EDTFluxApiDataType RequestType, int InContestId = -1, int InStageId = -1,
|
|
|
|
|
|
int InSplitId = -1);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "DTFlux|Network")
|
|
|
|
|
|
void SendMessage(const FString& Message);
|
2025-07-03 17:28:51 +02:00
|
|
|
|
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "DTFlux|Network")
|
|
|
|
|
|
FOnWebSocketConnected OnWebSocketConnected;
|
2025-06-30 19:02:19 +02:00
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
FOnDTFluxTrackedRequestCompleted OnTrackedRequestCompleted;
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "DTFlux|Tracked Requests")
|
|
|
|
|
|
FOnDTFluxTrackedRequestFailed OnTrackedRequestFailed;
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
FOnRaceDataReceived OnRaceDataReceived;
|
|
|
|
|
|
FOnTeamListReceived OnTeamListReceived;
|
|
|
|
|
|
FOnStageRankingReceived OnStageRankingReceived;
|
|
|
|
|
|
FOnSplitRankingReceived OnSplitRankingReceived;
|
|
|
|
|
|
FOnContestRankingReceived OnContestRankingReceived;
|
|
|
|
|
|
FOnSplitSensorReceived OnSplitSensorReceived;
|
|
|
|
|
|
FOnTeamUpdateReceived OnTeamUpdateReceived;
|
|
|
|
|
|
FOnTeamStatusUpdateReceived OnTeamStatusUpdateReceived;
|
2025-07-09 03:27:23 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
FOnRaceDataReceived& OnReceivedRaceData() { return OnRaceDataReceived; }
|
|
|
|
|
|
FOnTeamListReceived& OnReceivedTeamList() { return OnTeamListReceived; }
|
|
|
|
|
|
FOnStageRankingReceived& OnReceivedStageRanking() { return OnStageRankingReceived; }
|
|
|
|
|
|
FOnSplitRankingReceived& OnReceivedSplitRanking() { return OnSplitRankingReceived; }
|
|
|
|
|
|
FOnContestRankingReceived& OnReceivedContestRanking() { return OnContestRankingReceived; }
|
|
|
|
|
|
FOnSplitSensorReceived& OnReceivedSplitSensor() { return OnSplitSensorReceived; }
|
|
|
|
|
|
FOnTeamUpdateReceived& OnReceivedTeamUpdate() { return OnTeamUpdateReceived; }
|
|
|
|
|
|
FOnTeamStatusUpdateReceived& OnReceivedTeamStatusUpdate() { return OnTeamStatusUpdateReceived; }
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-15 07:59:45 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
TSharedPtr<FDTFluxQueuedRequestManager> GetRequestManager() const { return RequestManager; }
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
2025-06-29 19:04:36 +02:00
|
|
|
|
protected:
|
|
|
|
|
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
|
|
|
|
|
virtual void Deinitialize() override;
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
FDTFluxWsSettings WsSettings;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
FDTFluxWebSocketClientSP WsClient = nullptr;
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
TSharedPtr<FDTFluxQueuedRequestManager> RequestManager;
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
|
|
|
|
|
void RegisterWebSocketEvents();
|
2025-07-12 16:07:37 +02:00
|
|
|
|
void UnregisterWebSocketEvents() const;
|
2025-06-29 19:04:36 +02:00
|
|
|
|
void OnWebSocketConnected_Subsystem();
|
|
|
|
|
|
void OnWebSocketConnectionError_Subsystem(const FString& Error);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean);
|
2025-07-11 19:04:37 +02:00
|
|
|
|
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
|
|
|
|
|
|
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
|
|
|
|
|
FDelegateHandle OnWsConnectedEventDelegateHandle;
|
|
|
|
|
|
FDelegateHandle OnWsConnectionErrorEventDelegateHandle;
|
|
|
|
|
|
FDelegateHandle OnWsClosedEventDelegateHandle;
|
|
|
|
|
|
FDelegateHandle OnWsMessageEventDelegateHandle;
|
|
|
|
|
|
FDelegateHandle OnWsMessageSentEventDelegateHandle;
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Essayer de matcher une réponse à une requête trackée
|
|
|
|
|
|
* @param MessageString Message JSON reçu
|
|
|
|
|
|
* @return true si la réponse correspond à une requête trackée
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool TryMatchResponseToQueuedRequest(const FString& MessageString);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Traiter une réponse en mode legacy
|
|
|
|
|
|
* @param MessageString Message JSON à traiter
|
|
|
|
|
|
*/
|
|
|
|
|
|
void ProcessLegacyResponse(const FString& MessageString);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Traiter une réponse déjà parsée
|
|
|
|
|
|
* @param ParsedResponse Réponse parsée à traiter
|
|
|
|
|
|
*/
|
|
|
|
|
|
void ProcessParsedResponse(TSharedPtr<FDTFluxServerResponse> ParsedResponse);
|
|
|
|
|
|
|
|
|
|
|
|
// === MÉTHODES DE PARSING LEGACY (pour compatibilité) ===
|
|
|
|
|
|
void ParseTeamListResponse(FDTFluxServerResponse& Response);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
void ParseRaceData(FDTFluxServerResponse& Response);
|
|
|
|
|
|
void ParseContestRanking(FDTFluxServerResponse& Response);
|
|
|
|
|
|
void ParseStageRankingResponse(FDTFluxServerResponse& Response);
|
|
|
|
|
|
void ParseSplitRankingResponse(FDTFluxServerResponse& Response);
|
|
|
|
|
|
void ParseStatusUpdateResponse(FDTFluxServerResponse& Response);
|
|
|
|
|
|
void ParseSplitSensorResponse(FDTFluxServerResponse& Response);
|
|
|
|
|
|
EDTFluxResponseStatus ProcessPushMessage(FDTFluxServerResponse& Response);
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Callback appelé quand une requête trackée se termine
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnRequestCompleted_Internal(const FDTFluxTrackedRequest& CompletedRequest);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Callback appelé quand une requête trackée échoue
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnRequestFailed_Internal(const FDTFluxTrackedRequest& FailedRequest);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Callback appelé quand les paramètres WebSocket changent
|
|
|
|
|
|
*/
|
2025-07-08 16:50:31 +02:00
|
|
|
|
UFUNCTION()
|
2025-07-11 19:04:37 +02:00
|
|
|
|
void WsSettingsChanged(const FDTFluxWsSettings& NewWsSettings);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Reconnecter le client WebSocket
|
|
|
|
|
|
*/
|
|
|
|
|
|
void ReconnectWs(const FName WsClientId);
|
2025-06-29 19:04:36 +02:00
|
|
|
|
|
2025-07-11 19:04:37 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Construire une adresse WebSocket complète
|
|
|
|
|
|
*/
|
2025-06-29 19:04:36 +02:00
|
|
|
|
static FString ConstructWsAddress(const FString& Address, const FString& Path, const int& Port);
|
2025-07-11 19:04:37 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Envoyer une requête trackée via le réseau
|
|
|
|
|
|
*/
|
|
|
|
|
|
void SendQueuedRequest(const FDTFluxTrackedRequest& QueuedRequest);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Déterminer si on doit utiliser le parsing asynchrone
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool ShouldUseAsyncParsing(const FString& JsonData) const;
|
2025-06-29 19:04:36 +02:00
|
|
|
|
};
|