package me.fromgate.reactions.util; import me.fromgate.reactions.util.message.M; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; public class UpdateChecker { private static JavaPlugin pluginInstance; private static boolean enableUpdateChecker; private static String projectId; private static String projectName; private static String projectApiUrl; private static String informPermission; // кого оповещать об обнволениях private static String projectBukkitDev; private static String projectCurrentVersion; private static String projectLastVersion; private static List<String> updateMessages; /** * UpdateChecker initialization * * @param plugin - plugin * @param pluginName - plugin name (for example: FaceChat) * @param projectID - CurseAPI project id * @param bukkitDevName - bukkit-dev name * @param enable - enable (true) update checker * <p> * Example: * UpdateChecker.init(this, "FaceChat", "12345", "facechat", true); */ public static void init(JavaPlugin plugin, String pluginName, String projectID, String bukkitDevName, boolean enable) { pluginInstance = plugin; projectId = projectID; projectApiUrl = "https://api.curseforge.com/servermods/files?projectIds=" + projectId; projectName = pluginName; projectCurrentVersion = pluginInstance.getDescription().getVersion(); enableUpdateChecker = enable && (!projectId.isEmpty()); projectBukkitDev = "http://dev.bukkit.org/bukkit-plugins/" + bukkitDevName + "/"; informPermission = bukkitDevName + ".config"; projectLastVersion = ""; setUpdateMessage(new ArrayList<String>()); if (enableUpdateChecker) { updateMsg(); Bukkit.getScheduler().runTaskTimerAsynchronously(pluginInstance, new Runnable() { @Override public void run() { updateMsg(); } }, (40 + (new Random()).nextInt(20)) * 1200, 60 * 1200); } } /** * Change permission for informing players (player with this permission will see update message) * Default permission (if this method was not used) is: <BukkitDevName>.config (for example: facechat.config) * * @param permission Example: * UpdateChecker.setPermission ("facechat.updateinform"); */ public static void setPermission(String permission) { informPermission = permission; } /** * Setup update message (could contains few lines) * Supported placeholders: * %plugin% %newversion% %oldversion% %url% * * @param list - String list containing message * if list is empty will filled with default messages * <p> * Example: * List<String> list = new ArrayList<String>(); * list.add("&6%plugin% &eis outdated! Recommended version is &6v%newversion%"); * list.add("&ePlease download new version from BukkitDev:"); * list.add("&b%url%"); * UpdateChecker.setUpdateMessage(list); */ public static void setUpdateMessage(List<String> list) { if (list == null || list.isEmpty()) { updateMessages = new ArrayList<>(); updateMessages.add(M.MSG_OUTDATED.getText("%plugin%", "%newversion%")); updateMessages.add(M.MSG_PLEASEDOWNLOAD.getText()); updateMessages.add("&b%url%"); } else updateMessages = list; } /** * Setup update message (could contains few lines) * Supported placeholders: * %plugin% %newversion% %oldversion% %url% * * @param str - String list containing message * <p> * Example: * UpdateChecker.setUpdateMessage ("&6%plugin% &eis outdated! Recommended version is &6v%newversion%", * "&ePlease download new version from BukkitDev:","&b%url%"); */ public static void setUpdateMessage(String... str) { List<String> list = new ArrayList<>(); list.addAll(Arrays.asList(str)); setUpdateMessage(list); } /** * Show update message for player. You must call this method inside PlayerJoinEvent handler * * @param player Example: * @EventHandler public void onJoin (PlayerJoinEvent event){ * UpdateChecker.updateMsg(event.getPlayer()); * } */ public static void updateMsg(Player player) { if (isUpdateRequired() && player.hasPermission(informPermission)) { for (String message : updateMessages) { player.sendMessage(ChatColor.translateAlternateColorCodes('&', replacePlaceholders(message))); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private static void updateMsg() { pluginInstance.getServer().getScheduler().runTaskAsynchronously(pluginInstance, new Runnable() { @Override public void run() { updateLastVersion(); if (isUpdateRequired()) { log(projectName + " v" + projectCurrentVersion + " is outdated! Recommended version is v" + projectLastVersion); log(projectBukkitDev); } } }); } private static void updateLastVersion() { if (!enableUpdateChecker) return; URL url; try { url = new URL(projectApiUrl); } catch (Exception e) { log("Failed to create URL: " + projectApiUrl); return; } try { URLConnection conn = url.openConnection(); conn.addRequestProperty("X-API-Key", null); conn.addRequestProperty("User-Agent", projectName + " using UpdateChecker (by fromgate)"); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String response = reader.readLine(); JSONArray array = (JSONArray) JSONValue.parse(response); if (array.size() > 0) { JSONObject latest = (JSONObject) array.get(array.size() - 1); String plugin_name = (String) latest.get("name"); projectLastVersion = plugin_name.replace(projectName + " v", "").trim(); } } catch (Exception e) { log("Failed to check last version"); } } private static boolean isUpdateRequired() { if (!enableUpdateChecker) return false; if (projectId.isEmpty()) return false; if (projectLastVersion.isEmpty()) return false; if (projectCurrentVersion.isEmpty()) return false; if (projectCurrentVersion.equalsIgnoreCase(projectLastVersion)) return false; double current_version = parseVersion(projectCurrentVersion);//Double.parseDouble(projectCurrentVersion.replaceFirst("\\.", "").replace("/", "")); double last_version = parseVersion(projectLastVersion); //Double.parseDouble(projectLastVersion.replaceFirst("\\.", "").replace("/", "")); return (last_version > current_version); } /* * ReActions v0.1.0/10 -> 000100.010 * ReActions v1.2.3/4 -> 010102.004 **/ private static double parseVersion(String versionStr) { String a = versionStr; String b = "000"; if (versionStr.contains("/")) { a = versionStr.substring(0, versionStr.indexOf("/")); b = versionStr.substring(versionStr.indexOf("/") + 1); } String[] ln = a.split("\\."); StringBuilder sb = new StringBuilder(); for (String s : ln) { sb.append(s.matches("\\d+") ? String.format("%02d", Integer.parseInt(s)) : "00"); } sb.append("."); sb.append(b.matches("\\d+") ? String.format("%03d", Integer.parseInt(b)) : "000"); return Double.parseDouble(sb.toString()); } private static void log(String message) { pluginInstance.getLogger().info(message); } private static String replacePlaceholders(String message) { return message.replace("%plugin%", projectName).replace("%newversion%", projectLastVersion).replace("%oldversion%", projectLastVersion).replace("%url%", projectBukkitDev); } }