2024-07-10 00:52:51 +08:00
|
|
|
#nullable enable
|
|
|
|
|
using System;
|
2021-06-03 13:43:46 +08:00
|
|
|
using System.IO;
|
|
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
using Minio;
|
2024-04-16 06:57:56 +08:00
|
|
|
using SimApi.Configurations;
|
2021-06-03 13:43:46 +08:00
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
namespace SimApi.Helpers;
|
|
|
|
|
|
|
|
|
|
public class SimApiStorage
|
2021-06-03 13:43:46 +08:00
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
private MinioClient Mc { get; }
|
|
|
|
|
|
|
|
|
|
public MinioClient Client => Mc;
|
|
|
|
|
|
|
|
|
|
private string ServeUrl { get; }
|
|
|
|
|
|
2024-07-10 00:52:51 +08:00
|
|
|
private string Endpoint { get; }
|
|
|
|
|
|
2024-06-27 04:38:04 +08:00
|
|
|
public string Bucket { get; }
|
2024-03-23 07:29:43 +08:00
|
|
|
|
|
|
|
|
private IHttpContextAccessor HttpContextAccessor { get; }
|
|
|
|
|
|
|
|
|
|
public SimApiStorage(SimApiOptions apiOptions, IHttpContextAccessor httpContextAccessor)
|
2021-06-03 13:43:46 +08:00
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
var options = apiOptions.SimApiStorageOptions;
|
|
|
|
|
HttpContextAccessor = httpContextAccessor;
|
2024-07-10 00:52:51 +08:00
|
|
|
Endpoint = options.Endpoint;
|
2024-03-23 07:29:43 +08:00
|
|
|
var useSsl = false;
|
|
|
|
|
string endpoint;
|
|
|
|
|
if (options.Endpoint.StartsWith("http://"))
|
2021-06-03 13:43:46 +08:00
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
endpoint = options.Endpoint.Replace("http://", string.Empty);
|
|
|
|
|
}
|
|
|
|
|
else if (options.Endpoint.StartsWith("https://"))
|
|
|
|
|
{
|
|
|
|
|
endpoint = options.Endpoint.Replace("https://", string.Empty);
|
|
|
|
|
useSsl = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("SimApiStorage: Error Endpoint");
|
2021-06-03 13:43:46 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
ServeUrl = options.ServeUrl;
|
2024-07-10 00:52:51 +08:00
|
|
|
if (ServeUrl.EndsWith('/')) throw new Exception("SimApiStorage: ServeUrl must not end with /");
|
2024-03-23 07:29:43 +08:00
|
|
|
Bucket = options.Bucket;
|
|
|
|
|
var mcb = new MinioClient().WithEndpoint(endpoint)
|
|
|
|
|
.WithCredentials(options.AccessKey, options.SecretKey);
|
|
|
|
|
if (useSsl)
|
2021-09-29 02:37:14 +08:00
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
mcb = mcb.WithSSL();
|
2021-09-29 02:37:14 +08:00
|
|
|
}
|
2024-04-16 06:57:56 +08:00
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
Mc = mcb.Build();
|
2021-09-29 02:37:14 +08:00
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
var found = Mc.BucketExistsAsync(new BucketExistsArgs().WithBucket(Bucket)).Result;
|
|
|
|
|
if (!found)
|
2021-06-03 13:43:46 +08:00
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
Mc.MakeBucketAsync(new MakeBucketArgs().WithBucket(Bucket)).Wait();
|
2021-06-03 13:43:46 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取上传的URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <param name="expire"></param>
|
|
|
|
|
/// <returns></returns>
|
2024-07-10 00:52:51 +08:00
|
|
|
public GetUploadUrlResponse GetUploadUrl(string path, int expire = 7200)
|
2024-03-23 07:29:43 +08:00
|
|
|
{
|
2024-07-10 00:52:51 +08:00
|
|
|
CheckPath(path);
|
|
|
|
|
var obj = path.TrimStart('/');
|
|
|
|
|
var uploadUrl = Mc.PresignedPutObjectAsync(new PresignedPutObjectArgs().WithBucket(Bucket)
|
|
|
|
|
.WithObject(obj).WithExpiry(expire)).Result;
|
|
|
|
|
return new GetUploadUrlResponse(uploadUrl, $"{ServeUrl}{path}", path);
|
2024-03-23 07:29:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取下载的URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <param name="expire"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string GetDownloadUrl(string path, int expire = 600)
|
|
|
|
|
{
|
2024-07-10 00:52:51 +08:00
|
|
|
CheckPath(path);
|
|
|
|
|
path = path.TrimStart('/');
|
2024-03-23 07:29:43 +08:00
|
|
|
return Mc.PresignedGetObjectAsync(new PresignedGetObjectArgs().WithBucket(Bucket).WithObject(path)
|
|
|
|
|
.WithExpiry(expire)).Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-07-10 00:52:51 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 直接上传文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <param name="stream"></param>
|
|
|
|
|
/// <param name="contentType"></param>
|
|
|
|
|
public void UploadFile(string path, Stream stream, string contentType = "image/png")
|
2024-03-23 07:29:43 +08:00
|
|
|
{
|
2024-07-10 00:52:51 +08:00
|
|
|
CheckPath(path);
|
|
|
|
|
path = path.TrimStart('/');
|
2024-03-23 07:29:43 +08:00
|
|
|
Mc.PutObjectAsync(new PutObjectArgs().WithBucket(Bucket).WithObject(path).WithObjectSize(stream.Length)
|
|
|
|
|
.WithStreamData(stream).WithContentType(contentType)).Wait();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-10 00:52:51 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 使用path获取完整的访问URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2024-03-23 07:29:43 +08:00
|
|
|
public string FullUrl(string path)
|
|
|
|
|
{
|
2024-07-10 00:52:51 +08:00
|
|
|
if(path.StartsWith("http://") || path.StartsWith("https://")) return path;
|
|
|
|
|
if (!(path.StartsWith('/') || path.StartsWith("~/"))) throw new Exception("path must start with / or ~/");
|
2024-03-23 07:29:43 +08:00
|
|
|
var httpRequest = HttpContextAccessor.HttpContext?.Request;
|
|
|
|
|
var url = $"{httpRequest?.Scheme}://{httpRequest?.Host}";
|
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
|
|
|
{
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return path.StartsWith('~') ? string.Concat(url, path.AsSpan(1, path.Length - 1)) : $"{ServeUrl}{path}";
|
|
|
|
|
}
|
2024-07-10 00:52:51 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从URL中获取相对路径 (如果url不是当前服务器的url,则原样返回)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="url"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string? GetPath(string? url)
|
|
|
|
|
{
|
2024-07-10 01:18:18 +08:00
|
|
|
return url?.Replace($"{Endpoint}/{Bucket}", string.Empty);
|
2024-07-10 00:52:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CheckPath(string path)
|
|
|
|
|
{
|
|
|
|
|
if (!path.StartsWith('/')) throw new Exception("path must start with /");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public record GetUploadUrlResponse(string UploadUrl, string DownloadUrl, string Path);
|