diff --git a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java index 9a13260..bf9a588 100644 --- a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java +++ b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java @@ -1,12 +1,15 @@ package com.extendedclip.papi.expansion.pinger; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import me.clip.placeholderapi.expansion.Cacheable; import me.clip.placeholderapi.expansion.Configurable; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.Taskable; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.net.InetSocketAddress; @@ -14,134 +17,120 @@ import java.net.SocketException; import java.nio.charset.Charset; import java.util.HashMap; +import java.util.Locale; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.*; +@SuppressWarnings("unused") public class PingerExpansion extends PlaceholderExpansion implements Cacheable, Taskable, Configurable { - private BukkitTask pingTask = null; private String online = "&aOnline"; private String offline = "&cOffline"; - private final Map servers = new ConcurrentHashMap<>(); - - private final Map toPing = new ConcurrentHashMap<>(); + @Nullable + private LoadingCache> cache; private int interval = 60; public Map getDefaults() { Map defaults = new HashMap<>(); - defaults.put("check_interval", Integer.valueOf(30)); + defaults.put("check_interval", 30); defaults.put("online", "&aOnline"); defaults.put("offline", "&cOffline"); return defaults; } public void start() { - String on = getString("online", "&aOnline"); - this.online = (on != null) ? on : "&aOnline"; - String off = getString("offline", "&cOffline"); - this.offline = (off != null) ? off : "&cOffline"; + this.online = getString("online", this.online); + this.offline = getString("offline", this.offline); + int time = getInt("check_interval", 60); - if (time > 0) - this.interval = time; - this.pingTask = (new BukkitRunnable() { - public void run() { - if (PingerExpansion.this.toPing.isEmpty()) - return; - for (Map.Entry address : PingerExpansion.this.toPing.entrySet()) { - PingerExpansion.Pinger r; - try { - r = new PingerExpansion.Pinger(address.getValue().getHostName(), address.getValue().getPort()); - if (r.fetchData()) { - PingerExpansion.this.servers.put(address.getKey(), r); - continue; - } - if (PingerExpansion.this.servers.containsKey(address.getKey())) - PingerExpansion.this.servers.remove(address.getKey()); - } catch (Exception exception) { - } - } - } - }).runTaskTimerAsynchronously(getPlaceholderAPI(), 20L, 20L * this.interval); + if (time > 0) this.interval = time; + + this.cache = CacheBuilder.newBuilder() + .concurrencyLevel(1) + .refreshAfterWrite(this.interval, TimeUnit.SECONDS) + .build(new PingerCacheLoader()); } public void stop() { - try { - this.pingTask.cancel(); - } catch (Exception exception) { - } - this.pingTask = null; + if (this.cache == null) return; + this.cache.asMap().values().forEach(future -> future.cancel(true)); + this.cache = null; } public void clear() { - this.servers.clear(); - this.toPing.clear(); + if (this.cache == null) return; + this.cache.cleanUp(); } public boolean canRegister() { return true; } - public String getAuthor() { + public @NotNull String getAuthor() { return "clip"; } - public String getIdentifier() { + public @NotNull String getIdentifier() { return "pinger"; } - public String getPlugin() { - return null; - } - - public String getVersion() { - return "1.0.1"; + public @NotNull String getVersion() { + return "1.0.2"; } public String onPlaceholderRequest(Player p, String identifier) { - int place = identifier.indexOf("_"); + final int place = identifier.indexOf("_"); if (place == -1) return null; - String type = identifier.substring(0, place); - String address = identifier.substring(place + 1); - Pinger r = null; - for (String a : this.servers.keySet()) { - if (a.equalsIgnoreCase(address)) { - r = this.servers.get(a); - break; + + final String type = identifier.substring(0, place).toLowerCase(Locale.ROOT); + final String address = identifier.substring(place + 1); + + if (this.cache == null) return null; + try { + final Future future = this.cache.get(address); + final Pinger pinger = future.isDone() ? future.get() : null; + + switch (type) { + case "motd": + if (pinger == null) return ""; + return pinger.getMotd(); + + case "count": + case "players": + if (pinger == null) return "0"; + return String.valueOf(pinger.getPlayersOnline()); + + case "max": + case "maxplayers": + if (pinger == null) return "0"; + return String.valueOf(pinger.getMaxPlayers()); + + case "pingversion": + case "pingv": + if (pinger == null) return "-1"; + return String.valueOf(pinger.getPingVersion()); + + case "gameversion": + case "version": + if (pinger == null) return ""; + return pinger.getGameVersion(); + + case "online": + case "isonline": + if (pinger == null) return this.offline; + return this.online; } + } catch (InterruptedException | ExecutionException ignored) { } - if (r == null) - if (!this.toPing.containsKey(address)) { - int port = 25565; - String add = address; - if (address.contains(":")) { - add = address.substring(0, address.indexOf(":")); - try { - port = Integer.parseInt(address.substring(address.indexOf(":") + 1)); - } catch (Exception exception) { - } - } - this.toPing.put(address, new InetSocketAddress(add, port)); - } - if (type.equalsIgnoreCase("motd")) - return (r != null) ? r.getMotd() : ""; - if (type.equalsIgnoreCase("count") || type.equalsIgnoreCase("players")) - return (r != null) ? String.valueOf(r.getPlayersOnline()) : "0"; - if (type.equalsIgnoreCase("max") || type.equalsIgnoreCase("maxplayers")) - return (r != null) ? String.valueOf(r.getMaxPlayers()) : "0"; - if (type.equalsIgnoreCase("pingversion") || type.equalsIgnoreCase("pingv")) - return (r != null) ? String.valueOf(r.getPingVersion()) : "-1"; - if (type.equalsIgnoreCase("gameversion") || type.equalsIgnoreCase("version")) - return (r != null && r.getGameVersion() != null) ? r.getGameVersion() : ""; - if (type.equalsIgnoreCase("online") || type.equalsIgnoreCase("isonline")) - return (r != null) ? this.online : this.offline; + return null; } - public final class Pinger { + private static class Pinger { private String address = "localhost"; private int port = 25565; @@ -321,4 +310,28 @@ public boolean fetchData() { return true; } } + + private static class PingerCacheLoader extends CacheLoader> { + @Override + public Future load(final String key) { + final InetSocketAddress address = this.address(key); + final Pinger pinger = new Pinger(address.getHostName(), address.getPort()); + + return CompletableFuture.supplyAsync(() -> { + if (!pinger.fetchData()) return null; + + return pinger; + }); + } + + private InetSocketAddress address(final String key) { + final int index = key.indexOf(":"); + if (index == -1) return new InetSocketAddress(key, 25565); + + final String host = key.substring(0, index); + final int port = Integer.parseInt(key.substring(index + 1)); + + return new InetSocketAddress(host, port); + } + } }