using MegghysAPI.Attributes; using Minio; using Minio.DataModel.Args; namespace MegghysAPI.Core { internal class FileManager { private static IMinioClient minio = new MinioClient() .WithEndpoint(Config.Instance.MinIOEndpoint) .WithRegion(Config.Instance.MinIORegion) .WithCredentials(Config.Instance.MinIOAccessKey, Config.Instance.MinIOSecretKey) .WithSSL(false) .Build(); public const string FavoritePath = "/Files/Favorite/"; [AutoInit("初始化文件服务")] public static void Init() { } public static async Task DownloadFileAsync(string fileName, string path) { try { var temp = Path.Combine(Datas.TempFilePath, fileName); if (File.Exists(temp)) return temp; var result = await minio.GetObjectAsync(new Minio.DataModel.Args.GetObjectArgs() .WithBucket(Config.Instance.MinIOBucket) .WithObject(fileName) .WithCallbackStream(stream => { // 将下载流保存为本地文件 using var fileStream = File.Create(temp); stream.CopyTo(fileStream); })); return temp; } catch (Exception ex) { Logs.Warn($"未能从储存空间下载文件: {path}{fileName}\r\n{ex}"); return null; } } public static bool UploadBytes(byte[] data, string remotePath, string contentType = "application/octet-stream", bool overwrite = false) { using var stream = new MemoryStream(data); return UploadStream(stream, remotePath, contentType, overwrite: overwrite); } public static async Task UploadStreamAsync(Stream stream, string remotePath, string contentType = "application/octet-stream", bool overwrite = false) { try { if (!overwrite && await ContainsFileAsync(remotePath)) return true; // Upload a file to bucket. var putObjectArgs = new PutObjectArgs() .WithBucket(Config.Instance.MinIOBucket) .WithStreamData(stream) .WithObjectSize(stream.Length) .WithObject(remotePath) .WithContentType(contentType); await minio.PutObjectAsync(putObjectArgs); return true; } catch (Exception ex) { Logs.Warn($"未能向储存空间路径上传文件流 {remotePath}\r\n{ex}"); return false; } } public static bool UploadStream(Stream stream, string remotePath, string contentType = "application/octet-stream", bool overwrite = false) => UploadStreamAsync(stream, remotePath, contentType, overwrite).Result; /*public static async Task UploadFileAsync(string localFilePath, string remotePath = SetuPath, bool overwrite = false) { { try { if (!File.Exists(localFilePath)) return false; return await FTPConnection.UploadFile(localFilePath, remotePath, overwrite ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip); } catch (Exception ex) { Logs.Warn($"未能向储存空间路径上传文件 {localFilePath} => {remotePath}\r\n{ex}"); return FtpStatus.Failed; } } } public static FtpStatus UploadFile(string localFilePath, string remotePath = SetuPath, bool overwrite = false) => UploadFileAsync(localFilePath, remotePath, overwrite).Result;*/ public static async Task ListFilesNameAsync(string path) { return (await ListFilesAsync(path)).Select(x => x.Name).ToArray(); } public class MItem(Minio.DataModel.Item item) : Minio.DataModel.Item { public string Name { get; set; } = item.Key.Contains('/') ? item.Key[(item.Key.LastIndexOf('/') + 1)..] : item.Key; } public static async Task ListFilesAsync(string path, bool recursive = false, bool includeUserMetadata = false) { try { var result = minio.ListObjectsEnumAsync(new ListObjectsArgs() .WithBucket(Config.Instance.MinIOBucket) .WithRecursive(recursive) .WithIncludeUserMetadata(includeUserMetadata)); var fileList = new List(); if(fileList.Count == 0) { return []; } await foreach (var item in result) { fileList.Add(item); } return [.. fileList.Select(x => new MItem(x))]; } catch (Exception ex) { Logs.Warn($"未能列出储存空间中 {path} 的文件\r\n{ex}"); return null; } } public static async Task ContainsFileAsync(string path) { try { var stat = await minio.StatObjectAsync( new StatObjectArgs() .WithBucket(Config.Instance.MinIOBucket) .WithObject(path) ); return true; } catch { return false; } } } }