using Minio; using Minio.DataModel.Args; using Minio.Exceptions; namespace RobotNet.RobotManager.Services; public class RobotEditorStorageRepository { private class MinioOption { public bool UsingLocal { get; set; } public string? Endpoint { get; set; } public string? User { get; set; } public string? Password { get; set; } public string? Bucket { get; set; } } private readonly IMinioClient MinioClient; private readonly MinioOption MinioOptions = new(); public RobotEditorStorageRepository(IConfiguration configuration) { configuration.Bind("MinIO", MinioOptions); MinioClient = new MinioClient() .WithEndpoint(MinioOptions.Endpoint) .WithCredentials(MinioOptions.User, MinioOptions.Password) .WithSSL(false) .Build(); } public async Task<(bool, string)> UploadAsync(string path, string objectName, Stream data, long size, string contentType, CancellationToken cancellationToken) { try { if (!MinioOptions.UsingLocal) { var beArgs = new BucketExistsArgs().WithBucket(MinioOptions.Bucket); bool found = await MinioClient.BucketExistsAsync(beArgs, cancellationToken).ConfigureAwait(false); if (!found) { var mbArgs = new MakeBucketArgs() .WithBucket(MinioOptions.Bucket); await MinioClient.MakeBucketAsync(mbArgs, cancellationToken).ConfigureAwait(false); } var getListBucketsTask = await MinioClient.ListBucketsAsync(cancellationToken); var putObjectArgs = new PutObjectArgs() .WithBucket(MinioOptions.Bucket) .WithObject($"{path}/{objectName}") .WithObjectSize(size) .WithStreamData(data) .WithContentType(contentType); await MinioClient.PutObjectAsync(putObjectArgs, cancellationToken).ConfigureAwait(false); return (true, ""); } var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket; if (!Directory.Exists(mapImageFolder)) Directory.CreateDirectory(mapImageFolder); var pathLocal = Path.Combine(mapImageFolder, $"{objectName}.png"); if (File.Exists($"{pathLocal}.bk")) File.Delete($"{pathLocal}.bk"); if (File.Exists(pathLocal)) File.Move(pathLocal, $"{pathLocal}.bk"); using (Stream fileStream = new FileStream(pathLocal, FileMode.Create)) { await data.CopyToAsync(fileStream, cancellationToken); } return (true, ""); } catch (MinioException ex) { return (false, ex.Message); } } public (bool usingLocal, string url) GetUrl(string path, string objectName) { try { if (!MinioOptions.UsingLocal) { var presignedGetObjectArgs = new PresignedGetObjectArgs() .WithBucket(MinioOptions.Bucket) .WithObject($"{path}/{objectName}") .WithExpiry(60 * 60 * 24); var url = MinioClient.PresignedGetObjectAsync(presignedGetObjectArgs); url.Wait(); return (false, url.Result); } var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket; if (Directory.Exists(mapImageFolder)) { var pathLocal = Path.Combine(mapImageFolder, $"{objectName}.png"); if (File.Exists(pathLocal)) { return (true, pathLocal); } } return (true, ""); } catch (MinioException e) { return (false, e.Message); } } public async Task<(bool, string)> DeleteAsync(string path, string objectName, CancellationToken cancellationToken) { try { if (!MinioOptions.UsingLocal) { var removeObjectArgs = new RemoveObjectArgs() .WithBucket(MinioOptions.Bucket) .WithObject($"{path}/{objectName}"); await MinioClient.RemoveObjectAsync(removeObjectArgs, cancellationToken).ConfigureAwait(false); return (true, ""); } var mapImageFolder = string.IsNullOrEmpty(MinioOptions.Bucket) ? "MapImages" : MinioOptions.Bucket; if (Directory.Exists(mapImageFolder)) { var pathLocal = Path.Combine(mapImageFolder, $"{objectName}.png"); if (File.Exists(pathLocal)) File.Delete(pathLocal); if (File.Exists($"{pathLocal}.bk")) File.Delete($"{pathLocal}.bk"); } return (true, ""); } catch (MinioException ex) { return (false, ex.Message); } } }