// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "DTFluxQueuedManager.h" #include "Struct/DTFluxServerResponseStruct.h" #include "Subsystems/EngineSubsystem.h" #include "Types/DTFluxNetworkSettingsTypes.h" #include "Types/Enum/DTFluxCoreEnum.h" #include "Types/Struct/DTFluxRaceDataStructs.h" #include "Types/Struct/DTFluxRankingStructs.h" #include "Types/Struct/DTFluxSplitSensor.h" #include "Types/Struct/DTFluxTeamListStruct.h" #include "DTFluxNetworkSubsystem.generated.h" class FDTFluxWebSocketClient; class UDTFluxQueuedManager; typedef TSharedPtr FDTFluxWebSocketClientSP; class FDTFluxHttpClient; typedef TSharedPtr FDTFluxHttpClientSP; // Delegates pour les requêtes avec callback 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); DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestFailed, const FGuid&, RequestId, EDTFluxApiDataType, RequestType, const FString&, ErrorMessage); /** * */ UCLASS(Blueprintable) class DTFLUXNETWORK_API UDTFluxNetworkSubsystem : public UEngineSubsystem { GENERATED_BODY() public: UPROPERTY() EDTFluxConnectionStatus WsStatus = EDTFluxConnectionStatus::Unset; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWebSocketConnected); UPROPERTY(BlueprintAssignable, Category="DTFlux|Network") FOnWebSocketConnected OnWebSocketConnected; DECLARE_DELEGATE_OneParam(FOnRaceDataReceived, const FDTFluxRaceData& /*RaceDataDefinition*/); FOnRaceDataReceived OnRaceDataReceived; FOnRaceDataReceived& OnReceivedRaceData() { return OnRaceDataReceived; }; // === DELEGATES POUR LES DONNÉES REÇUES (PUSH) === DECLARE_DELEGATE_OneParam(FOnTeamListReceived, const FDTFluxTeamListDefinition& /*TeamListDefinition*/); FOnTeamListReceived OnTeamListReceived; FOnTeamListReceived& OnReceivedTeamList() { return OnTeamListReceived; }; DECLARE_DELEGATE_OneParam(FOnStageRankingReceived, const FDTFluxStageRankings& /*StageRankings*/); FOnStageRankingReceived OnStageRankingReceived; FOnStageRankingReceived& OnReceivedStageRanking() { return OnStageRankingReceived; } DECLARE_DELEGATE_OneParam(FOnSplitRankingReceived, const FDTFluxSplitRankings& /*SplitRankings*/); FOnSplitRankingReceived OnSplitRankingReceived; FOnSplitRankingReceived& OnReceivedSplitRanking() { return OnSplitRankingReceived; } DECLARE_DELEGATE_OneParam(FOnContestRankingReceived, const FDTFluxContestRankings& /*ContestRankings*/); FOnContestRankingReceived OnContestRankingReceived; FOnContestRankingReceived& OnReceivedContestRanking() { return OnContestRankingReceived; }; // === DELEGATES POUR LES DONNÉES REÇUES (PULL) === DECLARE_DELEGATE_OneParam(FOnSplitSensorReceived, const FDTFluxSplitSensorInfo& /*ContestRankings*/); FOnSplitSensorReceived OnSplitSensorReceived; FOnSplitSensorReceived& OnReceivedSplitSensor() { return OnSplitSensorReceived; }; DECLARE_DELEGATE_OneParam(FOnTeamUpdateReceived, const FDTFluxTeamListDefinition& /*ParticipantToUpdate*/); FOnTeamUpdateReceived OnTeamUpdateReceived; FOnTeamUpdateReceived& OnReceivedTeamUpdate() { return OnTeamUpdateReceived; }; DECLARE_DELEGATE_OneParam(FOnTeamStatusUpdateReceived, const FDTFluxTeamStatusUpdate& /*TeamToUpdate*/); FOnTeamStatusUpdateReceived OnTeamStatusUpdateReceived; FOnTeamStatusUpdateReceived& OnReceivedTeamStatusUpdate() { return OnTeamStatusUpdateReceived; }; UFUNCTION(BlueprintCallable, Category="DTFlux|Network") void Connect(); UFUNCTION(BlueprintCallable, Category="DTFlux|Network") void Disconnect(); UFUNCTION(BlueprintCallable, Category="DTFlux|Network") void Reconnect(); // === REQUÊTES AVEC QUEUE ET TRACKING === UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") FGuid SendTrackedRequest(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1, int32 SplitId = -1, float TimeoutSeconds = 5.0f); FGuid SendTrackedRequestWithCallback(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId, FOnDTFluxTrackedRequestResponse OnCompleted, FOnDTFluxTrackedRequestTimeout OnTimeout, TOptional OnError = TOptional< FOnDTFluxRequestResponseError>(), float TimeoutSeconds = 5.0f); UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") bool GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const; const FDTFluxQueuedRequest* GetTrackedRequestPtr(const FGuid& RequestId) const; UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests", CallInEditor) bool HasRequestReceivedResponse(const FGuid& RequestId) const; UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") FString GetRequestResponseData(const FGuid& RequestId) const; UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") bool IsRequestPending(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1, int32 SplitId = -1) const; UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") int32 GetPendingRequestCount() const; UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") UDTFluxQueuedManager* GetQueueManager() const; // === EVENTS BLUEPRINT POUR LE TRACKING === UPROPERTY(BlueprintAssignable, Category="DTFlux|Tracked Requests") FOnDTFluxTrackedRequestCompleted OnTrackedRequestCompleted; UPROPERTY(BlueprintAssignable, Category="DTFlux|Tracked Requests") FOnDTFluxTrackedRequestFailed OnTrackedRequestFailed; UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") // === REQUÊTES DIRECTES (LEGACY) === void SendRequest(const EDTFluxApiDataType RequestType, int InContestId = -1, int InStageId = -1, int InSplitId = -1); UFUNCTION(BlueprintCallable, Category="DTFlux|Network") void SendMessage(const FString& Message); protected: // ~Subsystem Interface virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; // ~Subsystem Interface private: // === CONFIGURATION === FDTFluxWsSettings WsSettings; FDTFluxHttpSettings HttpSettings; UPROPERTY() UDTFluxQueuedManager* QueueManager; // === MAPPING DES CALLBACKS C++ === TMap PendingCallbacks; TMap PendingTimeoutCallbacks; TMap PendingErrorCallbacks; // === CLIENTS RÉSEAU === FDTFluxWebSocketClientSP WsClient = nullptr; FDTFluxHttpClientSP HttpClient = nullptr; // === MÉTHODES DE CONFIGURATION === UFUNCTION() void WsSettingsChanged(const FDTFluxWsSettings& NewWsSettings); void ReconnectWs(const FName WsClientId); UFUNCTION() void HttpSettingsChanged(const FDTFluxHttpSettings& NewHttpSettings); void ReconnectHttp(const FName WsClientId); // === GESTION DES ÉVÉNEMENTS HTTP === void RegisterHttpEvents(); void UnregisterHttpEvents(); // === GESTION DES ÉVÉNEMENTS WEBSOCKET === void RegisterWebSocketEvents(); void UnregisterWebSocketEvents(); void OnWebSocketConnected_Subsystem(); void OnWebSocketConnectionError_Subsystem(const FString& Error); void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean); void OnWebSocketMessageEvent_Subsystem(const FString& MessageString); void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent); FDelegateHandle OnWsConnectedEventDelegateHandle; FDelegateHandle OnWsConnectionErrorEventDelegateHandle; FDelegateHandle OnWsClosedEventDelegateHandle; FDelegateHandle OnWsMessageEventDelegateHandle; FDelegateHandle OnWsMessageSentEventDelegateHandle; // === PARSING DES RÉPONSES === void ParseTeamListResponse(FDTFluxServerResponse& ServerResponse); 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); void Parse(FDTFluxServerResponse& Response); bool CleanRequestCallbacks(const FGuid& RequestId); // === GESTION DES REQUÊTES TRACKÉES === UFUNCTION() void OnRequestTimedOut_Internal(const FDTFluxQueuedRequest& TimedOutRequest); 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); // === UTILITAIRES === static FString ConstructWsAddress(const FString& Address, const FString& Path, const int& Port); };