// Copyright Epic Games, Inc. All Rights Reserved. using EpicGames.Horde; using EpicGames.Horde.Jobs; using EpicGames.Horde.Secrets; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http; using System.Threading; using System.Threading.Tasks; #nullable enable namespace AutomationTool { /// /// Helper methods for Horde functionality /// public partial class CommandUtils { static readonly ConcurrentDictionary> _cachedSecrets = new ConcurrentDictionary>(); /// /// Reads a secret from Horde /// /// Identifier of the secret to retrieve /// Cancellation token for the operation /// Values configured for the given secret public static async Task> GetHordeSecretAsync(SecretId secretId, CancellationToken cancellationToken = default) { IReadOnlyDictionary? secret; if (!_cachedSecrets.TryGetValue(secretId, out secret)) { IHordeClient hordeClient = ServiceProvider.GetRequiredService(); using HordeHttpClient hordeHttpClient = hordeClient.CreateHttpClient(); GetSecretResponse response; try { response = await hordeHttpClient.GetSecretAsync(secretId); } catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) { throw new AutomationException(ex, $"Secret '{secretId}' was not found on {hordeClient.ServerUrl}"); } catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden) { throw new AutomationException(ex, $"User does not have permissions to read '{secretId}' on {hordeClient.ServerUrl}"); } secret = response.Data; _cachedSecrets.TryAdd(secretId, secret); } return secret; } /// /// Reads a secret from Horde /// /// Identifier of the secret to retrieve /// Name of the property within the secret /// Cancellation token for the operation /// Values configured for the given secret public static async Task GetHordeSecretAsync(SecretId secretId, string propertyName, CancellationToken cancellationToken = default) { IReadOnlyDictionary secrets = await GetHordeSecretAsync(secretId, cancellationToken); if (!secrets.TryGetValue(propertyName, out string? propertyValue)) { throw new AutomationException("Secret '{secretId}' does not contain a value for '{propertyName}'"); } return propertyValue; } public static async Task AddHordeJobMetadata(JobId id, IEnumerable? jobMetaData = null, Dictionary>? stepMetaData = null, CancellationToken cancellationToken = default) { IHordeClient hordeClient = ServiceProvider.GetRequiredService(); using HordeHttpClient hordeHttpClient = hordeClient.CreateHttpClient(); bool bConnected = hordeHttpClient.CheckConnectionAsync(cancellationToken).Result; if (!bConnected) { Logger.LogWarning("No connection to the Horde Server when tagging job metadata"); return; } await hordeHttpClient.PutJobMetadataAsync(id, jobMetaData, stepMetaData, cancellationToken); } } }