61 lines
2.5 KiB
C#
61 lines
2.5 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using StellaOps.Signals.Options;
|
|
using StellaOps.Signals.Storage.Models;
|
|
|
|
namespace StellaOps.Signals.Storage;
|
|
|
|
/// <summary>
|
|
/// Stores callgraph artifacts on the local filesystem.
|
|
/// </summary>
|
|
internal sealed class FileSystemCallgraphArtifactStore : ICallgraphArtifactStore
|
|
{
|
|
private readonly SignalsArtifactStorageOptions storageOptions;
|
|
private readonly ILogger<FileSystemCallgraphArtifactStore> logger;
|
|
|
|
public FileSystemCallgraphArtifactStore(IOptions<SignalsOptions> options, ILogger<FileSystemCallgraphArtifactStore> logger)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(options);
|
|
storageOptions = options.Value.Storage;
|
|
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
public async Task<StoredCallgraphArtifact> SaveAsync(CallgraphArtifactSaveRequest request, Stream content, CancellationToken cancellationToken)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(request);
|
|
ArgumentNullException.ThrowIfNull(content);
|
|
|
|
var root = storageOptions.RootPath;
|
|
var directory = Path.Combine(root, Sanitize(request.Language), Sanitize(request.Component), Sanitize(request.Version));
|
|
Directory.CreateDirectory(directory);
|
|
|
|
var fileName = string.IsNullOrWhiteSpace(request.FileName)
|
|
? FormattableString.Invariant($"artifact-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}.bin")
|
|
: request.FileName.Trim();
|
|
|
|
var destinationPath = Path.Combine(directory, fileName);
|
|
|
|
await using (var fileStream = File.Create(destinationPath))
|
|
{
|
|
await content.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
var fileInfo = new FileInfo(destinationPath);
|
|
logger.LogInformation("Stored callgraph artifact at {Path} (length={Length}).", destinationPath, fileInfo.Length);
|
|
|
|
return new StoredCallgraphArtifact(
|
|
Path.GetRelativePath(root, destinationPath),
|
|
fileInfo.Length,
|
|
request.Hash,
|
|
request.ContentType);
|
|
}
|
|
|
|
private static string Sanitize(string value)
|
|
=> string.Join('_', value.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)).ToLowerInvariant();
|
|
}
|