Files
UnrealEngine/Engine/Source/Programs/Shared/EpicGames.Horde/Artifacts/HttpArtifactCollection.cs
2025-05-18 13:04:45 +08:00

164 lines
6.6 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using EpicGames.Horde.Commits;
using EpicGames.Horde.Storage;
using EpicGames.Horde.Storage.Nodes;
using EpicGames.Horde.Streams;
namespace EpicGames.Horde.Artifacts
{
class HttpArtifactCollection : IArtifactCollection
{
[DebuggerDisplay("{Id}")]
class Artifact : IArtifact
{
readonly HttpArtifactCollection _collection;
public Artifact(HttpArtifactCollection collection, GetArtifactResponse response)
: this(collection, response.Id, response.Name, response.Type, response.Description, response.StreamId, response.CommitId, response.Keys, response.Metadata, response.NamespaceId, response.RefName, response.CreatedAtUtc)
{ }
public Artifact(HttpArtifactCollection collection, ArtifactId id, ArtifactName name, ArtifactType type, string? description, StreamId streamId, CommitIdWithOrder commitId, IReadOnlyList<string> keys, IReadOnlyList<string> metadata, NamespaceId namespaceId, RefName refName, DateTime createdAtUtc)
{
_collection = collection;
Id = id;
Name = name;
Type = type;
Description = description;
StreamId = streamId;
CommitId = commitId;
Keys = keys;
Metadata = metadata;
NamespaceId = namespaceId;
RefName = refName;
CreatedAtUtc = createdAtUtc;
}
public ArtifactId Id { get; }
public ArtifactName Name { get; }
public ArtifactType Type { get; }
public string? Description { get; }
public StreamId StreamId { get; }
public CommitIdWithOrder CommitId { get; }
public IReadOnlyList<string> Keys { get; }
public IReadOnlyList<string> Metadata { get; }
public NamespaceId NamespaceId { get; }
public RefName RefName { get; }
public DateTime CreatedAtUtc { get; }
public IBlobRef<DirectoryNode> Content
=> _collection.Open(this);
public Task DeleteAsync(CancellationToken cancellationToken)
=> _collection.DeleteAsync(Id, cancellationToken);
}
class ArtifactBuilder : IArtifactBuilder
{
record class AliasInfo(string Name, IBlobRef BlobRef, int Rank, ReadOnlyMemory<byte> Data);
readonly Artifact _artifact;
readonly CreateArtifactResponse _response;
readonly IStorageNamespace _namespace;
readonly List<AliasInfo> _aliases = new List<AliasInfo>();
public ArtifactId Id => _artifact.Id;
public ArtifactName Name => _artifact.Name;
public ArtifactType Type => _artifact.Type;
public string? Description => _artifact.Description;
public StreamId StreamId => _artifact.StreamId;
public CommitIdWithOrder CommitId => _artifact.CommitId;
public IReadOnlyList<string> Keys => _artifact.Keys;
public IReadOnlyList<string> Metadata => _artifact.Metadata;
public NamespaceId NamespaceId => _artifact.NamespaceId;
public RefName RefName => _artifact.RefName;
public ArtifactBuilder(HttpArtifactCollection collection, Artifact artifact, CreateArtifactResponse response)
{
_artifact = artifact;
_response = response;
_namespace = collection._hordeClient.GetStorageNamespace(response.NamespaceId, response.Token);
}
/// <inheritdoc/>
public Task AddAliasAsync(string name, IBlobRef handle, int rank = 0, ReadOnlyMemory<byte> data = default, CancellationToken cancellationToken = default)
{
_aliases.Add(new AliasInfo(name, handle, rank, data.ToArray()));
return Task.CompletedTask;
}
/// <inheritdoc/>
public async Task<IArtifact> CompleteAsync(IHashedBlobRef blobRef, CancellationToken cancellationToken = default)
{
await using (IStorageWriter writer = _namespace.CreateWriter(cancellationToken))
{
foreach (AliasInfo aliasInfo in _aliases)
{
await writer.AddAliasAsync(aliasInfo.Name, aliasInfo.BlobRef, aliasInfo.Rank, aliasInfo.Data, cancellationToken);
}
await writer.AddRefAsync(_artifact.RefName, blobRef, cancellationToken: cancellationToken);
}
return _artifact;
}
/// <inheritdoc/>
public IBlobWriter CreateBlobWriter()
=> _namespace.CreateBlobWriter(_response.RefName);
}
readonly IHordeClient _hordeClient;
public HttpArtifactCollection(IHordeClient hordeClient)
=> _hordeClient = hordeClient;
IBlobRef<DirectoryNode> Open(Artifact artifact)
{
IStorageNamespace store = _hordeClient.GetStorageNamespace(artifact.Id);
return store.CreateBlobRef<DirectoryNode>(new RefName("default"));
}
/// <inheritdoc/>
public async Task<IArtifactBuilder> CreateAsync(ArtifactName name, ArtifactType type, string? description, StreamId streamId, CommitId commitId, IEnumerable<string> keys, IEnumerable<string> metadata, CancellationToken cancellationToken = default)
{
HordeHttpClient hordeHttpClient = _hordeClient.CreateHttpClient();
CreateArtifactResponse response = await hordeHttpClient.CreateArtifactAsync(name, type, description, streamId, commitId, keys, metadata, cancellationToken);
Artifact artifact = new Artifact(this, response.ArtifactId, name, type, description, streamId, CommitIdWithOrder.FromPerforceChange(commitId.GetPerforceChange()), keys.ToList(), metadata.ToList(), response.NamespaceId, response.RefName, DateTime.UtcNow);
return new ArtifactBuilder(this, artifact, response);
}
/// <inheritdoc/>
public async IAsyncEnumerable<IArtifact> FindAsync(ArtifactId[]? ids = null, StreamId? streamId = null, CommitId? minCommitId = null, CommitId? maxCommitId = null, ArtifactName? name = null, ArtifactType? type = null, IEnumerable<string>? keys = null, int maxResults = 100, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
HordeHttpClient hordeHttpClient = _hordeClient.CreateHttpClient();
List<GetArtifactResponse> responses = await hordeHttpClient.FindArtifactsAsync(ids, streamId, minCommitId, maxCommitId, name, type, keys, maxResults, cancellationToken);
foreach (GetArtifactResponse response in responses)
{
yield return new Artifact(this, response);
}
}
async Task DeleteAsync(ArtifactId artifactId, CancellationToken cancellationToken = default)
{
HordeHttpClient hordeHttpClient = _hordeClient.CreateHttpClient();
await hordeHttpClient.DeleteArtifactAsync(artifactId, cancellationToken);
}
/// <inheritdoc/>
public async Task<IArtifact?> GetAsync(ArtifactId artifactId, CancellationToken cancellationToken = default)
{
HordeHttpClient hordeHttpClient = _hordeClient.CreateHttpClient();
GetArtifactResponse? response = await hordeHttpClient.GetArtifactAsync(artifactId, cancellationToken);
return new Artifact(this, response);
}
}
}