// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.SQS;
using Amazon.SQS.Model;
using Amazon.S3.IO;
namespace Tools.CrashReporter.CrashReportCommon
{
///
/// Helper class for accessing AWS
///
public class AmazonClient : IDisposable
{
///
/// Is the AmazonClient initialized and ready to use with S3?
///
public bool IsS3Valid
{
get { return S3Client != null; }
}
///
/// Is the AmazonClient initialized and ready to use with SQS?
///
public bool IsSQSValid
{
get { return SqsClient != null; }
}
///
/// Create a new AmazonClient
///
/// Amazon Credentials for the connection to AWS
/// SQS connection details
/// S3 connection details
/// Out error, receives the error string if an error occurs
public AmazonClient(AWSCredentials Credentials, AmazonSQSConfig SqsConfig, AmazonS3Config S3Config, out string OutError)
{
OutError = string.Empty;
if (SqsConfig != null)
{
try
{
SqsClient = new AmazonSQSClient(Credentials, SqsConfig);
}
catch (Exception Ex)
{
OutError += Ex.Message;
}
}
if (S3Config != null)
{
try
{
S3Client = new AmazonS3Client(Credentials, S3Config);
}
catch (Exception Ex)
{
OutError += Ex.Message;
}
}
}
///
/// Dispose of this object
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Dispose of this object
///
/// Dispose of managed resources?
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (SqsClient != null) SqsClient.Dispose();
if (S3Client != null) S3Client.Dispose();
}
}
///
/// Get the number of items in an SQS queue
///
/// The SQS queue URL
/// Number of messages in the queue. Returns zero in the event of an error.
public int GetSQSQueueCount(string QueueUrl)
{
if (!IsSQSValid) return 0;
GetQueueAttributesRequest AttribRequest = new GetQueueAttributesRequest
{
QueueUrl = QueueUrl,
AttributeNames = new List
{
"ApproximateNumberOfMessages"
}
};
GetQueueAttributesResponse AttribResponse = SqsClient.GetQueueAttributes(AttribRequest);
return AttribResponse.ApproximateNumberOfMessages;
}
///
/// Gets a message from an SQS queue and if successful, deletes the message from the queue.
/// Safe method for multiple concurrent consumers of a single SQS because the initial message read makes the message unavailable to other callers.
///
/// The SQS queue URL
/// Debug option. Skips the message delete when testing reading messages from a live queue
/// A dequeued SQS message or null if it fails.
public Message SQSDequeueMessage(string QueueUrl, bool bForceNoDelete)
{
if (!IsSQSValid) return null;
ReceiveMessageRequest ReceiveRequest = new ReceiveMessageRequest
{
QueueUrl = QueueUrl,
MaxNumberOfMessages = 1
};
ReceiveMessageResponse ReceiveResponse = SqsClient.ReceiveMessage(ReceiveRequest);
if (ReceiveResponse.Messages.Count == 1)
{
Message Message = ReceiveResponse.Messages[0];
if (Message != null && (bForceNoDelete || DeleteRecordSQS(QueueUrl, Message)))
{
return Message;
}
}
return null;
}
///
/// Retrieves an object from S3. (Caller can use the response to read the response stream)
///
/// S3 bucket name
/// S3 object key
/// S3 object response for the requested object or null if it fails.
public GetObjectResponse GetS3Object(string BucketName, string Key)
{
if (!IsS3Valid) return null;
GetObjectRequest ObjectRequest = new GetObjectRequest
{
BucketName = BucketName,
Key = Key
};
return S3Client.GetObject(ObjectRequest);
}
///
/// Retrieves an URL with the appropriate signature to access the file for a predetermined amount of time
///
/// S3 bucket name
/// S3 object key
/// Expiration of link in minutes
/// The URL that can be used to access the file
public string GetS3SignedUrl(string BucketName, string Key, int expirationInMinutes)
{
if (!IsS3Valid) return null;
string url = null;
S3FileInfo s3FileInfo = new Amazon.S3.IO.S3FileInfo(S3Client, BucketName, Key);
if (s3FileInfo.Exists)
{
url = S3Client.GetPreSignedURL(new GetPreSignedUrlRequest
{
BucketName = BucketName,
Key = Key,
Expires = DateTime.UtcNow.AddMinutes(expirationInMinutes)
//ResponseHeaderOverrides = new ResponseHeaderOverrides() { ContentDisposition = "attachment; filename=\"test.txt\"", }
});
}
return url;
}
///
/// Uploads a file to S3 synchronously (blocks until complete).
///
/// S3 bucket name
/// S3 object key
/// Full path of the file to upload
/// S3 object response for the uploaded object or null if it fails.
public PutObjectResponse PutS3ObjectFromFile(string BucketName, string Key, string Filepath)
{
if (!IsS3Valid) return null;
PutObjectRequest ObjectRequest = new PutObjectRequest
{
BucketName = BucketName,
Key = Key,
FilePath = Filepath
};
return S3Client.PutObject(ObjectRequest);
}
///
/// Uploads a stream to S3 synchronously (blocks until complete).
///
/// S3 bucket name
/// S3 object key
/// Source stream containing data to upload
/// S3 object response for the uploaded object or null if it fails.
public PutObjectResponse PutS3ObjectFromStream(string BucketName, string Key, Stream InStream)
{
if (!IsS3Valid) return null;
PutObjectRequest ObjectRequest = new PutObjectRequest
{
BucketName = BucketName,
Key = Key,
InputStream = InStream
};
return S3Client.PutObject(ObjectRequest);
}
private bool DeleteRecordSQS(string QueueUrl, Message InMessage)
{
DeleteMessageRequest DeleteRequest = new DeleteMessageRequest
{
QueueUrl = QueueUrl,
ReceiptHandle = InMessage.ReceiptHandle
};
var DeleteResponse = SqsClient.DeleteMessage(DeleteRequest);
return DeleteResponse.HttpStatusCode == HttpStatusCode.OK;
}
private readonly AmazonSQSClient SqsClient;
private readonly AmazonS3Client S3Client;
}
}