package ru.kirillius.pf.sdn.service; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import ru.kirillius.pf.sdn.Util.WorkerUtils; import ru.kirillius.pf.sdn.api.Networking.DomainResolver; import java.net.Inet4Address; import java.time.Duration; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @Service @RequiredArgsConstructor @Slf4j public class DomainUpdaterService { private final DomainCacheService domainCacheService; private final DomainResolver domainResolver; private final ExecutorService executor; private final SubscriptionService subscriptionService; public List getActualAddresses(String domain) { var cached = domainCacheService.load(domain, true); if (!cached.isEmpty()) { var resolved = domainResolver.getAddresses(domain); while (!resolved.isDone() && !resolved.isCancelled()) { Thread.yield(); } if (resolved.isDone()) { try { domainCacheService.update(domain, resolved.get()); cached.addAll(resolved.get()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } } return cached; } private Future worker; private final RuntimeConfigService configService; @PostConstruct private void initialize() { worker = executor.submit(() -> new WorkerUtils.LoopedWorker() { @Override protected void doWork() { subscriptionService.getSubscriptions().forEach(subscription -> { var scope = subscription.getScope(); if (scope.getResolveDomains().isEmpty()) { return; } scope.getDomains().forEach(domain -> { var future = domainResolver.getAddresses(domain); while (!future.isDone() && !future.isCancelled()) { Thread.yield(); } if (future.isDone()) { try { domainCacheService.update(domain, future.get()); } catch (InterruptedException | ExecutionException e) { log.error("Domain {} resolve failed", domain); } } }); }); WorkerUtils.waitForTimer(() -> Duration.ofMinutes(configService.getConfig().getDomainResolveInterval())); } }); } @PreDestroy private void destroy() { if (worker != null) { worker.cancel(true); worker = null; } } }