using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport;
using Amazon.Lambda.Serialization.SystemTextJson;
using Amazon.XRay.Recorder.Handlers.AwsSdk;
using Common;
namespace store_image_metadata
{
public class Function
{
private static readonly string PHOTO_TABLE = Environment.GetEnvironmentVariable("PHOTO_TABLE") ?? string.Empty;
private static readonly IAmazonDynamoDB _ddbClient = new AmazonDynamoDBClient();
static Function()
{
AWSSDKHandler.RegisterXRayForAllServices();
}
///
/// The main entry point for the custom runtime.
///
///
private static async Task Main()
{
Func handler = FunctionHandler;
await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer(options =>
{
options.PropertyNameCaseInsensitive = true;
}))
.Build()
.RunAsync();
}
///
/// A simple function that takes a string and returns both the upper and lower case version of the string.
///
///
///
///
private static async Task FunctionHandler(InputEvent input, ILambdaContext context)
{
var logger = new ImageRecognitionLogger(input, context);
var thumbnail = JsonSerializer.Deserialize(JsonSerializer.Serialize(input.ParallelResults[1]),
CustomJsonSerializerContext.Default.Thumbnail);
var labels = JsonSerializer.Deserialize(JsonSerializer.Serialize(input.ParallelResults[0]),
CustomJsonSerializerContext.Default.ListLabel);
var photo = new Photo
{
PhotoId = WebUtility.UrlDecode(input.PhotoId),
ProcessingStatus = ProcessingStatus.Succeeded,
FullSize = new PhotoImage
{
Key = WebUtility.UrlDecode(input.SourceKey),
Width = input.ExtractedMetadata?.Dimensions?.Width,
Height = input.ExtractedMetadata?.Dimensions?.Height
},
Format = input.ExtractedMetadata?.Format,
ExifMake = input.ExtractedMetadata?.ExifMake ?? string.Empty,
ExifModel = input.ExtractedMetadata?.ExifModel ?? string.Empty,
Thumbnail = new PhotoImage
{
Key = WebUtility.UrlDecode(thumbnail?.s3key),
Width = thumbnail?.width,
Height = thumbnail?.height
},
ObjectDetected = labels.Select(l => l.Name).ToArray(),
GeoLocation = input.ExtractedMetadata?.Geo,
UpdatedDate = DateTime.UtcNow
};
int status = (int)photo.ProcessingStatus;
var request = new UpdateItemRequest
{
Key = new Dictionary()
{
{ "PhotoId", new AttributeValue { S = photo.PhotoId } }
},
ExpressionAttributeValues = new Dictionary()
{
{":status",new AttributeValue { S = status.ToString() }},
{":date",new AttributeValue { S = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fff'Z'", CultureInfo.InvariantCulture)}},
{ ":objects",new AttributeValue { SS = photo.ObjectDetected.ToList() }},
{":thumb",new AttributeValue { M = ToDynamoAttributes(photo.Thumbnail) } },
{":full",new AttributeValue { M = ToDynamoAttributes(photo.FullSize) }},
{":make",new AttributeValue { S = photo.ExifMake}},
{":model",new AttributeValue { S = photo.ExifModel }},
},
UpdateExpression = "SET ProcessingStatus = :status, UpdatedDate = :date, ObjectDetected = :objects, Thumbnail = :thumb, FullSize = :full, ExifMake = :make, ExifModel = :model",
TableName = PHOTO_TABLE
};
Console.WriteLine(request.UpdateExpression);
var data = JsonSerializer.Serialize(photo, CustomJsonSerializerContext.Default.Photo);
Console.WriteLine(data);
await _ddbClient.UpdateItemAsync(request);
await logger.WriteMessageAsync(
new MessageEvent
{ Message = "Photo recognition metadata stored succesfully", Data = data, CompleteEvent = true },
ImageRecognitionLogger.Target.All);
}
private static Dictionary ToDynamoAttributes(PhotoImage photoImage)
{
Dictionary item = new Dictionary();
item.Add("Key", new AttributeValue { S = photoImage.Key });
if (photoImage.Width != null)
{
item.Add("Width", new AttributeValue { N = photoImage.Width.ToString() });
}
if (photoImage.Height != null)
{
item.Add("Height", new AttributeValue { N = photoImage.Height.ToString() });
}
return item;
}
}
}