Innovenergy_trunk/csharp/Lib/S3Utils/S3.cs

246 lines
8.0 KiB
C#

using System.Collections.Concurrent;
using System.Net;
using System.Text;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using InnovEnergy.Lib.S3Utils.DataTypes;
using InnovEnergy.Lib.Utils;
using S3Bucket = InnovEnergy.Lib.S3Utils.DataTypes.S3Bucket;
using S3Region = InnovEnergy.Lib.S3Utils.DataTypes.S3Region;
namespace InnovEnergy.Lib.S3Utils;
public static class S3
{
private static readonly ConcurrentDictionary<S3Region, AmazonS3Client> S3ClientCache = new();
// QOL method
public static S3Bucket Bucket(this S3Region region, String name) => new
(
Name: name,
Region: region
);
// QOL method
public static S3Url Path(this S3Bucket bucket, String path) => new
(
Bucket: bucket,
Path: path
);
public static IAsyncEnumerable<S3Url> ListObjects(this S3Bucket bucket) => ListObjects(bucket, null);
public static IAsyncEnumerable<S3Url> ListObjects(this S3Bucket bucket, String? pathPrefix)
{
return bucket
.Region
.GetS3Client()
.Paginators
.ListObjectsV2(new() { BucketName = bucket.Name, Prefix = pathPrefix })
.S3Objects
.Select(o => new S3Url(o.Key, bucket));
}
public static Task<ListBucketsResponse> ListAllBuckets(this S3Region region)
{
return region
.GetS3Client()
.ListBucketsAsync();
}
public static Task<Boolean> PutObject(this S3Url path, String data, Encoding encoding) => path.PutObject(encoding.GetBytes(data));
public static Task<Boolean> PutObject(this S3Url path, String data) => path.PutObject(data, Encoding.UTF8);
public static Task<Boolean> PutObject(this S3Url path, Byte[] data) => path.PutObject(new MemoryStream(data));
public static async Task<Boolean> PutObject(this S3Url path, Stream data)
{
var request = new PutObjectRequest
{
BucketName = path.Bucket.Name,
Key = path.Path,
InputStream = data
};
var response = await path
.Bucket
.Region
.GetS3Client()
.PutObjectAsync(request);
return response.HttpStatusCode == HttpStatusCode.OK;
}
public static Task<String> GetObjectAsString(this S3Url path) => GetObjectAsString(path, Encoding.UTF8);
public static async Task<String> GetObjectAsString(this S3Url path, Encoding encoding)
{
await using var stream = await GetObjectAsStream(path);
using var reader = new StreamReader(stream, encoding);
return await reader.ReadToEndAsync();
}
public static async Task<Stream> GetObjectAsStream(this S3Url path)
{
var request = new GetObjectRequest
{
BucketName = path.Bucket.Name,
Key = path.Path
};
var response = await path
.Bucket
.Region
.GetS3Client()
.GetObjectAsync(request);
return response.ResponseStream;
}
// public static async Task<Boolean> CheckRoleExists(this S3Region region, String roleId)
// {
//
//
// var response = await region
// .GetIamClient()
// .GetRoleAsync(new GetRoleRequest(){RoleName = roleId});
// return response.HttpStatusCode != HttpStatusCode.NotFound;
// }
public static async Task<IReadOnlyList<Byte>> GetObject(this S3Url url)
{
// beautiful await using stream soup...
await using var stream = await url.GetObjectAsStream();
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
public static IAsyncEnumerable<String> GetObjectLineByLine(this S3Url url) => GetObjectLineByLine(url, Encoding.UTF8);
public static async IAsyncEnumerable<String> GetObjectLineByLine(this S3Url url, Encoding encoding)
{
await using var stream = await url.GetObjectAsStream();
using var reader = new StreamReader(stream, encoding);
while (true)
{
var line = await reader.ReadLineAsync();
if (line is not null)
yield return line;
else
yield break;
}
}
public static async Task<S3Bucket?> PutBucket(this S3Region region, string name)
{
var request = new PutBucketRequest { BucketName = name };
var response = await region.GetS3Client().PutBucketAsync(request);
if (response.HttpStatusCode == HttpStatusCode.OK)
{
// Define CORS configuration rules
var corsConfiguration = new CORSConfiguration
{
Rules = new List<CORSRule>
{
new CORSRule
{
AllowedHeaders = new List<string> { "*" },
AllowedMethods = new List<string> { "GET", "HEAD" },
AllowedOrigins = new List<string> { "*" },
ExposeHeaders = new List<string>() // Empty list as per your settings
}
}
};
// Create a PutCORSConfigurationRequest
var putCorsRequest = new PutCORSConfigurationRequest
{
BucketName = name,
Configuration = corsConfiguration
};
// Set the CORS configuration for the bucket
var corsResponse = await region.GetS3Client().PutCORSConfigurationAsync(putCorsRequest);
if (corsResponse.HttpStatusCode == HttpStatusCode.OK)
{
return region.Bucket(name);
}
else
{
Console.WriteLine("Failed to set CORS configuration.");
return null;
}
}
else
{
Console.WriteLine("Failed to create bucket.");
return null;
}
}
// public static async Task<S3Bucket?> PutBucket(this S3Region region, String name)
// {
// var request = new PutBucketRequest { BucketName = name };
//
// var response = await region
// .GetS3Client()
// .PutBucketAsync(request);
//
// return response.HttpStatusCode switch
// {
// HttpStatusCode.OK => region.Bucket(name),
// _ => null
// };
// }
public static async Task<Boolean> PutCors(this S3Bucket bucket, CORSConfiguration corsConfiguration)
{
var request = new PutCORSConfigurationRequest
{
BucketName = bucket.Name,
Configuration = corsConfiguration
};
var response = await bucket
.GetS3Client()
.PutCORSConfigurationAsync(request);
return response.HttpStatusCode == HttpStatusCode.OK;
}
public static async Task<Boolean> DeleteBucket(this S3Bucket bucket)
{
var request = new DeleteBucketRequest { BucketName = bucket.Name };
var response = await bucket
.GetS3Client()
.DeleteBucketAsync(request);
return response.HttpStatusCode == HttpStatusCode.OK;
}
private static AmazonS3Client GetS3Client(this S3Url url ) => url.Bucket.GetS3Client();
private static AmazonS3Client GetS3Client(this S3Bucket bucket) => bucket.Region.GetS3Client();
private static AmazonS3Client GetS3Client(this S3Region region)
{
return S3ClientCache.GetOrAdd(region, CreateS3Client); // Memoize
}
private static AmazonS3Client CreateS3Client(S3Region region) => new
(
credentials: new BasicAWSCredentials(region.Credentials.Key, region.Credentials.Secret),
clientConfig: new()
{
ServiceURL = region.Name.EnsureStartsWith("https://"),
ForcePathStyle = true,
}
);
}