package dev.thinhha.tunnel_client.service; import dev.thinhha.tunnel_client.config.TunnelConfig; import dev.thinhha.tunnel_client.entity.RouteConfig; import dev.thinhha.tunnel_client.repository.RouteConfigRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service @RequiredArgsConstructor @Slf4j public class RouteResolver { private final TunnelConfig tunnelConfig; private final RouteConfigRepository routeConfigRepository; public String resolveTargetUrl(String path) { // First check database routes List matchingRoutes = routeConfigRepository.findMatchingRoutes(path); if (!matchingRoutes.isEmpty()) { RouteConfig bestMatch = matchingRoutes.get(0); log.debug("Resolved path '{}' to database target: {}", path, bestMatch.getTargetUrl()); return bestMatch.getTargetUrl(); } // Fallback to configuration routes if (tunnelConfig.getTarget().getRoutes() != null && !tunnelConfig.getTarget().getRoutes().isEmpty()) { String bestMatch = null; String bestMatchUrl = null; for (Map.Entry route : tunnelConfig.getTarget().getRoutes().entrySet()) { String routePath = route.getKey(); String targetUrl = route.getValue(); if (path.startsWith(routePath)) { if (bestMatch == null || routePath.length() > bestMatch.length()) { bestMatch = routePath; bestMatchUrl = targetUrl; } } } if (bestMatchUrl != null) { log.debug("Resolved path '{}' to config target: {}", path, bestMatchUrl); return bestMatchUrl; } } log.debug("No route match for path '{}', using default target: {}", path, tunnelConfig.getTarget().getDefaultUrl()); return tunnelConfig.getTarget().getDefaultUrl(); } public boolean isWebSocketTarget(String targetUrl) { return targetUrl.startsWith("ws://") || targetUrl.startsWith("wss://"); } public RouteConfig addRoute(String pathPattern, String targetUrl, Integer priority, String description) { RouteConfig route = new RouteConfig(); route.setPathPattern(pathPattern); route.setTargetUrl(targetUrl); route.setPriority(priority != null ? priority : 0); route.setDescription(description); route.setEnabled(true); return routeConfigRepository.save(route); } public void removeRoute(String pathPattern) { routeConfigRepository.findByEnabledTrueOrderByPriorityDescPathPatternDesc() .stream() .filter(route -> route.getPathPattern().equals(pathPattern)) .findFirst() .ifPresent(route -> { route.setEnabled(false); routeConfigRepository.save(route); }); } public List getAllRoutes() { return routeConfigRepository.findByEnabledTrueOrderByPriorityDescPathPatternDesc(); } }