网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.Security.Cryptography;
using Dpz.Core.Infrastructure;
using Dpz.Core.Infrastructure.PublicStruct;
using Dpz.Core.Public.ViewModel.V4;
using Dpz.Core.Shard.Service;
using FluentFTP;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;

namespace Dpz.Core.Service.ObjectStorage.Services.Impl;

public class ObjectStorageService(
    UpyunOperator upyunOperator,
    HttpClient httpClient,
    ILogger<ObjectStorageService> logger,
    IFtpLogger ftpLogger,
    ParallelChunkBreakpointUpload<UpyunOperator> parallelChunkBreakpointUpload,
    UpyunUpload upyunUpload)
    : IObjectStorageOperation
{
    private const string FtpHost = "v0.ftp.upyun.com";

    public string Bucket => upyunOperator.Bucket ?? throw new BusinessException("Bucket is null");

    public async Task<UploadResult> UploadAsync(Stream stream, ICollection<string> path, string filename)
    {
        return await UploadAsync(path, filename, () => new StreamContent(stream));
    }

    private async Task<UploadResult> UploadAsync(
        IEnumerable<string> path,
        string filename,
        Func<HttpContent> setContent,
        string? contentMd5 = null)
    {
        if (string.IsNullOrEmpty(filename))
            throw new ArgumentNullException(nameof(filename));
        var pathList = path.ToList();
        pathList.Add(filename);

        return await UploadAsync(pathList, setContent, contentMd5);
    }

    private async Task<UploadResult> UploadAsync(
        ICollection<string> pathToFile,
        Func<HttpContent> setContent,
        string? contentMd5 = null)
    {
        return await upyunUpload.UploadAsync(
            pathToFile, 
            setContent, 
            upyunOperator, 
            contentMd5);
    }

    public async Task<FileAddress?> UploadFileAsync(CloudFile file)
    {
        return await parallelChunkBreakpointUpload.UploadFileAsync(file, UploadAsync);
    }


    public async Task<UploadResult> UploadAsync(byte[] bytes, ICollection<string> path, string filename)
    {
        return await UploadAsync(path, filename, () => new ByteArrayContent(bytes));
    }

    private string CalculateMd5(byte[] bytes)
    {
        using var md5 = MD5.Create();
        var hash = md5.ComputeHash(bytes);
        return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
    }

    private async Task<string> GetImageFormatAsync(byte[] bytes)
    {
        try
        {
            using var stream = new MemoryStream(bytes);
            using var image = await Image.LoadAsync(stream);
            return image.Metadata.DecodedImageFormat?.FileExtensions.FirstOrDefault() ?? "jpg";
        }
        catch (Exception e)
        {
            logger.LogError(e, "get image format fail");
            return "jpg";
        }
    }

    public async Task<VmPictureRecord> UploadPictureAsync(byte[] bytes, PictureInformation information)
    {
        if (bytes == null)
            throw new ArgumentNullException(nameof(bytes));
        if (information == null)
            throw new ArgumentNullException(nameof(information));

        var pictureRecord = new VmPictureRecord
        {
            Creator = information.Uploader,
            UploadTime = DateTime.Now,
            Tags = information.Tags.ToList(),
            Description = information.Description,
            Category = information.Category
        };

        var filename = $"{information.Name ?? Guid.NewGuid().ToString("N")}.{await GetImageFormatAsync(bytes)}";

        var uploadResult = await UploadAsync(new[] { "images", "album", DateTime.Now.ToString("yyyy-MM-dd") }, filename,
            () => new ByteArrayContent(bytes));

        pictureRecord.AccessUrl = uploadResult.AccessUrl;
        pictureRecord.Length = bytes.Length;
        pictureRecord.ObjectStorageUploadTime = DateTime.Now;
        pictureRecord.Md5 = CalculateMd5(bytes);
        pictureRecord.Width = uploadResult.Width;
        pictureRecord.Height = uploadResult.Height;

        return pictureRecord;
    }

    public async Task<Stream> DownloadAsync(string pathToFile)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, $"/{Bucket}/{pathToFile}")
        {
            Version = new Version(2, 0)
        };
        await request.SignatureAsync(upyunOperator);
        var response = await httpClient.SendAsync(request);
        if (!response.IsSuccessStatusCode)
        {
            logger.LogError("download fail,status code:{StatusCode}", response.StatusCode);
            throw new BusinessException($"download fail,response status code:{response.StatusCode}");
        }

        var stream = await response.Content.ReadAsStreamAsync();
        return stream;
    }

    public async Task SaveAsAsync(string pathToFile, string path)
    {
        if (string.IsNullOrEmpty(pathToFile))
            throw new ArgumentNullException(nameof(pathToFile));
        if (string.IsNullOrEmpty(path))
            throw new ArgumentNullException(nameof(path));
        var stream = await DownloadAsync(pathToFile);
        await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
        await stream.CopyToAsync(fileStream);
        await fileStream.FlushAsync();
    }

    public async Task DeleteAsync(string pathToFile)
    {
        if (string.IsNullOrEmpty(pathToFile))
            throw new ArgumentNullException(nameof(pathToFile));
        if (pathToFile.StartsWith("http", StringComparison.OrdinalIgnoreCase))
        {
            pathToFile =
                pathToFile.Replace(
                    upyunOperator.Host ??
                    throw new BusinessException("configuration upyun operator host value is null"), "");
        }
        else
        {
            pathToFile = !pathToFile.StartsWith('/') ? $"/{pathToFile}" : pathToFile;
        }

        var request = new HttpRequestMessage(HttpMethod.Delete, $"/{Bucket}{pathToFile}")
        {
            Version = new Version(2, 0)
        };
        await request.SignatureAsync(upyunOperator);
        var response = await httpClient.SendAsync(request);
        if (!response.IsSuccessStatusCode)
        {
            logger.LogError("delete fail,status code:{StatusCode}", response.StatusCode);
        }
    }

    public async Task<IList<FolderResult>> GetFolderListAsync(string path)
    {
        if (path == null)
            throw new ArgumentNullException(nameof(path));
        try
        {
            await using var client = new AsyncFtpClient(
                FtpHost,
                $"{upyunOperator.Operator}/{upyunOperator.Bucket}",
                upyunOperator.Password,
                logger: ftpLogger);

            await client.Connect();
            //await client.AutoConnectAsync();

            var list = new List<FolderResult>();
            foreach (var item in await client.GetListing(path))
            {
                var result = new FolderResult
                {
                    LastUpdateTime = item.Modified,
                    Name = item.Name
                };
                if (item.Type == FtpObjectType.Directory)
                {
                    result.FileType = FileType.Directory;
                }
                else
                {
                    result.FileType = FileType.File;
                    result.Size = await client.GetFileSize(item.FullName);
                }

                list.Add(result);
            }

            await client.Disconnect();
            return list;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "get folder list fail");
            return new List<FolderResult>();
        }
    }

    public async Task<FileInformation> GetFileInformationAsync(string pathToFile)
    {
        if (string.IsNullOrEmpty(pathToFile))
            throw new ArgumentNullException(nameof(pathToFile));
        pathToFile = !pathToFile.StartsWith('/') ? $"/{pathToFile}" : pathToFile;

        var request = new HttpRequestMessage(HttpMethod.Head, $"/{Bucket}{pathToFile}")
        {
            Version = new Version(2, 0)
        };
        await request.SignatureAsync(upyunOperator);
        var response = await httpClient.SendAsync(request);
        if (!response.IsSuccessStatusCode)
        {
            logger.LogError("delete fail,status code:{StatusCode}", response.StatusCode);
            throw new BusinessException($"delete fail,response status code:{response.StatusCode}");
        }

        // response.Headers.Contains("x-upyun-frames")
        //     ? response.Headers.GetValues("x-upyun-file-size").FirstOrDefault() ?? "0"
        //     : "0";
        response.Headers.TryGetValues("x-upyun-file-size", out var size);
        long.TryParse(size?.FirstOrDefault() ?? "0", out var length);

        response.Headers.TryGetValues("x-upyun-file-date", out var date);

        long.TryParse(date?.FirstOrDefault() ?? "0", out var timespan);

        var dateTime = timespan.ToDateTime();

        response.Headers.TryGetValues("Content-Md5", out var md5);

        var information = new FileInformation
        {
            Length = length,
            Md5 = md5?.FirstOrDefault() ?? "",
            UploadTime = dateTime
        };

        return information;
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码定义了一个名为 ObjectStorageService 的类,它实现了 IObjectStorageOperation 接口,主要用于与对象存储服务(如 Upyun)进行交互。该类提供了一系列方法来上传、下载、删除文件,以及获取文件信息和文件夹列表。以下是对代码功能的详细解释:

主要功能

  1. 上传文件:

    • UploadAsync(Stream stream, ICollection<string> path, string filename):通过流上传文件。
    • UploadAsync(byte[] bytes, ICollection<string> path, string filename):通过字节数组上传文件。
    • UploadPictureAsync(byte[] bytes, PictureInformation information):上传图片并返回图片记录,包括上传者、时间、标签、描述等信息。
  2. 下载文件:

    • DownloadAsync(string pathToFile):根据文件路径下载文件并返回文件流。
    • SaveAsAsync(string pathToFile, string path):将下载的文件保存到指定路径。
  3. 删除文件:

    • DeleteAsync(string pathToFile):根据文件路径删除文件。
  4. 获取文件和文件夹信息:

    • GetFileInformationAsync(string pathToFile):获取指定文件的元数据,包括文件大小、MD5 值和上传时间。
    • GetFolderListAsync(string path):获取指定路径下的文件夹和文件列表。
  5. 计算 MD5 值:

    • CalculateMd5(byte[] bytes):计算给定字节数组的 MD5 值。
  6. 获取图片格式:

    • GetImageFormatAsync(byte[] bytes):根据字节数组获取图片格式,使用 ImageSharp 库来解析图片。

代码结构

  • 构造函数:接受多个依赖项(如 UpyunOperatorHttpClientILogger 等),用于初始化对象存储服务。
  • 常量:定义了 FTP 主机地址 FtpHost
  • 属性:提供了 Bucket 属性,用于获取存储桶名称。
  • 异常处理:在多个方法中使用了异常处理,确保在出现错误时能够记录日志并抛出适当的异常。

依赖项

  • FluentFTP:用于与 FTP 服务器交互。
  • ImageSharp:用于处理和解析图像文件。
  • ILogger:用于记录日志信息。
  • HttpClient:用于发送 HTTP 请求。

总结

ObjectStorageService 类是一个功能丰富的服务类,封装了与对象存储服务的交互逻辑,提供了上传、下载、删除文件以及获取文件和文件夹信息的功能。它使用了现代的异步编程模式,确保在处理 I/O 操作时不会阻塞线程。

loading