From 8300f22e26fa2c662f1a559a0596b98f4df6f217 Mon Sep 17 00:00:00 2001 From: test Date: Wed, 4 Sep 2024 05:37:26 +1000 Subject: [PATCH] Spy tracker debug legacy setting --- .../discord/apiv2/PoliticsAndWarV2.java | 4 +- .../discord/apiv3/PoliticsAndWarV3.java | 42 ++++++++++++++----- .../apiv3/subscription/PnwPusherHandler.java | 3 +- .../commands/manager/CommandManager.java | 3 +- .../manager/v2/binding/annotation/Arg.java | 4 ++ .../manager/v2/impl/SlashCommandManager.java | 4 +- .../v2/impl/pw/commands/ConflictCommands.java | 4 +- .../pw/commands/PlayerSettingCommands.java | 39 +++++++++++++---- .../link/locutus/discord/config/Settings.java | 38 ++++++----------- .../link/locutus/discord/util/AlertUtil.java | 1 - .../link/locutus/discord/util/SpyTracker.java | 27 ++++++------ 11 files changed, 102 insertions(+), 67 deletions(-) diff --git a/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java b/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java index 61ea6a99..1b9571c9 100644 --- a/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java +++ b/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java @@ -95,11 +95,11 @@ public String read(PagePriority priority, QueryURLV2 url, String arg, String que String successStr = "success\":"; int successIndex = json.indexOf(successStr); if (successIndex == -1) { - throw new IOException("Invalid response: " + json + " for " + url.getUrl("XXXX", arg, query)); + throw new IOException("Invalid response: " + StringMan.stripApiKey(json) + " for " + url.getUrl("XXXX", arg, query)); } char tf = json.charAt(successIndex + successStr.length()); if (tf != 't') { - throw new IOException("Failed: " + json + " for " + url.getUrl("XXXX", arg, query)); + throw new IOException("Failed: " + StringMan.stripApiKey(json) + " for " + url.getUrl("XXXX", arg, query)); } String startStr = "\"data\":"; diff --git a/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java b/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java index 94e839ac..87079f0f 100644 --- a/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java +++ b/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java @@ -131,20 +131,23 @@ public enum ErrorResponse { } private static class RateLimit { + // Amount of requests allowed per interval public volatile int limit; + // The interval in milliseconds (typically 60_000) public volatile int intervalMs; - public volatile long resetAfterMs; + // The number of ms until the ratelimit resets (unused) + public volatile long resetAfterMs_unused; + // The remaining number of requests this interval public volatile int remaining; + // the unix epoch time in milliseconds when the ratelimit resets public volatile long resetMs; public void reset(long now) { if (now > resetMs) { remaining = limit; - long remainder = (now - resetMs) % intervalMs; - - resetAfterMs = intervalMs - remainder; - resetMs = now + resetAfterMs; + resetAfterMs_unused = intervalMs - remainder; + resetMs = now + resetAfterMs_unused; } } } @@ -171,7 +174,9 @@ public List readSnapshot(PagePriority priority, Clas JsonObject obj = JsonParser.parseString(body).getAsJsonObject(); String errorRaw = obj.get("error").getAsString(); if (errorRaw.equalsIgnoreCase("rate-limited")) { - Thread.sleep(30500); + long amt = 30_500; + setRateLimit(amt); + Thread.sleep(amt); continue; } else { errorMsg = errorRaw; @@ -189,7 +194,23 @@ public List readSnapshot(PagePriority priority, Clas if (body != null && !errorMsg.contains("rate-limited") && !errorMsg.contains("database error") && !errorMsg.contains("couldn't find api key")) { Logg.text("Unknown error with APIv3 Snapshot response: " + errorMsg + "\n\n---START BODY\n\n" + body + "\n\n---END BODY---\n\n"); } - rethrow(new IllegalArgumentException(errorMsg.replace(pair.getKey(), "XXX")), pair, true); + rethrow(new IllegalArgumentException(StringUtils.replaceIgnoreCase(errorMsg, pair.getKey(), "XXX")), pair, true); + } + } + + private void setRateLimit(long timeMs) { + synchronized (rateLimitGlobal) { + if (rateLimitGlobal.intervalMs == 0) { + rateLimitGlobal.intervalMs = 60_000; + } + if (rateLimitGlobal.limit == 0) { + rateLimitGlobal.limit = 60; + } + long now = System.currentTimeMillis(); + rateLimitGlobal.resetAfterMs_unused = timeMs; + rateLimitGlobal.remaining = 0; + rateLimitGlobal.resetMs = now + timeMs; + rateLimitGlobal.limit = 0; } } @@ -211,8 +232,9 @@ private void handleRateLimit() { throw new RuntimeException(e); } } + now = System.currentTimeMillis(); } - rateLimitGlobal.reset(System.currentTimeMillis()); + rateLimitGlobal.reset(now); rateLimitGlobal.remaining--; } } @@ -270,7 +292,7 @@ public T readTemplate(PagePriority priority, boolean pagination, GraphQLRequ } String message = errorMessages.isEmpty() ? errors.toString() : StringMan.join(errorMessages, "\n"); message = StringMan.stripApiKey(message); - rethrow(new IllegalArgumentException(message.replace(pair.getKey(), "XXX")), pair, true); + rethrow(new IllegalArgumentException(StringUtils.replaceIgnoreCase(message, pair.getKey(), "XXX")), pair, true); } result = jacksonObjectMapper.readValue(body, resultBody); @@ -338,7 +360,7 @@ public T readTemplate(PagePriority priority, boolean pagination, GraphQLRequ HttpHeaders header = exchange.getHeaders(); synchronized (rateLimitGlobal) { if (header.containsKey("X-RateLimit-Reset-After")) { - rateLimitGlobal.resetAfterMs = Long.parseLong(Objects.requireNonNull(header.get("X-RateLimit-Reset-After")).get(0)) * 1000L; + rateLimitGlobal.resetAfterMs_unused = Long.parseLong(Objects.requireNonNull(header.get("X-RateLimit-Reset-After")).get(0)) * 1000L; } if (header.containsKey("X-RateLimit-Limit")) { rateLimitGlobal.limit = Integer.parseInt(Objects.requireNonNull(header.get("X-RateLimit-Limit")).get(0)); diff --git a/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherHandler.java b/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherHandler.java index 249e582d..54045304 100644 --- a/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherHandler.java +++ b/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherHandler.java @@ -25,6 +25,7 @@ import link.locutus.discord.util.FileUtil; import link.locutus.discord.util.StringMan; import link.locutus.discord.util.io.PagePriority; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import java.io.IOException; @@ -233,7 +234,7 @@ private String getChannel() { return channel.getAsString(); } } - String msg = channelInfo.replace(pnwKey, "XXX"); + String msg = StringUtils.replaceIgnoreCase(channelInfo, pnwKey, "XXX"); msg = msg.replaceAll("(?i)[\\[\\]\"\\n^:\\s,\\.](?=.*[A-Za-z])(?=.*\\d)[0-9A-F]{14,}(?=[\\[\\]\"\\n$:\\s,\\.]|$)", "XXX"); throw new PnwPusherError(msg); } catch (IOException e) { diff --git a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java index 9e92a742..356cbdde 100644 --- a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java @@ -133,6 +133,7 @@ import net.dv8tion.jda.api.entities.channel.concrete.Category; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import org.apache.commons.lang3.StringUtils; import java.nio.ByteBuffer; import java.util.*; @@ -359,7 +360,7 @@ public boolean run(Guild guild, IMessageIO channel, final User msgUser, String c // return; } if (result != null && !result.isEmpty()) { - result = result.replaceAll("(?i)" + Locutus.loader().getApiKey(), "XXX"); + result = StringUtils.replaceIgnoreCase(result, Locutus.loader().getApiKey(), "XXX"); // result = result.replaceAll("(?i)(?<=^|[^A-Fa-f0-9])(?:[0-9a-f]{2}){7,}(?=[^A-Fa-f0-9]|$)", "XXX"); channel.send(result); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/binding/annotation/Arg.java b/src/main/java/link/locutus/discord/commands/manager/v2/binding/annotation/Arg.java index 4eb0b750..4d453610 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/binding/annotation/Arg.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/binding/annotation/Arg.java @@ -8,6 +8,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER, ElementType.METHOD}) public @interface Arg { + String[] requiresAny() default {}; + String[] requiresAll() default {}; + String[] requiresNone() default {}; + String value(); int group() default -1; String[] aliases() default {}; diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java index c47f79ec..b7c895d4 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java @@ -64,8 +64,6 @@ import java.util.function.Supplier; public class SlashCommandManager extends ListenerAdapter { - public static boolean PRINT_MISSING = false; - private static final Map> CHANNEL_TYPES = new ConcurrentHashMap<>(); private static final Map OPTION_TYPES = new ConcurrentHashMap<>(); @@ -578,7 +576,7 @@ private List createOptions(ParametricCallable cmd, List optInDiscRoles = new ArrayList<>(); + for (Roles r : optInRoles) { + Role discR = r.toRole(guild); + if (discR != null) { + optInDiscRoles.add(discR); + } + } + List notes = new ArrayList<>(); + if (optInDiscRoles.isEmpty() && optInRoles.length > 0) { + notes.add("No role `" + Arrays.stream(optInRoles).map(Roles::name).collect(Collectors.joining("`, `")) + "` is set. Have an admin use e.g. " + CM.role.setAlias.cmd.locutusRole(optInRoles[0].name()).discordRole("@someRole")); + } Role role = lcRole.toRole(guild); if (role == null) { // find role by name @@ -142,14 +150,27 @@ public static String handleOptOut(Member member, GuildDB db, Roles lcRole, Boole db.addRole(lcRole, role, 0); } } - if (member.getRoles().contains(role)) { + + List memberRoles = member.getRoles(); + boolean hasAnyOptIn = optInDiscRoles.stream().anyMatch(memberRoles::contains); + if (memberRoles.contains(role)) { if (forceOptOut == Boolean.TRUE) { return "You are already opted out of " + lcRole.name() + " alerts"; } RateLimitUtil.complete(guild.removeRoleFromMember(member, role)); - return "Opted back in to " + lcRole.name() + " alerts (@" + role.getName() + " removed from your user). Use the command again to opt out"; + String msg; + if (!optInDiscRoles.isEmpty() && !hasAnyOptIn) { + msg = "Your opt out role has been removed (@" + role.getName() + " removed) however you lack a role required to opt back in (@" + Arrays.stream(optInRoles).map(Roles::name).collect(Collectors.joining(", @")) + ")"; + } else { + msg = "Opted back in to " + lcRole.name() + " alerts (@" + role.getName() + " removed)"; + } + msg += ". Use the command again to opt out"; + return msg; } if (forceOptOut == Boolean.FALSE) { + if (!optInDiscRoles.isEmpty() && !hasAnyOptIn) { + return "You do not have the opt out role (@" + role.getName() + ") however lack a role to opt in (@" + Arrays.stream(optInRoles).map(Roles::name).collect(Collectors.joining(", @")) + ")"; + } return "You are already opted in to " + lcRole.name() + " alerts"; } RateLimitUtil.complete(guild.addRoleToMember(member, role)); @@ -164,12 +185,12 @@ public String auditAlertOptOut(@Me Member member, @Me DBNation me, @Me Guild gui @Command(desc = "Toggle your opt out of enemy alerts") public String enemyAlertOptOut(@Me GuildDB db, @Me User user, @Me Member member, @Me Guild guild) { - return PlayerSettingCommands.handleOptOut(member, db, Roles.WAR_ALERT_OPT_OUT, null); + return PlayerSettingCommands.handleOptOut(member, db, Roles.WAR_ALERT_OPT_OUT, null, Roles.ENEMY_ALERT_OFFLINE, Roles.BEIGE_ALERT); } @Command(desc = "Toggle your opt out of bounty alerts") public String bountyAlertOptOut(@Me GuildDB db, @Me User user, @Me Member member, @Me Guild guild) { - return PlayerSettingCommands.handleOptOut(member, db, Roles.BOUNTY_ALERT_OPT_OUT, null); + return PlayerSettingCommands.handleOptOut(member, db, Roles.BOUNTY_ALERT_OPT_OUT, null, Roles.BOUNTY_ALERT); } @Command(desc = "Set the required transfer market value required for automatic bank alerts\n" + diff --git a/src/main/java/link/locutus/discord/config/Settings.java b/src/main/java/link/locutus/discord/config/Settings.java index 5bbb8eb3..bc5ae633 100644 --- a/src/main/java/link/locutus/discord/config/Settings.java +++ b/src/main/java/link/locutus/discord/config/Settings.java @@ -343,37 +343,11 @@ public static class PROXY { } public static class LEGACY_SETTINGS { - @Final - @Ignore - @Comment("Open browser window when these ppl do attacks") - public List ATTACKER_DESKTOP_ALERTS = new ArrayList<>(); - @Final @Ignore @Comment("Timestamp for when marked deposits were introduced") public long MARKED_DEPOSITS_DATE = 1622661922L * 1000L; - @Final - @Ignore - public boolean OPEN_DESKTOP_FOR_CAPTCHA = false; - - @Final - @Ignore - public boolean OPEN_DESKTOP_FOR_MISTRADES = false; - - @Final - @Ignore - public boolean OPEN_DESKTOP_FOR_RAIDS = false; - - @Final - @Ignore - @Deprecated - @Comment("Access key for P&W (deprecated)") - public String ACCESS_KEY = ""; - @Final - @Ignore // disabled (not super accurate and not fair) - @Deprecated - public boolean DEANONYMIZE_SPYOPS = false; @Final @Ignore // disabled (not super accurate and not fair) @Deprecated @@ -390,6 +364,18 @@ public static class LEGACY_SETTINGS { @Deprecated @Comment("Reduce the appearance of these always online nations for espionage alerts (if causing false positives)") public List ESPIONAGE_ALWAYS_ONLINE_AA = Arrays.asList(); + + @Ignore + @Final + @Comment("Print the binding types which lack an autocomplete\n" + + "Disabled by default, as its normal for some types not to have completion") + public boolean PRINT_MISSING_AUTOCOMPLETE = false; + + @Ignore + @Final + @Comment("Print the espionage debug information\n" + + "Disabled by default, as it is verbose") + public boolean PRINT_ESPIONAGE_DEBUG = false; } diff --git a/src/main/java/link/locutus/discord/util/AlertUtil.java b/src/main/java/link/locutus/discord/util/AlertUtil.java index 44363845..4b9e4444 100644 --- a/src/main/java/link/locutus/discord/util/AlertUtil.java +++ b/src/main/java/link/locutus/discord/util/AlertUtil.java @@ -95,7 +95,6 @@ public static void auditAlert(DBNation nation, AutoAuditType type, Function> casualtyTracker = new ConcurrentHashMap<>(); @@ -120,12 +121,12 @@ public void accept(NationResponseProjection f) { private final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); public void updateCasualties(List nations) throws IOException { - System.out.println("Called update casualties " + nations.size()); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Called update casualties " + nations.size()); long timestamp = System.currentTimeMillis(); for (Nation nation : nations) { updateCasualties(nation, timestamp); } - System.out.println(" queue1 " + queue.size()); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text(" queue1 " + queue.size()); checkActive(); } @@ -168,19 +169,19 @@ public void addStat(int nationId, MilitaryUnit unit, int kills, int losses, int if (previousKills != null && kills > previousKills) { int change = kills - previousKills; queue.add(new SpyActivity(nationId, unit, currentUnits, change, timestamp, score, true)); - System.out.println("Add activity kill " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Add activity kill " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); } if (previousLosses != null && losses > previousLosses) { int change = losses - previousLosses; if (unit == MilitaryUnit.SPIES) { SpyActivity activity = new SpyActivity(nationId, unit, currentUnits + change, change, timestamp, score, false); - System.out.println("Add activity loss " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Add activity loss " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); queue.add(activity); checkActiveFlag.set(true); } else { - System.out.println("Ignore activity loss " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score + "| " + previousLosses + " | " + losses); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Ignore activity loss " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score + "| " + previousLosses + " | " + losses); } } @@ -197,7 +198,7 @@ public void addStat(int nationId, MilitaryUnit unit, int kills, int losses, int } SpyActivity activity = new SpyActivity(nationId, unit, currentUnits + change, change, timestamp, score, false); - System.out.println("Add activity sold " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Add activity sold " + nationId + " | " + unit + " | " + change + " | " + timestamp + " | " + score); queue.add(activity); } } @@ -240,7 +241,7 @@ public synchronized long removeMatchingAttacks() { } } else { if (Math.abs(attack.getDate() - activity.timestamp) < requiredProximityMs && !activity.isKill) { - System.out.println("Ignore loss " + attack.getWar_id() + " " + activity.unit + " " + activity.change + " | " + attack.getAttack_type() + " | " + Math.abs(attack.getDate() - activity.timestamp)); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Ignore loss " + attack.getWar_id() + " " + activity.unit + " " + activity.change + " | " + attack.getAttack_type() + " | " + Math.abs(attack.getDate() - activity.timestamp)); iter.remove(); break; } @@ -257,7 +258,7 @@ public synchronized void processQueue() throws IOException { checkActive(); long latestAttackMs = removeMatchingAttacks(); if (queue.isEmpty()) return; - System.out.println("Processing queue1: " + queue.size()); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Processing queue-1: " + queue.size()); long checkDefensiveMaxMs = latestAttackMs - TimeUnit.MINUTES.toMillis(5); long deleteOffensiveBelowMs = checkDefensiveMaxMs - TimeUnit.MINUTES.toMillis(20); @@ -283,7 +284,7 @@ public synchronized void processQueue() throws IOException { if (offensiveByUnit.isEmpty() && defensiveByUnit.isEmpty()) return; - System.out.println("Processing queue2 " + offensiveByUnit.size() + " | " + defensiveByUnit.size() + " | " + checkDefensiveMaxMs); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Processing queue2 " + offensiveByUnit.size() + " | " + defensiveByUnit.size() + " | " + checkDefensiveMaxMs); // sort defensives for (Map.Entry> entry : defensiveByUnit.entrySet()) { @@ -313,7 +314,7 @@ public synchronized void processQueue() throws IOException { DBAlliance defAA = defender.getAlliance(); Set treaties = defAA == null ? Collections.emptySet() : defAA.getTreaties().keySet(); - System.out.println("Finding match for " + defender.getNation_id() + " c" + defender.getCities() + " | " + defensive.change + "x" + defensive.unit + " | " + defensive.timestamp + " | " + defensive.score); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Finding match for " + defender.getNation_id() + " c" + defender.getCities() + " | " + defensive.change + "x" + defensive.unit + " | " + defensive.timestamp + " | " + defensive.score); SpyAlert alert = new SpyAlert(defender, unit, defensive.original, defensive.change, defensive.timestamp); @@ -369,7 +370,7 @@ public synchronized void processQueue() throws IOException { } } if (alert.exact.isEmpty() && alert.close.isEmpty() && alert.online.isEmpty()) { - System.out.println("Failed to find op for " + defender.getNation_id() + " c" + defender.getCities() + " | " + defensive.change + "x" + defensive.unit + " | " + defensive.timestamp + " | " + defensive.score); + if (Settings.INSTANCE.LEGACY_SETTINGS.PRINT_ESPIONAGE_DEBUG) Logg.text("Failed to find op for " + defender.getNation_id() + " c" + defender.getCities() + " | " + defensive.change + "x" + defensive.unit + " | " + defensive.timestamp + " | " + defensive.score); continue; }