package com.example.service.base; import com.example.repository.FirestoreBaseRepository; import com.google.cloud.firestore.CollectionReference; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.QueryDocumentSnapshot; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @Service public class DataPurgeService { private static final Logger logger = LoggerFactory.getLogger(DataPurgeService.class); private final ReactiveRedisTemplate redisTemplate; private final FirestoreBaseRepository firestoreBaseRepository; private final Firestore firestore; @Autowired public DataPurgeService( @Qualifier("reactiveRedisTemplate") ReactiveRedisTemplate redisTemplate, FirestoreBaseRepository firestoreBaseRepository, Firestore firestore) { this.redisTemplate = redisTemplate; this.firestoreBaseRepository = firestoreBaseRepository; this.firestore = firestore; } public Mono purgeAllData() { return purgeRedis() .then(purgeFirestore()); } private Mono purgeRedis() { logger.info("Starting Redis data purge."); return redisTemplate.getConnectionFactory().getReactiveConnection().serverCommands().flushAll() .doOnSuccess(v -> logger.info("Successfully purged all data from Redis.")) .doOnError(e -> logger.error("Error purging data from Redis.", e)) .then(); } private Mono purgeFirestore() { logger.info("Starting Firestore data purge."); return Mono.fromRunnable(() -> { try { String appId = firestoreBaseRepository.getAppId(); String conversationsCollectionPath = String.format("artifacts/%s/conversations", appId); String notificationsCollectionPath = String.format("artifacts/%s/notifications", appId); // Delete 'mensajes' sub-collections in 'conversations' logger.info("Deleting 'mensajes' sub-collections from '{}'", conversationsCollectionPath); try { List conversationDocuments = firestore.collection(conversationsCollectionPath).get().get().getDocuments(); for (QueryDocumentSnapshot document : conversationDocuments) { String messagesCollectionPath = document.getReference().getPath() + "/mensajes"; logger.info("Deleting sub-collection: {}", messagesCollectionPath); firestoreBaseRepository.deleteCollection(messagesCollectionPath, 50); } } catch (Exception e) { if (e.getMessage().contains("NOT_FOUND")) { logger.warn("Collection '{}' not found, skipping.", conversationsCollectionPath); } else { throw e; } } // Delete the 'conversations' collection logger.info("Deleting collection: {}", conversationsCollectionPath); try { firestoreBaseRepository.deleteCollection(conversationsCollectionPath, 50); } catch (Exception e) { if (e.getMessage().contains("NOT_FOUND")) { logger.warn("Collection '{}' not found, skipping.", conversationsCollectionPath); } else { throw e; } } // Delete the 'notifications' collection logger.info("Deleting collection: {}", notificationsCollectionPath); try { firestoreBaseRepository.deleteCollection(notificationsCollectionPath, 50); } catch (Exception e) { if (e.getMessage().contains("NOT_FOUND")) { logger.warn("Collection '{}' not found, skipping.", notificationsCollectionPath); } else { throw e; } } logger.info("Successfully purged Firestore collections."); } catch (Exception e) { logger.error("Error purging Firestore collections.", e); throw new RuntimeException("Failed to purge Firestore collections.", e); } }).subscribeOn(Schedulers.boundedElastic()).then(); } }