From d15ed558bb89ea18270e13bcef621fb0cc63a6f5 Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Fri, 5 Jun 2020 17:01:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=87=E4=BB=B6=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E6=A8=A1=E5=9D=97,=E9=9B=86=E6=88=90=E4=B8=83?= =?UTF-8?q?=E7=89=9B=E4=BA=91=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LINGYUN.Abp.FileStorage.Qiniu.csproj | 16 +++ .../Qiniu/AbpQiniuFileStorageModule.cs | 10 ++ .../Qiniu/QiniuFileStorageOptions.cs | 40 +++++++ .../Qiniu/QiniuFileStorageProvider.cs | 111 ++++++++++++++++++ .../LINGYUN.Abp.FileStorage.csproj | 12 ++ .../Abp/FileStorage/AbpFileStorageModule.cs | 8 ++ .../FileDownloadCompletedEventArges.cs | 8 ++ .../FileDownloadProgressEventArges.cs | 11 ++ .../LINGYUN/Abp/FileStorage/FileInfo.cs | 59 ++++++++++ .../Abp/FileStorage/FileStorageProvider.cs | 63 ++++++++++ .../FileUploadCompletedEventArges.cs | 8 ++ .../FileUploadProgressEventArges.cs | 21 ++++ .../Abp/FileStorage/IFileStorageProvider.cs | 41 +++++++ .../LINGYUN/Abp/FileStorage/IFileStore.cs | 39 ++++++ .../LINGYUN/Abp/FileStorage/MediaType.cs | 25 ++++ 15 files changed, 472 insertions(+) create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN.Abp.FileStorage.Qiniu.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/AbpQiniuFileStorageModule.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageOptions.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageProvider.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN.Abp.FileStorage.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/AbpFileStorageModule.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadCompletedEventArges.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadProgressEventArges.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileInfo.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileStorageProvider.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadCompletedEventArges.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadProgressEventArges.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStorageProvider.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStore.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/MediaType.cs diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN.Abp.FileStorage.Qiniu.csproj b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN.Abp.FileStorage.Qiniu.csproj new file mode 100644 index 000000000..f9f7278ba --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN.Abp.FileStorage.Qiniu.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/AbpQiniuFileStorageModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/AbpQiniuFileStorageModule.cs new file mode 100644 index 000000000..2568f6cd5 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/AbpQiniuFileStorageModule.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.FileStorage.Qiniu +{ + [DependsOn(typeof(AbpFileStorageModule))] + public class AbpQiniuFileStorageModule : AbpModule + { + + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageOptions.cs new file mode 100644 index 000000000..7a7838a0b --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageOptions.cs @@ -0,0 +1,40 @@ +namespace LINGYUN.Abp.FileStorage.Qiniu +{ + public class QiniuFileStorageOptions + { + /// + /// Api授权码 + /// + public string AccessKey { get; set; } + /// + /// Api密钥 + /// + public string SecretKey { get; set; } + /// + /// 默认自动删除该文件天数 + /// 默认 0,不删除 + /// + public int DeleteAfterDays { get; set; } + /// + /// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL。 + /// 必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL + /// + public string UploadCallbackUrl { get; set; } + /// + /// 上传成功后,七牛云向业务服务器发送回调通知时的 Host 值。 + /// 与 callbackUrl 配合使用,仅当设置了 callbackUrl 时才有效。 + /// + public string UploadCallbackHost { get; set; } + /// + /// 上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。 + /// 默认为 application/x-www-form-urlencoded,也可设置为 application/json。 + /// + public string UploadCallbackBodyType { get; set; } + /// + /// 上传成功后,自定义七牛云最终返回給上传端(在指定 returnUrl 时是携带在跳转路径参数中)的数据。 + /// 支持魔法变量和自定义变量。returnBody 要求是合法的 JSON 文本。 + /// 例如 {"key": $(key), "hash": $(etag), "w": $(imageInfo.width), "h": $(imageInfo.height)}。 + /// + public string UploadCallbackBody { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageProvider.cs new file mode 100644 index 000000000..2a19b2d4e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage.Qiniu/LINGYUN/Abp/FileStorage/Qiniu/QiniuFileStorageProvider.cs @@ -0,0 +1,111 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Qiniu.IO; +using Qiniu.IO.Model; +using Qiniu.RS; +using Qiniu.Util; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.FileStorage.Qiniu +{ + [Dependency(ServiceLifetime.Transient, ReplaceServices = true)] + [ExposeServices(typeof(IFileStorageProvider), typeof(FileStorageProvider))] + public class QiniuFileStorageProvider : FileStorageProvider + { + protected QiniuFileStorageOptions Options { get; } + public QiniuFileStorageProvider( + IFileStore store, + IOptions options) + : base(store) + { + Options = options.Value; + } + + protected override async Task DownloadFileAsync(FileInfo fileInfo, string saveLocalPath) + { + Mac mac = new Mac(Options.AccessKey, Options.SecretKey); + + int expireInSeconds = 3600; + string accUrl = DownloadManager.CreateSignedUrl(mac, fileInfo.Url, expireInSeconds); + + var saveLocalFile = Path.Combine(saveLocalPath, fileInfo.Name); + var httpResult = await DownloadManager.DownloadAsync(accUrl, saveLocalFile); + if(httpResult.Code == 200) + { + using (var fs = new FileStream(saveLocalFile, FileMode.Open, FileAccess.Read)) + { + fileInfo.Data = new byte[fs.Length]; + + await fs.ReadAsync(fileInfo.Data, 0, fileInfo.Data.Length).ConfigureAwait(false); + } + } + else + { + // TODO: 处理响应代码 + + Console.WriteLine(httpResult.Code); + } + + return fileInfo; + } + + protected override async Task RemoveFileAsync(FileInfo fileInfo, CancellationToken cancellationToken = default) + { + Mac mac = new Mac(Options.AccessKey, Options.SecretKey); + + var bucket = fileInfo.Directory + ":" + fileInfo.Name; + var backetManager = new BucketManager(mac); + await backetManager.DeleteAsync(bucket, fileInfo.Name); + + throw new NotImplementedException(); + } + + protected override async Task UploadFileAsync(FileInfo fileInfo, int? expireIn = null, CancellationToken cancellationToken = default) + { + Mac mac = new Mac(Options.AccessKey, Options.SecretKey); + + PutPolicy putPolicy = new PutPolicy + { + Scope = fileInfo.Directory + ":" + fileInfo.Name, + CallbackBody = Options.UploadCallbackBody, + CallbackBodyType = Options.UploadCallbackBodyType, + CallbackHost = Options.UploadCallbackHost, + CallbackUrl = Options.UploadCallbackUrl + }; + if (expireIn.HasValue) + { + putPolicy.SetExpires(expireIn.Value); + } + if (Options.DeleteAfterDays > 0) + { + putPolicy.DeleteAfterDays = Options.DeleteAfterDays; + } + + + string jstr = putPolicy.ToJsonString(); + string token = Auth.CreateUploadToken(mac, jstr); + + UploadProgressHandler handler = (uploadByte, totalByte) => + { + OnFileUploadProgressChanged(uploadByte, totalByte); + }; + + // 带进度的上传 + ResumableUploader uploader = new ResumableUploader(); + var httpResult = await uploader.UploadDataAsync(fileInfo.Data, fileInfo.Name, token, handler); + + // 普通上传 + //FormUploader fu = new FormUploader(); + //var httpResult = await fu.UploadDataAsync(fileInfo.Data, fileInfo.Name, token); + + // TODO: 处理响应代码 + + Console.WriteLine(httpResult.Code); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN.Abp.FileStorage.csproj b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN.Abp.FileStorage.csproj new file mode 100644 index 000000000..76ce15181 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN.Abp.FileStorage.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/AbpFileStorageModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/AbpFileStorageModule.cs new file mode 100644 index 000000000..57147498e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/AbpFileStorageModule.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.FileStorage +{ + public class AbpFileStorageModule : AbpModule + { + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadCompletedEventArges.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadCompletedEventArges.cs new file mode 100644 index 000000000..8d41bafa5 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadCompletedEventArges.cs @@ -0,0 +1,8 @@ +using System; + +namespace LINGYUN.Abp.FileStorage +{ + public class FileDownloadCompletedEventArges : EventArgs + { + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadProgressEventArges.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadProgressEventArges.cs new file mode 100644 index 000000000..d254b4461 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileDownloadProgressEventArges.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LINGYUN.Abp.FileStorage +{ + public class FileDownloadProgressEventArges : EventArgs + { + + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileInfo.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileInfo.cs new file mode 100644 index 000000000..7376e7297 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileInfo.cs @@ -0,0 +1,59 @@ +using System; + +namespace LINGYUN.Abp.FileStorage +{ + /// + /// 文件信息 + /// + public class FileInfo + { + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 大小 + /// + public long Size { get; set; } + /// + /// 文件路径 + /// + public string Directory { get; set; } + /// + /// 文件扩展名 + /// + public string Extension { get; set; } + /// + /// 文件哈希码,用于唯一标识 + /// + public string Hash { get; set; } + /// + /// 文件链接 + /// + public string Url { get; set; } + /// + /// 文件数据 + /// + public byte[] Data { get; set; } + /// + /// 媒体类型 + /// + public MediaType MediaType { get; set; } + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } + /// + /// 创建人 + /// + public Guid? CreatorId { get; set; } + /// + /// 上次变更时间 + /// + public DateTime? LastModificationTime { get; set; } + /// + /// 上次变更人 + /// + public Guid? LastModifierId { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileStorageProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileStorageProvider.cs new file mode 100644 index 000000000..57d33ca5e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileStorageProvider.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.FileStorage +{ + public abstract class FileStorageProvider : IFileStorageProvider + { + public event EventHandler FileDownloadProgressChanged; + public event EventHandler FileDownloadCompleted; + public event EventHandler FileUploadProgressChanged; + public event EventHandler FileUploadCompleted; + + protected IFileStore Store { get; } + + public FileStorageProvider(IFileStore store) + { + Store = store; + } + + public async Task DeleteFileAsync(string hash, CancellationToken cancellationToken = default) + { + // 获取文件信息 + var file = await Store.GetFileAsync(hash); + // 删除文件 + await RemoveFileAsync(file, cancellationToken); + // 删除文件信息 + await Store.DeleteFileAsync(hash, cancellationToken); + } + + public async Task GetFileAsync(string hash, string saveLocalPath) + { + // 获取文件信息 + var file = await Store.GetFileAsync(hash); + // 下载文件 + return await DownloadFileAsync(file, saveLocalPath); + } + + public async Task StorageAsync(FileInfo fileInfo, int? expireIn = null, CancellationToken cancellationToken = default) + { + // step1 上传文件 + await UploadFileAsync(fileInfo, expireIn, cancellationToken); + // step2 保存文件信息 + await Store.StorageAsync(fileInfo, expireIn, cancellationToken); + } + + protected abstract Task UploadFileAsync(FileInfo fileInfo, int? expireIn = null, CancellationToken cancellationToken = default); + + protected abstract Task DownloadFileAsync(FileInfo fileInfo, string saveLocalPath); + + protected abstract Task RemoveFileAsync(FileInfo fileInfo, CancellationToken cancellationToken = default); + + protected virtual void OnFileUploadProgressChanged(long sent, long total) + { + FileUploadProgressChanged?.Invoke(this, new FileUploadProgressEventArges(sent, total)); + } + + protected virtual void OnFileUploadConpleted() + { + FileUploadCompleted?.Invoke(this, new FileUploadCompletedEventArges()); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadCompletedEventArges.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadCompletedEventArges.cs new file mode 100644 index 000000000..eb23f111d --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadCompletedEventArges.cs @@ -0,0 +1,8 @@ +using System; + +namespace LINGYUN.Abp.FileStorage +{ + public class FileUploadCompletedEventArges : EventArgs + { + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadProgressEventArges.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadProgressEventArges.cs new file mode 100644 index 000000000..9ae7def26 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/FileUploadProgressEventArges.cs @@ -0,0 +1,21 @@ +using System; + +namespace LINGYUN.Abp.FileStorage +{ + public class FileUploadProgressEventArges : EventArgs + { + /// + /// 上传数据大小 + /// + public long BytesSent { get; } + /// + /// 总数据大小 + /// + public long TotalBytesSent { get; } + public FileUploadProgressEventArges(long sent, long total) + { + BytesSent = sent; + TotalBytesSent = total; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStorageProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStorageProvider.cs new file mode 100644 index 000000000..b7c892b45 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStorageProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.FileStorage +{ + /// + /// 文件存储提供者 + /// + public interface IFileStorageProvider + { + event EventHandler FileDownloadProgressChanged; + event EventHandler FileDownloadCompleted; + + event EventHandler FileUploadProgressChanged; + event EventHandler FileUploadCompleted; + + /// + /// 存储文件 + /// + /// 文件信息 + /// 过期时间,单位(s) + /// + /// + Task StorageAsync(FileInfo fileInfo, int? expireIn = null, CancellationToken cancellationToken = default); + /// + /// 获取文件 + /// + /// 文件唯一标识 + /// 保存到本地路径 + /// + Task GetFileAsync(string hash, string saveLocalPath); + /// + /// 删除文件 + /// + /// 文件唯一标识 + /// + /// + Task DeleteFileAsync(string hash, CancellationToken cancellationToken = default); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStore.cs new file mode 100644 index 000000000..f4b12a87b --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/IFileStore.cs @@ -0,0 +1,39 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.FileStorage +{ + /// + /// 文件存储接口 + /// + public interface IFileStore + { + /// + /// 存储文件 + /// + /// 文件信息 + /// 过期时间,单位(s) + /// + /// + Task StorageAsync(FileInfo fileInfo, int? expireIn = null, CancellationToken cancellationToken = default); + /// + /// 获取文件 + /// + /// 文件唯一标识 + /// + Task GetFileAsync(string hash); + /// + /// 文件是否存在 + /// + /// 文件唯一标识 + /// + Task FileHasExistsAsync(string hash); + /// + /// 删除文件 + /// + /// 文件唯一标识 + /// + /// + Task DeleteFileAsync(string hash, CancellationToken cancellationToken = default); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/MediaType.cs b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/MediaType.cs new file mode 100644 index 000000000..ebabe6fda --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.FileStorage/LINGYUN/Abp/FileStorage/MediaType.cs @@ -0,0 +1,25 @@ +namespace LINGYUN.Abp.FileStorage +{ + /// + /// 媒体类型 + /// + public enum MediaType + { + /// + /// 文档 + /// + Document = 0, + /// + /// 图像 + /// + Image = 2, + /// + /// 影像 + /// + Video = 3, + /// + /// 音乐 + /// + Music = 4 + } +}