FORCEINLINE FString BuildJsonStrFromMap(TMap<FString, FString> Map) { FString JsonStr; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&JsonStr); // Close the writer and finalize the output such that JsonStr has what we want TArray<FString> keys; Map.GetKeys(keys); JsonWriter->WriteObjectStart(); for (int32 k = 0; k < Map.Num(); k++) { JsonWriter->WriteValue(keys[k], Map[keys[k]]); } JsonWriter->WriteObjectEnd(); JsonWriter->Close(); return JsonStr; }
bool FPluginHelpers::SavePluginDescriptor(const FString& NewProjectFilename, const FPluginDescriptor& PluginDescriptor) { FString Text; TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&Text); Writer->WriteObjectStart(); // Write all the simple fields Writer->WriteValue(TEXT("FileVersion"), PluginDescriptor.FileVersion); Writer->WriteValue(TEXT("FriendlyName"), PluginDescriptor.FriendlyName); Writer->WriteValue(TEXT("Version"), PluginDescriptor.Version); Writer->WriteValue(TEXT("VersionName"), PluginDescriptor.VersionName); Writer->WriteValue(TEXT("CreatedBy"), PluginDescriptor.CreatedBy); Writer->WriteValue(TEXT("CreatedByURL"), PluginDescriptor.CreatedByURL); Writer->WriteValue(TEXT("Category"), PluginDescriptor.Category); Writer->WriteValue(TEXT("Description"), PluginDescriptor.Description); Writer->WriteValue(TEXT("EnabledByDefault"), PluginDescriptor.bEnabledByDefault); // Write the module list FModuleDescriptor::WriteArray(Writer.Get(), TEXT("Modules"), PluginDescriptor.Modules); Writer->WriteObjectEnd(); Writer->Close(); return FFileHelper::SaveStringToFile(Text, *NewProjectFilename); }
void FMultiBoxCustomizationData::SaveCustomizedBlocks() { FString SaveData; TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &SaveData ); Writer->WriteObjectStart(); Writer->WriteArrayStart(TEXT("CustomBlocks")); for (TArray<FCustomBlockTransaction>::TConstIterator It(Transactions); It; ++It) { const FCustomBlockTransaction& Transaction = *It; if( Transaction.Command.IsValid() ) { const FUICommandInfo& Command = *Transaction.Command.Pin(); Writer->WriteObjectStart(); Writer->WriteValue(TEXT("CommandName"), Command.GetCommandName().ToString() ); Writer->WriteValue(TEXT("Context"), Command.GetBindingContext().ToString() ); Writer->WriteValue(TEXT("Index"), (float)Transaction.BlockIndex ); Writer->WriteValue(TEXT("TransactionType"), (float)Transaction.TransactionType ); Writer->WriteObjectEnd(); } } Writer->WriteArrayEnd(); Writer->WriteObjectEnd(); Writer->Close(); GConfig->SetString( *GetConfigSectionName(), *CustomizationName.ToString(), *FRemoteConfig::ReplaceIniCharWithSpecialChar(SaveData).ReplaceCharWithEscapedChar(), GEditorPerProjectIni ); }
bool UFlareSaveGameSystem::SaveGame(const FString SaveName, UFlareSaveGame* SaveData) { bool ret = false; SaveLock.Lock(); FLOGV("UFlareSaveGameSystem::SaveGame SaveName=%s", *SaveName); UFlareSaveWriter* SaveWriter = NewObject<UFlareSaveWriter>(this, UFlareSaveWriter::StaticClass()); TSharedRef<FJsonObject> JsonObject = SaveWriter->SaveGame(SaveData); // Save the json object FString FileContents; //TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&FileContents); TSharedRef< TJsonWriter<> > JsonWriter = TJsonWriterFactory<>::Create(&FileContents); if (FJsonSerializer::Serialize(JsonObject, JsonWriter)) { JsonWriter->Close(); ret = FFileHelper::SaveStringToFile(FileContents, *GetSaveGamePath(SaveName)); FLOG("UFlareSaveGameSystem::SaveGame : Save done"); } else { FLOGV("Fail to serialize save %s", *SaveName); ret = false; } SaveLock.Unlock(); return ret; }
bool UStructToJsonObjectStringInternal(const TSharedRef<FJsonObject>& JsonObject, FString& OutJsonString, int32 Indent) { TSharedRef<TJsonWriter<CharType, PrintPolicy> > JsonWriter = TJsonWriterFactory<CharType, PrintPolicy>::Create(&OutJsonString, Indent); bool bSuccess = FJsonSerializer::Serialize(JsonObject, JsonWriter); JsonWriter->Close(); return bSuccess; }
void AHttpRequestCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location) { if (FingerIndex == ETouchIndex::Touch1) { /* Added for HTTP requests */ // Create a writer and hold it in this FString FString JsonStr; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&JsonStr); JsonWriter->WriteObjectStart(); JsonWriter->WriteValue(TEXT("user"), TEXT("StormUnited")); JsonWriter->WriteObjectEnd(); // Close the writer and finalize the output such that JsonStr has what we want JsonWriter->Close(); TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json; charset=utf-8")); HttpRequest->SetURL(TEXT("http://localhost/configuration")); HttpRequest->SetVerb(TEXT("POST")); HttpRequest->SetContentAsString(JsonStr); HttpRequest->OnProcessRequestComplete().BindUObject(this, HttpCompleteCallback); HttpRequest->ProcessRequest(); /* Added for HTTP requests */ StopJumping(); } }
FORCEINLINE FString UserRequestJson() { FString JsonStr; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&JsonStr); JsonWriter->WriteObjectStart(); JsonWriter->WriteValue(TEXT("devicetype"), TEXT("pc#ue4hue")); JsonWriter->WriteObjectEnd(); JsonWriter->Close(); return JsonStr; }
void UPhilipsHueBridge::SetLightBrightnessByGroupID(const int32 GroupID, const float Brightness) { int32 Bri = (int32)(255.f*Brightness); FString JsonStr; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&JsonStr); JsonWriter->WriteObjectStart(); JsonWriter->WriteValue(TEXT("bri"), Bri); JsonWriter->WriteObjectEnd(); JsonWriter->Close(); SetLightGroupActionByIDRaw(0, JsonStr); }
bool UFlareSaveGameSystem::SaveGame(const FString SaveName, UFlareSaveGame* SaveData) { bool ret = false; SaveLock.Lock(); FLOGV("UFlareSaveGameSystem::SaveGame SaveName=%s", *SaveName); UFlareSaveWriter* SaveWriter = NewObject<UFlareSaveWriter>(this, UFlareSaveWriter::StaticClass()); TSharedRef<FJsonObject> JsonObject = SaveWriter->SaveGame(SaveData); // Save the json object FString FileContents; //TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&FileContents); TSharedRef< TJsonWriter<> > JsonWriter = TJsonWriterFactory<>::Create(&FileContents); if (FJsonSerializer::Serialize(JsonObject, JsonWriter)) { JsonWriter->Close(); bool Compress = true; if(Compress) { uint32 StrLength = FCStringAnsi::Strlen(TCHAR_TO_UTF8(*FileContents)); uint8* CompressedDataRaw = new uint8[StrLength]; int32 CompressedSize = StrLength; const bool bResult = FCompression::CompressMemory((ECompressionFlags)(COMPRESS_GZIP), CompressedDataRaw, CompressedSize, TCHAR_TO_UTF8(*FileContents), StrLength); if (bResult) { ret = FFileHelper::SaveArrayToFile(TArrayView<const uint8>(CompressedDataRaw, CompressedSize), *GetSaveGamePath(SaveName, true)); } delete[] CompressedDataRaw; } else { ret = FFileHelper::SaveStringToFile(FileContents, *GetSaveGamePath(SaveName, false)); } FLOG("UFlareSaveGameSystem::SaveGame : Save done"); } else { FLOGV("Fail to serialize save %s", *SaveName); ret = false; } SaveLock.Unlock(); SaveListLock.Lock(); SaveList.Remove(SaveData); SaveListLock.Unlock(); return ret; }
bool FJsonObjectConverter::UStructToJsonObjectString(const UStruct* StructDefinition, const void* Struct, FString& OutJsonString, int64 CheckFlags, int64 SkipFlags, int32 Indent) { TSharedRef<FJsonObject> JsonObject = MakeShareable( new FJsonObject() ); if (UStructToJsonObject(StructDefinition, Struct, JsonObject, CheckFlags, SkipFlags)) { TSharedRef<TJsonWriter<> > JsonWriter = TJsonWriterFactory<>::Create(&OutJsonString, Indent); if (FJsonSerializer::Serialize( JsonObject, JsonWriter )) { JsonWriter->Close(); return true; } else { UE_LOG(LogJson, Warning, TEXT("UStructToJsonObjectString - Unable to write out json")); JsonWriter->Close(); } } return false; }
void FLauncherProfileManager::SaveSimpleProfiles() { for (TArray<ILauncherSimpleProfilePtr>::TIterator It(SimpleProfiles); It; ++It) { FString SimpleProfileFileName = FLauncherProfile::GetProfileFolder() / (*It)->GetDeviceName() + TEXT(".uslp"); FString Text; TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&Text); (*It)->Save(Writer.Get()); Writer->Close(); FFileHelper::SaveStringToFile(Text, *SimpleProfileFileName); } }
bool FLauncherProfileManager::SaveJSONProfile(const ILauncherProfileRef& Profile) { if (Profile->GetId().IsValid()) { FString Text; TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&Text); Profile->Save(Writer.Get()); Writer->Close(); return FFileHelper::SaveStringToFile(Text, *Profile->GetFilePath()); } return false; }
FString UCurveTable::GetTableAsJSON() const { // use the pretty print policy since these values are usually getting dumpped for check-in to P4 (or for inspection) FString Result; TSharedRef< TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR> >::Create(&Result); if (!WriteTableAsJSON(JsonWriter)) { return TEXT("No data in row curve!\n"); } JsonWriter->Close(); return Result; }
void UPhilipsHueBridge::SetLightColorByLightID(const int32 LightID, const FLinearColor InColor) { FVector2D xy = ColorToxy(InColor); FString JsonStr; TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&JsonStr); FString str = "[" + FString::SanitizeFloat(xy.X) + "," + FString::SanitizeFloat(xy.Y) + "]"; JsonWriter->WriteObjectStart(); JsonWriter->WriteRawJSONValue(TEXT("xy"), str); JsonWriter->WriteObjectEnd(); JsonWriter->Close(); SetLightStateByLightIDRaw(LightID, JsonStr); }
bool FInternationalizationManifestJsonSerializer::SerializeManifest( TSharedRef< const FInternationalizationManifest > Manifest, FString& Str ) { TSharedRef< FJsonObject > JsonManifestObj = MakeShareable( new FJsonObject ); bool bExecSuccessful = SerializeInternal( Manifest, JsonManifestObj ); if(bExecSuccessful) { TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &Str ); bExecSuccessful = FJsonSerializer::Serialize(JsonManifestObj, Writer); Writer->Close(); } return bExecSuccessful; }
bool FJsonInternationalizationArchiveSerializer::SerializeArchive( TSharedRef< const FInternationalizationArchive > InternationalizationArchive, FString& Str ) { TSharedRef< FJsonObject > JsonArchiveObj = MakeShareable( new FJsonObject ); bool bExecSuccessful = SerializeInternal( InternationalizationArchive, JsonArchiveObj ); if( bExecSuccessful ) { TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &Str ); bExecSuccessful = FJsonSerializer::Serialize( JsonArchiveObj, Writer ); Writer->Close(); } return bExecSuccessful; }
bool FProjectDescriptor::Save(const FString& FileName, FText& OutFailReason) { // Write the contents of the descriptor to a string. Make sure the writer is destroyed so that the contents are flushed to the string. FString Text; TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&Text); Write(Writer.Get()); Writer->Close(); // Save it to a file if ( FFileHelper::SaveStringToFile(Text, *FileName) ) { return true; } else { OutFailReason = FText::Format( LOCTEXT("FailedToWriteOutputFile", "Failed to write output file '{0}'. Perhaps the file is Read-Only?"), FText::FromString(FileName) ); return false; } }
/** * Posts the current request data to the internet * * @param WorldContextObject The current context * @param url The URL to post to * */ void UJsonFieldData::PostRequest(UObject* WorldContextObject, const FString &url) { FString outStr; TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<TCHAR>::Create(&outStr); // Start writing the response WriteObject(JsonWriter, "", new FJsonValueObject(Data)); JsonWriter->Close(); // Log the post data for the user (OPTIONAL) UE_LOG(LogTemp, Warning, TEXT("Post data: %s"), *outStr); // Create the post request with the generated data TSharedRef< IHttpRequest > HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetVerb("POST"); HttpRequest->SetURL(CreateURL(url)); HttpRequest->SetHeader("Content-Type", "application/json"); HttpRequest->SetContentAsString(outStr); HttpRequest->OnProcessRequestComplete().BindUObject(this, &UJsonFieldData::OnReady); // Execute the request HttpRequest->ProcessRequest(); }
FString FPerfCounters::ToJson() const { FString JsonStr; TSharedRef< TJsonWriter<> > Json = TJsonWriterFactory<>::Create(&JsonStr); Json->WriteObjectStart(); for (const auto& It : PerfCounterMap) { const FJsonVariant& JsonValue = It.Value; switch (JsonValue.Format) { case FJsonVariant::String: Json->WriteValue(It.Key, JsonValue.StringValue); break; case FJsonVariant::Number: Json->WriteValue(It.Key, JsonValue.NumberValue); break; case FJsonVariant::Callback: if (JsonValue.CallbackValue.IsBound()) { Json->WriteIdentifierPrefix(It.Key); JsonValue.CallbackValue.Execute(Json); } else { // write an explict null since the callback is unbound and the implication is this would have been an object Json->WriteNull(It.Key); } break; case FJsonVariant::Null: default: // don't write anything since wash may expect a scalar break; } } Json->WriteObjectEnd(); Json->Close(); return JsonStr; }
FString FJsonInternationalizationMetaDataSerializer::MetadataToString( const TSharedPtr<FLocMetadataObject> Metadata ) { FString StringMetadata = TEXT(""); if( Metadata.IsValid() ) { TSharedPtr< FJsonObject > JsonKeyMetadata; FJsonInternationalizationMetaDataSerializer::SerializeMetadata( Metadata.ToSharedRef(), JsonKeyMetadata ); if( JsonKeyMetadata.IsValid() ) { JsonKeyMetadata->Values.KeySort( TLess<FString>() ); TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &StringMetadata ); FJsonSerializer::Serialize( JsonKeyMetadata.ToSharedRef(), Writer ); Writer->Close(); StringMetadata.ReplaceInline( TEXT("\t"), TEXT(" ") ); StringMetadata.ReplaceInline( TEXT("\r\n"), TEXT(" ") ); StringMetadata.ReplaceInline( TEXT("\n"), TEXT(" ") ); } } return StringMetadata; }
void FAnalyticsProviderET::FlushEvents() { // Make sure we don't try to flush too many times. When we are not caching events it's possible this can be called when there are no events in the array. if (CachedEvents.Num() == 0) { return; } // There are much better ways to do this, but since most events are recorded and handled on the same (game) thread, // this is probably mostly fine for now, and simply favoring not crashing at the moment FScopeLock ScopedLock(&CachedEventsCS); if(ensure(FModuleManager::Get().IsModuleLoaded("HTTP"))) { FString Payload; FDateTime CurrentTime = FDateTime::UtcNow(); if (!UseLegacyProtocol) { TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&Payload); JsonWriter->WriteObjectStart(); JsonWriter->WriteArrayStart(TEXT("Events")); for (int32 EventIdx = 0; EventIdx < CachedEvents.Num(); EventIdx++) { const FAnalyticsEventEntry& Entry = CachedEvents[EventIdx]; // event entry JsonWriter->WriteObjectStart(); JsonWriter->WriteValue(TEXT("EventName"), Entry.EventName); FString DateOffset = (CurrentTime - Entry.TimeStamp).ToString(); JsonWriter->WriteValue(TEXT("DateOffset"), DateOffset); JsonWriter->WriteValue(TEXT("IsEditor"), FString::FromInt(GIsEditor)); if (Entry.Attributes.Num() > 0) { // optional attributes for this event for (int32 AttrIdx = 0; AttrIdx < Entry.Attributes.Num(); AttrIdx++) { const FAnalyticsEventAttribute& Attr = Entry.Attributes[AttrIdx]; JsonWriter->WriteValue(Attr.AttrName, Attr.AttrValue); } } JsonWriter->WriteObjectEnd(); } JsonWriter->WriteArrayEnd(); JsonWriter->WriteObjectEnd(); JsonWriter->Close(); FString URLPath = FString::Printf(TEXT("datarouter/api/v1/public/data?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&AppEnvironment=%s&UploadType=%s"), *FPlatformHttp::UrlEncode(SessionID), *FPlatformHttp::UrlEncode(APIKey), *FPlatformHttp::UrlEncode(AppVersion), *FPlatformHttp::UrlEncode(UserID), *FPlatformHttp::UrlEncode(AppEnvironment), *FPlatformHttp::UrlEncode(UploadType)); // Recreate the URLPath for logging because we do not want to escape the parameters when logging. // We cannot simply UrlEncode the entire Path after logging it because UrlEncode(Params) != UrlEncode(Param1) & UrlEncode(Param2) ... FString LogString = FString::Printf(TEXT("[%s] AnalyticsET URL:datarouter/api/v1/public/data?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&AppEnvironment=%s&UploadType=%s. Payload:%s"), *APIKey, *SessionID, *APIKey, *AppVersion, *UserID, *AppEnvironment, *UploadType, *Payload); UE_LOG(LogAnalytics, VeryVerbose, TEXT("%s"), *LogString); // Duplicate the same log message with a separate category. This is used as an "last chance" backup on the servers in the unlikely case // if the backend lost the events due to overload - then we can scrape the logs manually for them. UE_LOG(LogAnalyticsDumpEventPayload, Log, TEXT("%s"), *LogString); // Create/send Http request for an event TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json; charset=utf-8")); HttpRequest->SetURL(APIServer + URLPath); HttpRequest->SetVerb(TEXT("POST")); HttpRequest->SetContentAsString(Payload); // Don't set a response callback if we are in our destructor, as the instance will no longer be there to call. if (!bInDestructor) { HttpRequest->OnProcessRequestComplete().BindSP(this, &FAnalyticsProviderET::EventRequestComplete); } HttpRequest->ProcessRequest(); } else { // this is a legacy pathway that doesn't accept batch payloads of cached data. We'll just send one request for each event, which will be slow for a large batch of requests at once. for (const auto& Event : CachedEvents) { FString EventParams; if (Event.Attributes.Num() > 0) { for (int Ndx = 0; Ndx<FMath::Min(Event.Attributes.Num(), 40); ++Ndx) { EventParams += FString::Printf(TEXT("&AttributeName%d=%s&AttributeValue%d=%s"), Ndx, *FPlatformHttp::UrlEncode(Event.Attributes[Ndx].AttrName), Ndx, *FPlatformHttp::UrlEncode(Event.Attributes[Ndx].AttrValue)); } } // log out the un-encoded values to make reading the log easier. UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] AnalyticsET URL:SendEvent.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&EventName=%s%s"), *APIKey, *SessionID, *APIKey, *AppVersion, *UserID, *Event.EventName, *EventParams); // Create/send Http request for an event TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("text/plain")); // Don't need to URL encode the APIServer or the EventParams, which are already encoded, and contain parameter separaters that we DON'T want encoded. HttpRequest->SetURL(FString::Printf(TEXT("%sSendEvent.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&EventName=%s%s"), *APIServer, *FPlatformHttp::UrlEncode(SessionID), *FPlatformHttp::UrlEncode(APIKey), *FPlatformHttp::UrlEncode(AppVersion), *FPlatformHttp::UrlEncode(UserID), *FPlatformHttp::UrlEncode(Event.EventName), *EventParams)); HttpRequest->SetVerb(TEXT("GET")); HttpRequest->OnProcessRequestComplete().BindRaw(this, &FAnalyticsProviderET::EventRequestComplete); HttpRequest->ProcessRequest(); } } FlushEventsCountdown = MaxCachedElapsedTime; CachedEvents.Empty(); } }
void FBuildPatchAppManifest::SerializeToJSON(FString& JSONOutput) { #if UE_BUILD_DEBUG // We'll use this to switch between human readable JSON TSharedRef< TJsonWriter< TCHAR, TPrettyJsonPrintPolicy< TCHAR > > > Writer = TJsonWriterFactory< TCHAR, TPrettyJsonPrintPolicy< TCHAR > >::Create(&JSONOutput); #else TSharedRef< TJsonWriter< TCHAR, TCondensedJsonPrintPolicy< TCHAR > > > Writer = TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy< TCHAR > >::Create(&JSONOutput); #endif //ALLOW_DEBUG_FILES Writer->WriteObjectStart(); { // Write general data Writer->WriteValue(TEXT("ManifestFileVersion"), ToStringBlob(static_cast<int32>(Data->ManifestFileVersion))); Writer->WriteValue(TEXT("bIsFileData"), Data->bIsFileData); Writer->WriteValue(TEXT("AppID"), ToStringBlob(Data->AppID)); Writer->WriteValue(TEXT("AppNameString"), Data->AppName); Writer->WriteValue(TEXT("BuildVersionString"), Data->BuildVersion); Writer->WriteValue(TEXT("LaunchExeString"), Data->LaunchExe); Writer->WriteValue(TEXT("LaunchCommand"), Data->LaunchCommand); Writer->WriteValue(TEXT("PrereqName"), Data->PrereqName); Writer->WriteValue(TEXT("PrereqPath"), Data->PrereqPath); Writer->WriteValue(TEXT("PrereqArgs"), Data->PrereqArgs); // Write file manifest data Writer->WriteArrayStart(TEXT("FileManifestList")); for (const auto& FileManifest : Data->FileManifestList) { Writer->WriteObjectStart(); { Writer->WriteValue(TEXT("Filename"), FileManifest.Filename); Writer->WriteValue(TEXT("FileHash"), FString::FromBlob(FileManifest.FileHash.Hash, FSHA1::DigestSize)); if (FileManifest.bIsUnixExecutable) { Writer->WriteValue(TEXT("bIsUnixExecutable"), FileManifest.bIsUnixExecutable); } if (FileManifest.bIsReadOnly) { Writer->WriteValue(TEXT("bIsReadOnly"), FileManifest.bIsReadOnly); } if (FileManifest.bIsCompressed) { Writer->WriteValue(TEXT("bIsCompressed"), FileManifest.bIsCompressed); } const bool bIsSymlink = !FileManifest.SymlinkTarget.IsEmpty(); if (bIsSymlink) { Writer->WriteValue(TEXT("SymlinkTarget"), FileManifest.SymlinkTarget); } else { Writer->WriteArrayStart(TEXT("FileChunkParts")); { for (const auto& FileChunkPart : FileManifest.FileChunkParts) { Writer->WriteObjectStart(); { Writer->WriteValue(TEXT("Guid"), FileChunkPart.Guid.ToString()); Writer->WriteValue(TEXT("Offset"), ToStringBlob(FileChunkPart.Offset)); Writer->WriteValue(TEXT("Size"), ToStringBlob(FileChunkPart.Size)); } Writer->WriteObjectEnd(); } } Writer->WriteArrayEnd(); } } Writer->WriteObjectEnd(); } Writer->WriteArrayEnd(); // Write chunk hash list Writer->WriteObjectStart(TEXT("ChunkHashList")); for (const auto& ChunkInfo : Data->ChunkList) { const FGuid& ChunkGuid = ChunkInfo.Guid; const uint64& ChunkHash = ChunkInfo.Hash; Writer->WriteValue(ChunkGuid.ToString(), ToStringBlob(ChunkHash)); } Writer->WriteObjectEnd(); // Write data group list Writer->WriteObjectStart(TEXT("DataGroupList")); for (const auto& ChunkInfo : Data->ChunkList) { const FGuid& DataGuid = ChunkInfo.Guid; const uint8& DataGroup = ChunkInfo.GroupNumber; Writer->WriteValue(DataGuid.ToString(), ToStringBlob(DataGroup)); } Writer->WriteObjectEnd(); // Write chunk size list Writer->WriteObjectStart(TEXT("ChunkFilesizeList")); for (const auto& ChunkInfo : Data->ChunkList) { const FGuid& ChunkGuid = ChunkInfo.Guid; const int64& ChunkSize = ChunkInfo.FileSize; Writer->WriteValue(ChunkGuid.ToString(), ToStringBlob(ChunkSize)); } Writer->WriteObjectEnd(); // Write custom fields Writer->WriteObjectStart(TEXT("CustomFields")); for (const auto& CustomField : Data->CustomFields) { Writer->WriteValue(CustomField.Key, CustomField.Value); } Writer->WriteObjectEnd(); } Writer->WriteObjectEnd(); Writer->Close(); }
void FAnalyticsProviderET::FlushEvents() { // Make sure we don't try to flush too many times. When we are not caching events it's possible this can be called when there are no events in the array. if (CachedEvents.Num() == 0) { return; } // There are much better ways to do this, but since most events are recorded and handled on the same (game) thread, // this is probably mostly fine for now, and simply favoring not crashing at the moment FScopeLock ScopedLock(&CachedEventsCS); if(ensure(FModuleManager::Get().IsModuleLoaded("HTTP"))) { FString Payload; FDateTime CurrentTime = FDateTime::UtcNow(); TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&Payload); JsonWriter->WriteObjectStart(); JsonWriter->WriteArrayStart(TEXT("Events")); for (int32 EventIdx = 0; EventIdx < CachedEvents.Num(); EventIdx++) { const FAnalyticsEventEntry& Entry = CachedEvents[EventIdx]; // event entry JsonWriter->WriteObjectStart(); JsonWriter->WriteValue(TEXT("EventName"), Entry.EventName); FString DateOffset = (CurrentTime - Entry.TimeStamp).ToString(); JsonWriter->WriteValue(TEXT("DateOffset"), DateOffset); JsonWriter->WriteValue(TEXT("IsEditor"), FString::FromInt(GIsEditor)); if (Entry.Attributes.Num() > 0) { // optional attributes for this event for (int32 AttrIdx = 0; AttrIdx < Entry.Attributes.Num(); AttrIdx++) { const FAnalyticsEventAttribute& Attr = Entry.Attributes[AttrIdx]; JsonWriter->WriteValue(Attr.AttrName, Attr.AttrValue); } } JsonWriter->WriteObjectEnd(); } JsonWriter->WriteArrayEnd(); JsonWriter->WriteObjectEnd(); JsonWriter->Close(); FString URLPath = FString::Printf(TEXT("CollectData.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s"), *FGenericPlatformHttp::UrlEncode(SessionID), *FGenericPlatformHttp::UrlEncode(APIKey), *FGenericPlatformHttp::UrlEncode(AppVersion), *FGenericPlatformHttp::UrlEncode(UserID)); // Recreate the URLPath for logging because we do not want to escape the parameters when logging. // We cannot simply UrlEncode the entire Path after logging it because UrlEncode(Params) != UrlEncode(Param1) & UrlEncode(Param2) ... UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] AnalyticsET URL:CollectData.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s. Payload:%s"), *APIKey, *SessionID, *APIKey, *AppVersion, *UserID, *Payload); // Create/send Http request for an event TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json; charset=utf-8")); HttpRequest->SetURL(APIServer + URLPath); HttpRequest->SetVerb(TEXT("POST")); HttpRequest->SetContentAsString(Payload); // Don't set a response callback if we are in our destructor, as the instance will no longer be there to call. if (!bInDestructor) { HttpRequest->OnProcessRequestComplete().BindSP(this, &FAnalyticsProviderET::EventRequestComplete); } HttpRequest->ProcessRequest(); FlushEventsCountdown = MaxCachedElapsedTime; CachedEvents.Empty(); } }