package ar.com.companeros.runtime; import com.google.gson.*; import java.nio.file.*; import java.nio.charset.StandardCharsets; import java.io.IOException; import java.util.*; /** Límites y fuentes permitidas de investigación web; el presupuesto sigue siendo global. */ public record ResearchConfig(boolean enabled, int maxRequestsHour, int minAgentIntervalSeconds, Set allowedDomains) { public ResearchConfig { allowedDomains = Set.copyOf(allowedDomains); if (maxRequestsHour < 1 || maxRequestsHour > 12 || minAgentIntervalSeconds < 300 || minAgentIntervalSeconds > 86400 || allowedDomains.isEmpty() || allowedDomains.size() > 32 || allowedDomains.stream().anyMatch(domain -> !domain.matches("[a-z0-9][a-z0-9.-]{1,200}\\.[a-z]{2,20}"))) throw new IllegalArgumentException("Configuración de investigación inválida"); } public static ResearchConfig defaults() { return new ResearchConfig(false, 4, 900, Set.of("minecraft.wiki", "createmod.com", "github.com", "modrinth.com", "curseforge.com")); } public static ResearchConfig load(Path directory) throws IOException { Files.createDirectories(directory); Path file = directory.resolve("research.json"); if (!Files.exists(file)) { ResearchConfig initial = defaults(); JsonObject data = new JsonObject(); data.addProperty("schemaVersion", 1); data.addProperty("enabled", false); data.addProperty("maxRequestsHour", initial.maxRequestsHour()); data.addProperty("minAgentIntervalSeconds", initial.minAgentIntervalSeconds()); JsonArray domains = new JsonArray(); initial.allowedDomains().stream().sorted().forEach(domains::add); data.add("allowedDomains", domains); Files.writeString(file, new GsonBuilder().setPrettyPrinting().create().toJson(data) + "\n", StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW); } if (Files.isSymbolicLink(file) || Files.size(file) > 8192) throw new IOException("research.json fuera de límite"); JsonObject data = JsonParser.parseString(Files.readString(file, StandardCharsets.UTF_8)).getAsJsonObject(); if (!Set.of("schemaVersion", "enabled", "maxRequestsHour", "minAgentIntervalSeconds", "allowedDomains").equals(data.keySet()) || data.get("schemaVersion").getAsInt() != 1) throw new IOException("Formato de investigación desconocido"); Set domains = new HashSet<>(); for (JsonElement value : data.getAsJsonArray("allowedDomains")) domains.add(value.getAsString()); return new ResearchConfig(data.get("enabled").getAsBoolean(), data.get("maxRequestsHour").getAsInt(), data.get("minAgentIntervalSeconds").getAsInt(), domains); } }