Beispiel #1
0
        public async Task <APIGatewayProxyResponse> AddImageAsync(APIGatewayProxyRequest request, ILambdaContext context)
        {
            context.Logger.LogLine($"POST /images body: {request.Body}");

            var imageRequest = JsonSerializer.Deserialize <AddImageRequestModel>(request?.Body);

            var fileExt = Path.GetExtension(imageRequest.FileName);

            var image = new ScreenImage
            {
                Type       = imageRequest.ImageType,
                UploadedOn = DateTime.UtcNow,
                UserName   = "******", // TODO: set from auth'd user
                // IsPublished is false until the image has been processed
            };

            image.FileName = $"{image.Id}{fileExt}".ToLower();

            var keyPrefix    = $"{UPLOAD_KEY_PREFIX}{image.UploadedOn.ToString("yyyy/MM")}";
            var imageFileKey = $"{keyPrefix}/{image.FileName}";

            // All of these properties, including meta-data must match what the
            // frontend is sending ootherwise the key will mismatch, resulting
            // in a 403 response from S3
            var presignRequest = new GetPreSignedUrlRequest
            {
                Verb        = HttpVerb.PUT,
                BucketName  = _bucketName,
                Key         = imageFileKey,
                ContentType = imageRequest.ContentType,
                Expires     = DateTime.UtcNow.AddSeconds(PRESIGN_URL_EXPIRATION_SECS),
            };

            presignRequest.Metadata.Add("imageId", image.Id);
            presignRequest.Metadata.Add("imageType", image.Type);
            presignRequest.Metadata.Add("userName", image.UserName); // Maybe use user ID instead?

            var presignedUrl = _s3Client.GetPreSignedURL(presignRequest);

            context.Logger.LogLine($"Saving image with ID {image.Id}");
            await _ddbService.SaveAsync(image);

            var addImageResponse = new AddImageResponseModel
            {
                Id        = image.Id,
                Key       = imageFileKey,
                Type      = image.Type,
                UploadUrl = presignedUrl
            };

            var response = new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.Created,
                Body       = JsonSerializer.Serialize(addImageResponse),
                Headers    = _defaultHeaders
            };

            return(response);
        }
        public async Task <string> ProcessImage(S3Event evnt, ILambdaContext context)
        {
            var s3Event = evnt.Records?[0].S3;

            if (s3Event == null)
            {
                context.Logger.LogLine("ERROR: Could not get S3 Event Data");
                return(null);
            }

            try
            {
                var objMetadata = await _s3Client.GetObjectMetadataAsync(s3Event.Bucket.Name, s3Event.Object.Key);

                var imageId   = objMetadata.Metadata["x-amz-meta-imageid"];
                var imageType = objMetadata.Metadata["x-amz-meta-imagetype"];

                context.Logger.LogLine($"Processing image {s3Event.Object.Key}. ImageType: {imageType ?? "unknown"}");

                // Copy the file from the upload folder
                var originalSizeKey = GetResizedFileKey(s3Event.Object.Key);
                await _s3Client.CopyObjectAsync(s3Event.Bucket.Name, s3Event.Object.Key, s3Event.Bucket.Name, originalSizeKey);

                // Ideally, we would use the stream instead, but couldn't figure out how to get
                // it to re-use the same stream
                byte[] imageBytes       = null;
                var    imageContentType = "";

                using (var objectResp = await _s3Client.GetObjectAsync(s3Event.Bucket.Name, s3Event.Object.Key))
                    using (var ms = new MemoryStream())
                    {
                        imageContentType = objectResp.Headers.ContentType;

                        await objectResp.ResponseStream.CopyToAsync(ms);

                        imageBytes = ms.ToArray();
                    }

                var imageTypeSizes = _sizes.Where(x => x.ImageType == imageType);
                foreach (var imgSize in imageTypeSizes)
                {
                    context.Logger.LogLine($"... Resizing to {imgSize.Key}");

                    IImageFormat imageFormat;
                    using (var image = Image.Load(imageBytes, out imageFormat))
                    {
                        var resizedFileKey = GetResizedFileKey(s3Event.Object.Key, imgSize.Key);

                        using (var outStream = new MemoryStream())
                        {
                            image.Mutate(x => x.Resize(new ResizeOptions
                            {
                                Mode     = ResizeMode.Max, // TODO: allow each profile to specify method used
                                Position = AnchorPositionMode.Center,
                                Size     = new Size(imgSize.Width, imgSize.Height)
                            }));
                            image.Save(outStream, imageFormat);

                            var putObjectRequest = new PutObjectRequest
                            {
                                Key         = resizedFileKey,
                                BucketName  = s3Event.Bucket.Name,
                                ContentType = imageContentType,
                                InputStream = outStream
                            };
                            await _s3Client.PutObjectAsync(putObjectRequest);
                        }
                    }

                    context.Logger.LogLine($"... Resized and saved file '{s3Event.Object.Key}' to '{imgSize.Key}'");
                }

                var imageRecord = await _ddbService.GetByIdAsync <ScreenImage>(imageId);

                if (imageRecord != null)
                {
                    imageRecord.IsPublished = true;
                    await _ddbService.SaveAsync(imageRecord);
                }

                // Delete the original
                await _s3Client.DeleteObjectAsync(s3Event.Bucket.Name, s3Event.Object.Key);

                return("Ok");
            }
            catch (Exception ex)
            {
                context.Logger.LogLine($"Error processing image s3://{s3Event.Bucket.Name}/{s3Event.Object.Key}. Error: {ex.Message}");
                context.Logger.LogLine(ex.StackTrace);
                throw;
            }
        }