using FileStorage.Extensions; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using XF.Domain.Dependency; using XF.Domain.Exceptions; namespace FileStorage; public class DefaultFileStorage : IFileStorage, IScopeDependency { private readonly IFileMetadataRepository _fileMetadataRepository; private readonly IOptionsSnapshot _fileUploadOptions; private readonly ILogger _logger; public DefaultFileStorage(IFileMetadataRepository fileMetadataRepository, IOptionsSnapshot optionsSnapshot, ILogger logger) { _fileMetadataRepository = fileMetadataRepository; _fileUploadOptions = optionsSnapshot; _logger = logger; } /// /// 本地上传 /// /// /// /// /// /// /// 是否验证文件格式 /// public async Task UploadAsync(string fileName, long length, string extraInfo, Stream fileData, string client, bool? isVerification) { if (fileName == null) { fileName = "unkown"; } fileName = fileName.Replace("<", "").Replace(">", "").Replace(" ", ""); var rv = UploadLoca(fileName, length, extraInfo, fileData, client, isVerification); if (!string.IsNullOrEmpty(rv)) { FileMetadata fileModel = new FileMetadata(); fileModel.Client = client; fileModel.FileName = fileName; var ext = string.Empty; if (string.IsNullOrEmpty(fileName) == false) { var dotPos = fileName.LastIndexOf('.'); ext = fileName[(dotPos + 1)..]; } fileModel.FileExt = ext; fileModel.Path = rv; fileModel.Length = length; fileModel.SaveMode = _fileUploadOptions.Value.Impt; fileModel.ExtraInfo = extraInfo; fileModel.UploadTime = DateTime.Now; await _fileMetadataRepository.AddAsync(fileModel); return fileModel; } return null; } public async Task GetFileUrlAsync(string id, string clientId) { var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); if (fileMetadata != null) { long sTime = (long)(DateTime.Now.AddHours(1).ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; string encryptText = clientId + "|" + sTime + "|" + id; var signatureText = DESExtensions.Encrypt(encryptText); return new Uri("/file/files?id=" + id + "&expires=" + sTime + "&clientid=" + clientId + "&signature=" + signatureText); //return new Uri(_fileUploadOptions.Value.Local.VisDomain+fileMetadata.Path); } throw new UserFriendlyException("无权限访问"); } public async Task GetFileUrlIndefinitelyAsync(string id, string clientId) { var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); if (fileMetadata != null) { long sTime = (long)(DateTime.Now.AddHours(1).ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; string encryptText = clientId + "|" + sTime + "|" + id; var signatureText = DESExtensions.Encrypt(encryptText); return new Uri("/file/files_indefinitely?id=" + id + "&expires=" + sTime + "&clientid=" + clientId + "&signature=" + signatureText); } throw new UserFriendlyException("无权限访问"); } public (Stream stream, string contentType, string fileName) DownLoadFile(string id, string clientId) { var fileMetadata = _fileMetadataRepository.Get(x => x.Id == id && x.Client == clientId); if (fileMetadata != null) { string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileMetadata.Path); var contentType = TaskGetFileContentTypeAsync(fileMetadata.Path); var stream = File.OpenRead(filePath); return (stream, contentType, fileMetadata.FileName); } throw new UserFriendlyException("无权限访问"); } public async Task DelFileAsync(string id, string clientId) { var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); if (fileMetadata != null) { string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileMetadata.Path); await _fileMetadataRepository.RemoveAsync(id); File.Delete(filePath); return true; } return false; } public async Task GetFilePathAsync(string id, string clientId) { var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); return fileMetadata?.Path!; } public async Task GetFilePath(string id, string expires, string clientId, string signature) { string decryptText = DESExtensions.Decrypt(signature); if (!string.IsNullOrEmpty(decryptText)) { string[] paramData = decryptText.Split('|'); if (id != paramData[2] || clientId != paramData[0] || expires != paramData[1]) throw UserFriendlyException.SameMessage("参数不合法"); if (long.Parse(paramData[1]) < ((long)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds)) throw UserFriendlyException.SameMessage("链接已过期"); var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); if (fileMetadata == null) throw UserFriendlyException.SameMessage("无权限访问"); return GetFullPath(fileMetadata.Path); } throw UserFriendlyException.SameMessage("无权限访问"); } public async Task GetFilePathIndefinitely(string id, string expires, string clientId, string signature) { string decryptText = DESExtensions.Decrypt(signature); if (!string.IsNullOrEmpty(decryptText)) { string[] paramData = decryptText.Split('|'); if (id != paramData[2] || clientId != paramData[0] || expires != paramData[1]) throw UserFriendlyException.SameMessage("参数不合法"); var fileMetadata = await _fileMetadataRepository.GetAsync(x => x.Id == id && x.Client == clientId); if (fileMetadata == null) throw UserFriendlyException.SameMessage("无权限访问"); return GetFullPath(fileMetadata.Path); } throw UserFriendlyException.SameMessage("无权限访问"); } private string TaskGetFileContentTypeAsync(string fileName) { string suffix = Path.GetExtension(fileName); var provider = new FileExtensionContentTypeProvider(); var contentType = provider.Mappings[suffix]; return contentType; } private string UploadLoca(string fileName, long length, string extraInfo, Stream fileData, string client, bool? isVerification) { var settings = _fileUploadOptions.Value.Local; string groupDir = ""; if (settings != null) { groupDir = settings.Path; } if (string.IsNullOrEmpty(groupDir)) { groupDir = "uploads"; } string sub = DateTime.Now.ToString("yyyyMMdd"); groupDir = Path.Combine(groupDir, client, sub); string pathHeader = groupDir; string fulldir = GetFullPath(pathHeader); _logger.LogInformation("路径:"+fulldir); if (!Directory.Exists(fulldir)) { Directory.CreateDirectory(fulldir); } _logger.LogInformation("已执行"); var ext = string.Empty; if (!string.IsNullOrEmpty(fileName)) { var dotPos = fileName.LastIndexOf('.'); if (dotPos == 0) { throw UserFriendlyException.SameMessage("文件没有格式,请重新上传文件"); } ext = fileName.Substring(dotPos + 1); } if (isVerification.HasValue && isVerification == true) { //TODO验证文件格式 var extList = new List(); extList.Add("txt"); extList.Add("xls"); extList.Add("xlsx"); extList.Add("jpg"); extList.Add("jpeg"); extList.Add("png"); extList.Add("doc"); extList.Add("docx"); extList.Add("rar"); extList.Add("pdf"); extList.Add("mp3"); extList.Add("zip"); extList.Add("wmv"); extList.Add("mp4"); extList.Add("svg"); extList.Add("avi"); //extList.Add("m4a"); if (!extList.Contains(ext)) { // throw UserFriendlyException.SameMessage("文件格式不正确,只能上传【doc,rar,jpg,pdf,mp3,xls,xlsx,zip,docx,wmv,mp4.png,svg,avijpeg.m4a.txt】格式文件"); throw UserFriendlyException.SameMessage("文件格式不正确,只能上传【doc,rar,jpg,pdf,mp3,xls,xlsx,zip,docx,wmv,mp4.png,svg,avi,jpeg,txt】格式文件"); } } var filename = $"{Guid.NewGuid().ToString().Replace("-", string.Empty)}.{ext}"; var fullPath = Path.Combine(fulldir, filename); using (var fileStream = File.Create(fullPath)) { fileData.CopyTo(fileStream); } fileData.Dispose(); return (Path.Combine(pathHeader, filename)); } private string GetFullPath(string path) { string rv = ""; if (path.StartsWith(".")) { rv = Path.Combine(Directory.GetCurrentDirectory(), path); } else { rv = path; } rv = Path.GetFullPath(rv); return rv; } }