/Providers/S3StorageProvider.cs
# · C# · 303 lines · 224 code · 38 blank · 41 comment · 10 complexity · eea00c7adf621cd52652e9e60e67c7e7 MD5 · raw file
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.IO;
- using System.Linq;
- using System.Web.Hosting;
- using Amazon.S3.Util;
- using Orchard.Environment.Configuration;
- using Orchard.Localization;
- using Orchard.Validation;
- using Orchard.FileSystems.Media;
- using Amazon.S3.Model;
- using Werul.S3StorageProvider.Models;
- using Orchard.Environment.Extensions;
- using Amazon.S3;
- using Orchard;
- using Orchard.ContentManagement;
-
- namespace Werul.S3StorageProvider.Providers {
- [OrchardSuppressDependency("Orchard.FileSystems.Media.FileSystemStorageProvider")]
- public class S3StorageProvider : IStorageProvider {
-
- private readonly AmazonS3Config _S3Config;
- private readonly IOrchardServices Services;
-
- public S3StorageProvider(IOrchardServices services)
- {
- Services = services;
- _S3Config = new AmazonS3Config()
- {
- ServiceURL = "s3.amazonaws.com",
- CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP,
- };
-
- T = NullLocalizer.Instance;
- }
-
- public string PublicPath
- {
- get
- {
- return string.Format("https://{0}.s3.amazonaws.com/", BucketName);
- }
- }
- public string AWSAccessKey
- {
- get
- {
- return Services.WorkContext.CurrentSite.As<S3StorageProviderSettingsPart>().Record.AWSAccessKey;
- }
- }
- public string AWSSecretKey
- {
- get
- {
- return Services.WorkContext.CurrentSite.As<S3StorageProviderSettingsPart>().Record.AWSSecretKey;
- }
- }
- public string BucketName
- {
- get
- {
- return Services.WorkContext.CurrentSite.As<S3StorageProviderSettingsPart>().Record.BucketName;
- }
- }
-
- public Localizer T { get; set; }
-
- /// <summary>
- /// Retrieves the public URL for a given file within the storage provider.
- /// </summary>
- /// <param name="path">The relative path within the storage provider.</param>
- /// <returns>The public URL.</returns>
- public string GetPublicUrl(string path)
- {
- return string.IsNullOrEmpty(path) ? PublicPath : Path.Combine(PublicPath, path).Replace(Path.DirectorySeparatorChar, '/');
- }
-
- /// <summary>
- /// Retrieves a file within the storage provider.
- /// </summary>
- /// <param name="path">The relative path to the file within the storage provider.</param>
- /// <returns>The file.</returns>
- /// <exception cref="ArgumentException">If the file is not found.</exception>
- public IStorageFile GetFile(string path)
- {
- //not sure if we should use a temp directory here or what
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Lists the files within a storage provider's path.
- /// </summary>
- /// <param name="path">The relative path to the folder which files to list.</param>
- /// <returns>The list of files in the folder.</returns>
- public IEnumerable<IStorageFile> ListFiles(string path)
- {
- var files = new List<S3StorageFile>();
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config)) {
- var request = new ListObjectsRequest();
- request.BucketName = BucketName;
- request.Prefix = path;
-
- using (ListObjectsResponse response = client.ListObjects(request)) {
- foreach (var entry in response.S3Objects.Where(e => e.Key.Last() != '/' && e.Key.Count(c => c == '/') == path.Count(c => c == '/'))) {
- var mimeType = AmazonS3Util.MimeTypeFromExtension(entry.Key.Substring(entry.Key.LastIndexOf(".")));
- files.Add(new S3StorageFile(entry, mimeType));
- }
- }
- }
-
- return files;
- }
-
- /// <summary>
- /// Lists the folders within a storage provider's path.
- /// </summary>
- /// <param name="path">The relative path to the folder which folders to list.</param>
- /// <returns>The list of folders in the folder.</returns>
- public IEnumerable<IStorageFolder> ListFolders(string path)
- {
- var folders = new List<S3StorageFolder>();
-
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config)) {
- path = path ?? "";
- var request = new ListObjectsRequest();
- request.BucketName = BucketName;
- request.Prefix = path;
-
- using (ListObjectsResponse response = client.ListObjects(request)) {
- foreach (var entry in response.S3Objects.Where(e => e.Key.Last() == '/' && e.Key.Count(c => c == '/') == path.Count(c => c == '/') + 1)) {
- var folderSize = ListFiles(entry.Key).Sum(x => x.GetSize());
- folders.Add(new S3StorageFolder(entry, folderSize));
- }
- }
- }
-
- return folders;
- }
-
- /// <summary>
- /// Tries to create a folder in the storage provider.
- /// </summary>
- /// <param name="path">The relative path to the folder to be created.</param>
- /// <returns>True if success; False otherwise.</returns>
- public bool TryCreateFolder(string path)
- {
- try
- {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config))
- {
- var key = string.Format(@"{0}/", path);
- var request = new PutObjectRequest().WithBucketName(BucketName).WithKey(key);
- request.InputStream = new MemoryStream();
- client.PutObject(request);
- }
- }
- catch
- {
- return false;
- }
-
- return true;
- }
-
- /// <summary>
- /// Creates a folder in the storage provider.
- /// </summary>
- /// <param name="path">The relative path to the folder to be created.</param>
- /// <exception cref="ArgumentException">If the folder already exists.</exception>
- public void CreateFolder(string path)
- {
- try
- {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config))
- {
- var key = string.Format(@"{0}/", path);
- var request = new PutObjectRequest().WithBucketName(BucketName).WithKey(key);
- request.InputStream = new MemoryStream();
- client.PutObject(request);
- }
- }
- catch (Exception ex)
- {
- throw new ArgumentException(T("Directory {0} already exists", path).ToString(), ex);
- }
- }
-
- public void DeleteFolder(string path) {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config)) {
- DeleteFolder(path, client);
- }
- }
-
- private void DeleteFolder(string path, AmazonS3 client) {
- //TODO: Refactor to use async deletion?
- foreach (var folder in ListFolders(path)) {
- DeleteFolder(folder.GetPath(), client);
- }
-
- foreach (var file in ListFiles(path)) {
- DeleteFile(file.GetPath(), client);
- }
-
- var request = new DeleteObjectRequest() {
- BucketName = BucketName,
- Key = path
- };
-
- using (DeleteObjectResponse response = client.DeleteObject(request)) {
-
- }
- }
-
- public void RenameFolder(string oldPath, string newPath)
- {
- // Todo: recursive on all keys with prefix
- throw new NotImplementedException("Folder renaming currently not supported");
- }
-
- public void DeleteFile(string path)
- {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config))
- {
- DeleteFile(path, client);
- }
- }
-
- private void DeleteFile(string path, AmazonS3 client)
- {
- var request = new DeleteObjectRequest() {
- BucketName = BucketName,
- Key = path
- };
-
- using (DeleteObjectResponse response = client.DeleteObject(request)) {}
- }
-
- public void RenameFile(string oldPath, string newPath)
- {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config)) {
- RenameObject(oldPath, newPath, client);
-
- //Delete the original
- DeleteFile(oldPath);
- }
- }
-
- public IStorageFile CreateFile(string path)
- {
- throw new NotImplementedException("File creation currently not supported.");
- }
-
- private void RenameObject(string oldPath, string newPath, AmazonS3 client) {
- CopyObjectRequest copyRequest = new CopyObjectRequest()
- .WithSourceBucket(BucketName)
- .WithSourceKey(oldPath)
- .WithDestinationBucket(BucketName)
- .WithDestinationKey(newPath)
- .WithCannedACL(S3CannedACL.PublicRead);
-
- client.CopyObject(copyRequest);
- }
-
- /// <summary>
- /// Tries to save a stream in the storage provider.
- /// </summary>
- /// <param name="path">The relative path to the file to be created.</param>
- /// <param name="inputStream">The stream to be saved.</param>
- /// <returns>True if success; False otherwise.</returns>
- public bool TrySaveStream(string path, Stream inputStream)
- {
- try
- {
- SaveStream(path, inputStream);
- }
- catch
- {
- return false;
- }
-
- return true;
- }
-
- public void SaveStream(string path, Stream inputStream)
- {
- using (var client = Amazon.AWSClientFactory.CreateAmazonS3Client(AWSAccessKey, AWSSecretKey, _S3Config))
- {
- PutObjectRequest request = new PutObjectRequest();
- request.WithBucketName(BucketName).WithKey(path).WithCannedACL(S3CannedACL.PublicRead).WithInputStream(inputStream);
- using (var response = client.PutObject(request))
- {
-
- }
- }
- }
-
- public string Combine(string path1, string path2)
- {
- return path1 + path2;
- }
- }
- }