using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Qiniu.Http; using Qiniu.Storage; using Qiniu.Util; using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Ufangx.FileServices.Abstractions; using Microsoft.Extensions.DependencyInjection; namespace Qiniu { public class FileService : IFileService { protected readonly FileServiceOptions options; protected readonly Mac mac; protected readonly Config config; protected readonly IHttpContextAccessor contextAccessor; public FileService(IOptions options, IHttpContextAccessor contextAccessor) { if (options is null) { throw new ArgumentNullException(nameof(options)); } this.options = options.Value; mac = new Mac(this.options.AccessKey, this.options.SecretKey); config = new Config(); config.UseHttps = this.options.UseHttps; config.UseCdnDomains = this.options.UseCdnDomains; config.ChunkSize = this.options.ChunkUnit; if (this.options.PutThreshold.HasValue) { config.PutThreshold = this.options.PutThreshold.Value; } if (this.options.MaxRetryTimes.HasValue) { config.MaxRetryTimes = this.options.MaxRetryTimes.Value; } if (!string.IsNullOrWhiteSpace(this.options.Zone)) { switch (this.options.Zone.ToLower()) { case "zonecneast": config.Zone = Zone.ZoneCnEast; //config.Zone = Zone.ZONE_CN_East; break; case "zonecnnorth": config.Zone = Zone.ZoneCnNorth; //config.Zone = Zone.ZONE_CN_North; break; case "zonecnsouth": config.Zone = Zone.ZoneCnSouth; //config.Zone = Zone.ZONE_CN_South; break; case "zoneusnorth": config.Zone = Zone.ZoneUsNorth; //config.Zone = Zone.ZONE_US_North; break; case "zoneassingapore": config.Zone = Zone.ZoneAsSingapore; //config.Zone = Zone.ZONE_AS_Singapore; break; default: config.Zone = Newtonsoft.Json.JsonConvert.DeserializeObject(this.options.Zone); break; } } this.contextAccessor = contextAccessor; } public Task Append(string path, Stream stream, CancellationToken token = default) { //var key = GetSaveKey(path); //if (stream.CanSeek && stream.Position > 0) { stream.Position = 0; } //ResumableUploader resumableUploader = new ResumableUploader(config); //var result = await // resumableUploader.UploadStream(stream, key, GetToken(key), null); // //Task.FromResult(resumableUploader.UploadStream(stream, key, GetToken(key), null)); //return result.Code == (int)HttpCode.OK; throw new NotSupportedException(); } public async Task Append(string path, byte[] data, CancellationToken token = default) => await Append(path, new MemoryStream(data), token); public async Task Delete(string path, CancellationToken token = default) => (await GetBucketManager().Delete(options.Bucket,await GetSaveKey(path))).Code == (int)HttpCode.OK; //(await Task.FromResult(GetBucketManager().Delete(options.Bucket, GetSaveKey(path)))).Code == (int)HttpCode.OK; public async Task Exists(string path, CancellationToken token = default) { var result = await GetInfo(path); return result.Code == (int)HttpCode.OK; } async Task GetDownloadUrl(string path) { var key =await GetSaveKey(path); string baseUrl = options.Domain.Trim(); baseUrl = baseUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || baseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ? baseUrl : "http://" + baseUrl; var privateUrl = DownloadManager.CreatePrivateUrl(mac, baseUrl, key, 3600); return privateUrl; } public async Task GetFileData(string path, CancellationToken token = default) { var url =await GetDownloadUrl(path); HttpClient client = new HttpClient(); return await client.GetByteArrayAsync(url); } async Task GetInfo(string path) => await GetBucketManager().Stat(options.Bucket,await GetSaveKey(path)); //Task.FromResult(GetBucketManager().Stat(options.Bucket, GetSaveKey(path))); public async Task GetModifyDate(string path, CancellationToken token = default) { var result = await GetInfo(path); if (result.Code == (int)HttpCode.OK) { return new DateTime(result.Result.PutTime); } throw new Exception(result.Text); } public async Task GetStream(string path, CancellationToken token = default) { var url =await GetDownloadUrl(path); HttpClient client = new HttpClient(); return await client.GetStreamAsync(url); } BucketManager GetBucketManager() => new BucketManager(mac, config); public async Task Move(string sourceFileName, string destFileName) { BucketManager bucket = GetBucketManager(); //var result = await Task.FromResult(bucket.Move(options.Bucket, GetSaveKey(sourceFileName), options.Bucket, GetSaveKey(destFileName))); var result = await bucket.Move(options.Bucket,await GetSaveKey(sourceFileName), options.Bucket,await GetSaveKey(destFileName)); if (result.Code != (int)HttpCode.OK) { throw new Exception(result.Text); } } Task GetSaveKey(string path) { return contextAccessor.GetSaveKey(options.BasePath, path); } string GetToken(string savekey) { return Utils.GetToken(savekey, options.AccessKey, options.SecretKey, options.Bucket); //Mac mac = new Mac(options.AccessKey, options.SecretKey); //PutPolicy putPolicy = new PutPolicy(); //// 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY" //putPolicy.Scope = $"{options.Bucket}:{savekey}"; ////putPolicy.Scope = options.Bucket; //// 上传策略有效期(对应于生成的凭证的有效期) //putPolicy.SetExpires(3600); //// 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除 ////putPolicy.DeleteAfterDays = 1; //// 生成上传凭证,参见 //// https://developer.qiniu.com/kodo/manual/upload-token //string jstr = putPolicy.ToJsonString(); //var token = Auth.CreateUploadToken(mac, jstr); //return token; } UploadManager GetUploadManager() { return new UploadManager(config); } public async Task Save(string path, Stream stream, CancellationToken token = default) { if (stream == null || stream.Length == 0) return false; if (stream.CanSeek && stream.Position > 0) { stream.Position = 0; } byte[] data = new byte[stream.Length]; await stream.ReadAsync(data, 0, data.Length); return await Save(path, data, token); //不能用UploadStream方法,因为方法里面会释放掉数据流,数据量在作用域内释放会导致很多问题 } public async Task Save(string path, byte[] data, CancellationToken token = default) { var key =await GetSaveKey(path); var uploadManager = GetUploadManager(); //var result = await Task.FromResult(uploadManager.UploadData(data, key, GetToken(key), null)); var result = await uploadManager.UploadData(data, key, GetToken(key), null); return result.Code == (int)HttpCode.OK; } } }