diff --git a/.gitignore b/.gitignore
index 744289d..c63e02c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
-# Project exclude paths
-/target/
\ No newline at end of file
+/target/
+.idea/**
+out/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 57aa9a4..5ce75b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
net.aboodyy
localtime-expansion
- 1.2
+ 1.3
diff --git a/src/main/java/net/aboodyy/localtime/DateManager.java b/src/main/java/net/aboodyy/localtime/DateManager.java
index 807f359..693f61a 100644
--- a/src/main/java/net/aboodyy/localtime/DateManager.java
+++ b/src/main/java/net/aboodyy/localtime/DateManager.java
@@ -20,13 +20,11 @@
package net.aboodyy.localtime;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
-import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerQuitEvent;
-import org.bukkit.scheduler.BukkitRunnable;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@@ -34,14 +32,27 @@
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.concurrent.*;
+import java.util.logging.Level;
public class DateManager implements Listener {
private final Map timezones;
-
- DateManager() {
- timezones = new HashMap<>();
+ private final Cache cache;
+ private final ScheduledExecutorService executorService;
+ private int retryDelay;
+
+ public DateManager() {
+ this.timezones = new ConcurrentHashMap<>();
+ this.cache = CacheBuilder.newBuilder()
+ .expireAfterWrite(1, TimeUnit.DAYS)
+ .build();
+ this.retryDelay = 5; // default to 5 seconds
+ this.executorService = Executors.newSingleThreadScheduledExecutor();
}
public String getDate(String format, String timezone) {
@@ -53,55 +64,85 @@ public String getDate(String format, String timezone) {
return dateFormat.format(date);
}
- public String getTimeZone(Player player) {
+ public CompletableFuture getTimeZone(Player player) {
final String FAILED = "[LocalTime] Couldn't get " + player.getName() + "'s timezone. Will use default timezone.";
- String timezone = TimeZone.getDefault().getID();
- if (timezones.containsKey(player.getUniqueId()))
- return timezones.get(player.getUniqueId());
+ String cachedTimezone = cache.getIfPresent(player.getUniqueId().toString());
+ if (cachedTimezone != null) {
+ return CompletableFuture.completedFuture(cachedTimezone);
+ }
- InetSocketAddress address = player.getAddress();
- timezones.put(player.getUniqueId(), timezone);
+ String timezone = timezones.get(player.getUniqueId());
+ if (timezone != null) {
+ return CompletableFuture.completedFuture(timezone);
+ }
+ InetSocketAddress address = player.getAddress();
if (address == null) {
- Bukkit.getLogger().info(FAILED);
- return timezone;
+ PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, FAILED);
+ timezone = TimeZone.getDefault().getID();
+ cache.put(player.getUniqueId().toString(), timezone);
+ return CompletableFuture.completedFuture(timezone);
}
- new BukkitRunnable() {
- @Override
- public void run() {
- String timezone;
+ final String defaultTimezone = TimeZone.getDefault().getID();
+
+ CompletableFuture futureTimezone = CompletableFuture.supplyAsync(() -> {
+ String result = "undefined";
+ int retries = 3;
+ while (retries-- > 0) {
try {
URL api = new URL("https://ipapi.co/" + address.getAddress().getHostAddress() + "/timezone/");
URLConnection connection = api.openConnection();
-
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- timezone = bufferedReader.readLine();
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(5000);
+ connection.setRequestProperty("User-Agent", "Mozilla/5.0");
+
+ try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+ result = bufferedReader.readLine();
+
+ if (result == null) {
+ result = "undefined";
+ } else {
+ cache.put(player.getUniqueId().toString(), result);
+ }
+ break;
+ }
} catch (Exception e) {
- timezone = "undefined";
- }
-
- if (timezone.equalsIgnoreCase("undefined")) {
- Bukkit.getLogger().info(FAILED);
- timezone = TimeZone.getDefault().getID();
+ result = "undefined";
+ PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, "[LocalTime] Exception while getting timezone for player " + player.getName() + ": " + e.getMessage(), e);
+ try {
+ Thread.sleep(retryDelay * 1000);
+ } catch (InterruptedException ignored) {}
}
+ }
- timezones.put(player.getUniqueId(), timezone);
+ if (result.equalsIgnoreCase("undefined")) {
+ PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, FAILED);
+ result = defaultTimezone;
}
- }.runTaskAsynchronously(PlaceholderAPIPlugin.getInstance());
- return timezones.get(player.getUniqueId());
+ timezones.put(player.getUniqueId(), result);
+ return result;
+ }, executorService);
+
+ futureTimezone.exceptionally(ex -> {
+ PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, "[LocalTime] Exception while getting timezone for player " + player.getName() + ": " + ex.getMessage(), ex);
+ cache.put(player.getUniqueId().toString(), defaultTimezone);
+ timezones.put(player.getUniqueId(), defaultTimezone);
+ return defaultTimezone;
+ });
+
+ return futureTimezone;
}
public void clear() {
timezones.clear();
+ cache.invalidateAll();
}
- @SuppressWarnings("unused")
- @EventHandler
- public void onLeave(PlayerQuitEvent e) {
- timezones.remove(e.getPlayer().getUniqueId());
+ public void shutdown() {
+ this.executorService.shutdown();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/aboodyy/localtime/LocalTimeExpansion.java b/src/main/java/net/aboodyy/localtime/LocalTimeExpansion.java
index 8e39d46..ad62388 100644
--- a/src/main/java/net/aboodyy/localtime/LocalTimeExpansion.java
+++ b/src/main/java/net/aboodyy/localtime/LocalTimeExpansion.java
@@ -30,6 +30,7 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unused")
public class LocalTimeExpansion extends PlaceholderExpansion implements Cacheable, Configurable {
@@ -43,12 +44,12 @@ public String getIdentifier() {
@Override
public String getAuthor() {
- return "aBooDyy";
+ return "aBooDyy, Opal";
}
@Override
public String getVersion() {
- return "1.2";
+ return "1.3";
}
@Override
@@ -69,6 +70,7 @@ public Map getDefaults() {
public void clear() {
dateManager.clear();
HandlerList.unregisterAll(dateManager);
+ dateManager.shutdown();
}
@Override
@@ -82,7 +84,10 @@ public String onPlaceholderRequest(Player p, String identifier) {
args = identifier.split("time_");
if (args.length < 2) return null;
- return dateManager.getDate(args[1], dateManager.getTimeZone(p));
+ CompletableFuture timezoneFuture = dateManager.getTimeZone(p);
+ String timezone = timezoneFuture.join();
+
+ return dateManager.getDate(args[1], timezone);
}
if (identifier.startsWith("timezone_")) {
@@ -99,8 +104,12 @@ public String onPlaceholderRequest(Player p, String identifier) {
return dateManager.getDate(format, args[1]);
}
- if (identifier.equalsIgnoreCase("time"))
- return dateManager.getDate(format, dateManager.getTimeZone(p));
+ if (identifier.equalsIgnoreCase("time")) {
+ CompletableFuture timezoneFuture = dateManager.getTimeZone(p);
+ String timezone = timezoneFuture.join();
+
+ return dateManager.getDate(format, timezone);
+ }
return null;
}