in src/infra/docs-lambda-index-publisher/LinkIndexProvider.cs [18:80]
public class LinkIndexProvider(IAmazonS3 s3Client, ILambdaLogger logger, string bucketName, string key)
{
private string? _etag;
private LinkReferenceRegistry? _linkIndex;
private async Task<LinkReferenceRegistry> GetLinkIndex()
{
var getObjectRequest = new GetObjectRequest
{
BucketName = bucketName,
Key = key
};
logger.LogInformation("Getting link index from s3://{bucketName}/{key}", bucketName, key);
var getObjectResponse = await s3Client.GetObjectAsync(getObjectRequest);
await using var stream = getObjectResponse.ResponseStream;
_etag = getObjectResponse.ETag;
logger.LogInformation("Successfully got link index from s3://{bucketName}/{key}", bucketName, key);
_linkIndex = LinkReferenceRegistry.Deserialize(stream);
return _linkIndex;
}
public async Task UpdateLinkIndexEntry(LinkRegistryEntry linkRegistryEntry)
{
_linkIndex ??= await GetLinkIndex();
if (_linkIndex.Repositories.TryGetValue(linkRegistryEntry.Repository, out var existingEntry))
{
var newEntryIsNewer = DateTime.Compare(linkRegistryEntry.UpdatedAt, existingEntry[linkRegistryEntry.Branch].UpdatedAt) > 0;
if (newEntryIsNewer)
{
existingEntry[linkRegistryEntry.Branch] = linkRegistryEntry;
logger.LogInformation("Updated existing entry for {repository}@{branch}", linkRegistryEntry.Repository, linkRegistryEntry.Branch);
}
else
logger.LogInformation("Skipping update for {repository}@{branch} because the existing entry is newer", linkRegistryEntry.Repository, linkRegistryEntry.Branch);
}
else
{
_linkIndex.Repositories.Add(linkRegistryEntry.Repository, new Dictionary<string, LinkRegistryEntry>
{
{ linkRegistryEntry.Branch, linkRegistryEntry }
});
logger.LogInformation("Added new entry for {repository}@{branch}", linkRegistryEntry.Repository, linkRegistryEntry.Branch);
}
}
public async Task Save()
{
if (_etag == null || _linkIndex == null)
throw new InvalidOperationException("You must call UpdateLinkIndexEntry() before Save()");
var json = LinkReferenceRegistry.Serialize(_linkIndex);
logger.LogInformation("Saving link index to s3://{bucketName}/{key}", bucketName, key);
var putObjectRequest = new PutObjectRequest
{
BucketName = bucketName,
Key = key,
ContentBody = json,
ContentType = "application/json",
IfMatch = _etag // Only update if the ETag matches. Meaning the object has not been changed in the meantime.
};
_ = await s3Client.PutObjectAsync(putObjectRequest);
logger.LogInformation("Successfully saved link index to s3://{bucketName}/{key}", bucketName, key);
}
}