2025-07-08 16:50:31 +02:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
#include "Struct/DTFluxServerResponseStruct.h"
|
|
|
|
|
|
|
|
|
|
|
|
// === IMPLÉMENTATION DES CONSTRUCTEURS ===
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxServerResponse::FDTFluxServerResponse()
|
|
|
|
|
|
{
|
|
|
|
|
|
ReceivedAt = FDateTime::Now();
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::None;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Unset;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxServerResponse::FDTFluxServerResponse(const FString& JsonMessage, EDTFluxResponseStatus& OutStatus,
|
|
|
|
|
|
bool bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
ReceivedAt = FDateTime::Now();
|
|
|
|
|
|
RawMessage = JsonMessage;
|
|
|
|
|
|
|
|
|
|
|
|
ParsingStatus = InitializeFromJson(JsonMessage, bLogErrors);
|
|
|
|
|
|
OutStatus = ParsingStatus;
|
|
|
|
|
|
|
|
|
|
|
|
if (bLogErrors && ParsingStatus != EDTFluxResponseStatus::Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to create DTFluxServerResponse: %s"), *GetErrorMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxServerResponse FDTFluxServerResponse::CreateFromJson(const FString& JsonMessage, bool bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
EDTFluxResponseStatus Status;
|
|
|
|
|
|
FDTFluxServerResponse Response(JsonMessage, Status, bLogErrors);
|
|
|
|
|
|
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Status == EDTFluxResponseStatus::Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Successfully created DTFluxServerResponse: %s"),
|
|
|
|
|
|
*Response.ToDebugString());
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Warning, TEXT("Created DTFluxServerResponse with issues: %s"),
|
|
|
|
|
|
*Response.GetErrorMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Response;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EDTFluxResponseStatus FDTFluxServerResponse::TryParse(bool bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Vérifier que le type est présent
|
|
|
|
|
|
if (Type.IsEmpty())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response missing 'type' field"));
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::None;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::MissingData;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::UnknownError;
|
|
|
|
|
|
// Validation supplémentaire selon le type
|
|
|
|
|
|
if (ContainsDataType("race-data"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Parsing race-data response"));
|
|
|
|
|
|
}
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::RaceData;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ContainsDataType("team-list"))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::TeamList;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ContainsDataType("contest-ranking"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ContestID == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Warning, TEXT("Contest-ranking missing ContestID"));
|
|
|
|
|
|
}
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::DataError;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::ContestRanking;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ContainsDataType("stage-ranking"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ContestID == -1 || StageID == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Warning, TEXT("Stage-ranking missing ContestID or StageID"));
|
|
|
|
|
|
}
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::DataError;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (SplitID != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::SplitRanking;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::StageRanking;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ContainsDataType("status-update"))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::StatusUpdate;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ContainsDataType("split-sensor"))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::SplitSensor;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ContainsDataType("team-update"))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiDataType = EDTFluxApiDataType::TeamUpdate;
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return ParsingStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
return EDTFluxResponseStatus::UnknownError;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EDTFluxResponseStatus FDTFluxServerResponse::InitializeFromJson(const FString& JsonMessage, bool bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Parser le JSON de base
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct(JsonMessage, this, 0, 0, false, &FailureReason))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("JSON parse error: %s\nMessage: %s"), *FailureReason.ToString(),
|
|
|
|
|
|
*JsonMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Vérifier si c'est une erreur du serveur
|
|
|
|
|
|
if (Code != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bLogErrors)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Warning, TEXT("Server error response: Code=%d, Message=%s"), Code, *Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EDTFluxResponseStatus::ServerError;
|
|
|
|
|
|
}
|
|
|
|
|
|
return TryParse();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FString FDTFluxServerResponse::GetErrorMessage() const
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (ParsingStatus)
|
|
|
|
|
|
{
|
|
|
|
|
|
case EDTFluxResponseStatus::Success:
|
|
|
|
|
|
return TEXT("No error");
|
|
|
|
|
|
|
|
|
|
|
|
case EDTFluxResponseStatus::JsonParseError:
|
|
|
|
|
|
return FString::Printf(TEXT("JSON parsing failed: %s"), *FailureReason.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
case EDTFluxResponseStatus::ServerError:
|
|
|
|
|
|
return FString::Printf(TEXT("Server error %d: %s"), Code, *Message);
|
|
|
|
|
|
|
|
|
|
|
|
case EDTFluxResponseStatus::InvalidType:
|
|
|
|
|
|
return FString::Printf(TEXT("Invalid or missing response type: '%s'"), *Type);
|
|
|
|
|
|
|
|
|
|
|
|
case EDTFluxResponseStatus::MissingData:
|
|
|
|
|
|
return FString::Printf(TEXT("Missing required data fields for type '%s'"), *Type);
|
|
|
|
|
|
|
|
|
|
|
|
case EDTFluxResponseStatus::UnknownError:
|
|
|
|
|
|
default:
|
|
|
|
|
|
return TEXT("Unknown error occurred during parsing");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FString FDTFluxServerResponse::ToDebugString() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return FString::Printf(
|
|
|
|
|
|
TEXT("DTFluxServerResponse[Status=%s, Type=%s, Code=%d, Contest=%d, Stage=%d, Split=%d, ReceivedAt=%s]"),
|
|
|
|
|
|
*UEnum::GetValueAsString(ParsingStatus), *Type, Code, ContestID, StageID, SplitID, *ReceivedAt.ToString());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseTeamListResponse(FDTFluxTeamListDefinition& OutTeamList)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Unset;
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("team-list")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a team-list type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> JsonObject;
|
|
|
|
|
|
if (!ParseJsonObject(JsonObject))
|
|
|
|
|
|
{
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const TArray<TSharedPtr<FJsonValue>>* DataArray;
|
|
|
|
|
|
if (!JsonObject->TryGetArrayField(TEXT("datas"), DataArray))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("No 'datas' array found in team-list response"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::MissingData;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OutTeamList.Participants.Empty();
|
|
|
|
|
|
for (const TSharedPtr<FJsonValue>& Value : *DataArray)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Value->Type == EJson::Object)
|
|
|
|
|
|
{
|
|
|
|
|
|
const TSharedPtr<FJsonObject> Item = Value->AsObject();
|
|
|
|
|
|
FDTFluxParticipant Participant;
|
|
|
|
|
|
if (UDTFluxParticipantFactory::CreateFromJsonCpp(Item, Participant))
|
|
|
|
|
|
{
|
|
|
|
|
|
OutTeamList.Participants.Add(Participant);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Warning, TEXT("Failed to parse participant from JSON"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ParsingStatus = GetParsingStatus();
|
|
|
|
|
|
if (ParsingStatus == EDTFluxResponseStatus::Success && OutTeamList.Participants.Num() != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed %d participants from team-list"),
|
|
|
|
|
|
OutTeamList.Participants.Num());
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (OutTeamList.Participants.Num() == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("No Participant Added"));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ParsingStatus != EDTFluxResponseStatus::Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse team-list Error : %s"), *GetErrorMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseTeamUpdateResponse(FDTFluxTeamListDefinition& OutTeamUpdate)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ParseTeamListResponse(OutTeamUpdate);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseRaceData(FDTFluxRaceData& OutRaceData)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Unset;
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("race-data")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a race-data type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxRaceDataResponse RaceDataResponse;
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct<FDTFluxRaceDataResponse>(RawMessage, &RaceDataResponse))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse race-data JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
OutRaceData.Datas.Empty();
|
|
|
|
|
|
for (const auto& Contest : RaceDataResponse.Datas)
|
|
|
|
|
|
{
|
|
|
|
|
|
FDTFluxContest NewContest;
|
|
|
|
|
|
NewContest.Name = Contest.Name;
|
|
|
|
|
|
NewContest.ContestId = Contest.Id;
|
|
|
|
|
|
NewContest.Date = Contest.Date;
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Processing Contest %d [%s] Starting at %s"),
|
|
|
|
|
|
Contest.Id, *Contest.Name, *Contest.Date.ToString());
|
|
|
|
|
|
// Satges
|
|
|
|
|
|
for (const auto& Stage : Contest.Stages)
|
|
|
|
|
|
{
|
|
|
|
|
|
FDTFluxStage NewStage;
|
|
|
|
|
|
NewStage.StageId = Stage.Id;
|
|
|
|
|
|
NewStage.Name = Stage.Name;
|
|
|
|
|
|
|
|
|
|
|
|
// Construct full Timestamps strings
|
|
|
|
|
|
FString StartTimeFString = FString::Printf(TEXT("%s %s"),
|
|
|
|
|
|
*NewContest.Date.ToFormattedString(TEXT("%Y-%m-%d")),
|
|
|
|
|
|
*Stage.StartTime);
|
|
|
|
|
|
FString EndTimeFString = FString::Printf(TEXT("%s %s"),
|
|
|
|
|
|
*NewContest.Date.ToFormattedString(TEXT("%Y-%m-%d")),
|
|
|
|
|
|
*Stage.EndTime);
|
|
|
|
|
|
FString CutOffFString = FString::Printf(TEXT("%s %s"),
|
|
|
|
|
|
*NewContest.Date.ToFormattedString(TEXT("%Y-%m-%d")),
|
|
|
|
|
|
*Stage.CutOff);
|
|
|
|
|
|
FDateTime::Parse(StartTimeFString, NewStage.StartTime);
|
|
|
|
|
|
FDateTime::Parse(EndTimeFString, NewStage.EndTime);
|
|
|
|
|
|
FDateTime::Parse(CutOffFString, NewStage.CutOff);
|
|
|
|
|
|
NewContest.Stages.Add(NewStage);
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Stage %d [%s]: Start[%s], CutOff[%s], End[%s]"),
|
|
|
|
|
|
Stage.Id, *Stage.Name, *NewStage.StartTime.ToString(),
|
|
|
|
|
|
*NewStage.CutOff.ToString(), *NewStage.EndTime.ToString());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Traiter les splits
|
|
|
|
|
|
for (const auto& Split : Contest.Splits)
|
|
|
|
|
|
{
|
|
|
|
|
|
FDTFluxSplit NewSplit;
|
|
|
|
|
|
NewSplit.SplitId = Split.Id;
|
|
|
|
|
|
NewSplit.Name = Split.Name;
|
|
|
|
|
|
NewContest.Splits.Add(NewSplit);
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Split %d [%s]"), Split.Id, *Split.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
// Update Contest metadata
|
|
|
|
|
|
NewContest.UpdateEndTime();
|
|
|
|
|
|
NewContest.UpdateLastStageId();
|
|
|
|
|
|
|
|
|
|
|
|
OutRaceData.Datas.Add(NewContest);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed %d contests from race-data"),
|
|
|
|
|
|
OutRaceData.Datas.Num());
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseContestRanking(FDTFluxContestRankings& OutContestRankings)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("contest-ranking")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a contest-ranking type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxContestRankingResponse ContestRankingResponse;
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct<FDTFluxContestRankingResponse>(
|
|
|
|
|
|
RawMessage, &ContestRankingResponse))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse contest-ranking JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OutContestRankings.ContestId = ContestRankingResponse.ContestID;
|
|
|
|
|
|
OutContestRankings.Rankings.Empty();
|
|
|
|
|
|
for (const auto& RankingItem : ContestRankingResponse.Datas)
|
|
|
|
|
|
{
|
|
|
|
|
|
FDTFluxContestRanking Ranking = RankingItem;
|
|
|
|
|
|
OutContestRankings.Rankings.Add(Ranking);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed contest ranking for Contest %d with %d entries"),
|
|
|
|
|
|
OutContestRankings.ContestId, OutContestRankings.Rankings.Num());
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseStageRankingResponse(FDTFluxStageRankings& OutStageRankings)
|
|
|
|
|
|
{
|
2025-07-09 03:27:23 +02:00
|
|
|
|
// UE_LOG(logDTFluxNetwork, Log, TEXT("Response is stage-ranking type %s"), *RawMessage);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
if (!ValidateResponseType(TEXT("stage-ranking")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a stage-ranking type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
FDTFluxStageRankingResponse RankingResponse;
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct<FDTFluxStageRankingResponse>(RawMessage, &RankingResponse))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse stage-ranking JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-09 03:27:23 +02:00
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Reponse Update"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
OutStageRankings.ContestId = ContestID;
|
|
|
|
|
|
OutStageRankings.StageId = StageID;
|
|
|
|
|
|
OutStageRankings.Rankings = static_cast<TArray<FDTFluxDetailedRankingItem>>(RankingResponse.Datas);
|
|
|
|
|
|
OutStageRankings.Initialize();
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed stage ranking for Contest %d, Stage %d with %d entries"),
|
|
|
|
|
|
OutStageRankings.ContestId, OutStageRankings.StageId, OutStageRankings.Rankings.Num());
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseSplitRankingResponse(FDTFluxSplitRankings& OutSplitRankings)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("stage-ranking")) || SplitID == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error,
|
|
|
|
|
|
TEXT("Response is not a split-ranking type (stage-ranking with SplitID != -1)"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxSplitRankingResponse SplitRankingResponse;
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct<
|
|
|
|
|
|
FDTFluxSplitRankingResponse>(RawMessage, &SplitRankingResponse))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse split-ranking JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OutSplitRankings.ContestId = ContestID;
|
|
|
|
|
|
OutSplitRankings.StageId = StageID;
|
|
|
|
|
|
OutSplitRankings.SplitId = SplitID;
|
|
|
|
|
|
OutSplitRankings.Rankings = static_cast<TArray<FDTFluxDetailedRankingItem>>(SplitRankingResponse.Datas);
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log,
|
|
|
|
|
|
TEXT("Successfully parsed split ranking for Contest %d, Stage %d, Split %d with %d entries"),
|
|
|
|
|
|
OutSplitRankings.ContestId, OutSplitRankings.StageId, OutSplitRankings.SplitId,
|
|
|
|
|
|
OutSplitRankings.Rankings.Num());
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseStatusUpdateResponse(FDTFluxTeamStatusUpdate& OutStatusUpdate)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("status-update")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a status-update type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct<FDTFluxTeamStatusUpdate>(RawMessage, &OutStatusUpdate))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse status-update JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed status update for bib %d"), OutStatusUpdate.Bib);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseSplitSensorResponse(TArray<FDTFluxSplitSensorInfo>& OutSplitSensorInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ValidateResponseType(TEXT("split-sensor")))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Response is not a split-sensor type"));
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::InvalidType;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FDTFluxSplitSensorResponse SplitSensorResponse;
|
|
|
|
|
|
if (!FJsonObjectConverter::JsonObjectStringToUStruct(RawMessage, &SplitSensorResponse))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse split-sensor JSON: %s"), *RawMessage);
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::JsonParseError;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OutSplitSensorInfos.Empty();
|
|
|
|
|
|
for (const auto& SplitSensorInfoResponse : SplitSensorResponse.Datas)
|
|
|
|
|
|
{
|
|
|
|
|
|
FDTFluxSplitSensorInfo NewSplitSensorInfo;
|
|
|
|
|
|
NewSplitSensorInfo.Bib = SplitSensorInfoResponse.Bib;
|
|
|
|
|
|
NewSplitSensorInfo.ContestId = SplitSensorInfoResponse.ContestID;
|
|
|
|
|
|
NewSplitSensorInfo.StageId = SplitSensorInfoResponse.StageID;
|
|
|
|
|
|
NewSplitSensorInfo.SplitId = SplitSensorInfoResponse.SplitID;
|
|
|
|
|
|
NewSplitSensorInfo.Time = SplitSensorInfoResponse.Time;
|
|
|
|
|
|
|
|
|
|
|
|
OutSplitSensorInfos.Add(NewSplitSensorInfo);
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Verbose, TEXT("Split sensor info for bib %d in Contest %d, Stage %d, Split %d"),
|
|
|
|
|
|
NewSplitSensorInfo.Bib, NewSplitSensorInfo.ContestId, NewSplitSensorInfo.StageId,
|
|
|
|
|
|
NewSplitSensorInfo.SplitId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("Successfully parsed %d split sensor entries"), OutSplitSensorInfos.Num());
|
|
|
|
|
|
ParsingStatus = EDTFluxResponseStatus::Success;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FDTFluxServerResponse::ShowDebug(const bool bShouldPrintRawMessage) const
|
|
|
|
|
|
{
|
|
|
|
|
|
FString DebugMsg = FString::Printf(
|
|
|
|
|
|
TEXT("DTFluxServerResponse[Type=%s, Code=%d, Contest=%d, Stage=%d, Split=%d, ReceivedAt=%s]"),
|
|
|
|
|
|
*Type, Code, ContestID, StageID, SplitID, *ReceivedAt.ToString());
|
|
|
|
|
|
if (bShouldPrintRawMessage)
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Log, TEXT("%s\nRawMessage: \"%s\""), *DebugMsg, *RawMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// === MÉTHODES PRIVÉES ===
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ParseJsonObject(TSharedPtr<FJsonObject>& OutJsonObject) const
|
|
|
|
|
|
{
|
|
|
|
|
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(RawMessage);
|
|
|
|
|
|
|
|
|
|
|
|
if (!FJsonSerializer::Deserialize(Reader, OutJsonObject) || !OutJsonObject.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Failed to parse JSON: %s"), *RawMessage);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FDTFluxServerResponse::ValidateResponseType(const FString& ExpectedType) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!IsValidResponse())
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Invalid server response: Code=%d, Message=%s"), Code, *Message);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ContainsDataType(ExpectedType))
|
|
|
|
|
|
{
|
|
|
|
|
|
UE_LOG(logDTFluxNetwork, Error, TEXT("Expected type '%s' but got '%s'"), *ExpectedType, *Type);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|