网站首页 网站源码
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;
    }
}
loading