package com.krylov.refound.health; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import com.krylov.refound.config.MinioProperties; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.BucketLifecycleConfiguration; import software.amazon.awssdk.services.s3.model.BucketVersioningStatus; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; import software.amazon.awssdk.services.s3.model.ExpirationStatus; import software.amazon.awssdk.services.s3.model.HeadBucketRequest; import software.amazon.awssdk.services.s3.model.LifecycleRule; import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.services.s3.model.PutBucketLifecycleConfigurationRequest; import software.amazon.awssdk.services.s3.model.PutBucketVersioningRequest; import software.amazon.awssdk.services.s3.model.VersioningConfiguration; import java.util.List; /** * Сервис для управления структурой хранилища в MinIO. * Отвечает за создание необходимого бакета при запуске приложения. */ @Service @Slf4j @RequiredArgsConstructor public class StorageStructureService { private final S3Client s3Client; private final MinioProperties properties; /** * Инициализирует структуру хранилища при запуске приложения. * Вызывает метод createBuckets(). */ @EventListener(ContextRefreshedEvent.class) public void init() { createBuckets(); } /** * Создает основной бакет в MinIO, если он еще не существует. */ public void createBuckets() { log.info("Инициализация основного бакета MinIO..."); String mainBucket = properties.bucket(); createBucketIfNotExists(mainBucket); log.info("Проверка и создание основного бакета завершены."); try { log.info("Включение версионирования для бакета '{}'...", mainBucket); VersioningConfiguration versioningConfiguration = VersioningConfiguration.builder() .status(BucketVersioningStatus.ENABLED) .build(); PutBucketVersioningRequest request = PutBucketVersioningRequest.builder() .bucket(mainBucket) .versioningConfiguration(versioningConfiguration) .build(); s3Client.putBucketVersioning(request); log.info("Версионирование для бакета '{}' успешно включено.", mainBucket); } catch (Exception e) { log.error("Не удалось включить версионирование для бакета '{}': {}", mainBucket, e.getMessage(), e); } try { log.info("Установка политики жизненного цикла для бакета '{}'...", mainBucket); LifecycleRule rule = LifecycleRule.builder() .id("delete-after-180-days-rule") .status(ExpirationStatus.ENABLED) .filter(f -> f.prefix("")) .expiration(exp -> exp.days(180)) .build(); BucketLifecycleConfiguration lifecycleConfig = BucketLifecycleConfiguration.builder() .rules(List.of(rule)) .build(); PutBucketLifecycleConfigurationRequest request = PutBucketLifecycleConfigurationRequest.builder() .bucket(mainBucket) .lifecycleConfiguration(lifecycleConfig) .build(); s3Client.putBucketLifecycleConfiguration(request); log.info("Политика жизненного цикла для бакета '{}' успешно установлена.", mainBucket); } catch (Exception e) { log.error("Не удалось установить политику жизненного цикла для бакета '{}': {}", mainBucket, e.getMessage(), e); } } /** * Проверяет существование бакета в MinIO и создает его, если он отсутствует. * * @param bucketName Имя бакета для проверки и создания. */ private void createBucketIfNotExists(String bucketName) { try { log.debug("Проверка существования бакета: {}", bucketName); s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build()); log.info("Бакет '{}' уже существует.", bucketName); } catch (NoSuchBucketException e) { log.warn("Бакет '{}' не найден. Попытка создания...", bucketName); try { s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build()); log.info("Бакет '{}' успешно создан.", bucketName); } catch (Exception ex) { log.error("Ошибка при создании бакета '{}': {}", bucketName, ex.getMessage(), ex); } } catch (Exception e) { log.error("Ошибка при проверке бакета '{}': {}", bucketName, e.getMessage(), e); } } }