From 7050ec798fd4bede469a7470405ef085666af250 Mon Sep 17 00:00:00 2001 From: keough99 Date: Fri, 10 May 2019 20:05:50 -0400 Subject: [PATCH] metrics update added metrics --- .../maximuspayne/navycraft/MetricsLite.java | 344 ++++++++++++++++++ .../com/maximuspayne/navycraft/NavyCraft.java | 2 + .../com/maximuspayne/navycraft/update.java | 5 + .../maximuspayne/navycraft/NavyCraft.class | Bin 21362 -> 21642 bytes 4 files changed, 351 insertions(+) create mode 100644 src/main/java/com/maximuspayne/navycraft/MetricsLite.java create mode 100644 src/main/java/com/maximuspayne/navycraft/update.java diff --git a/src/main/java/com/maximuspayne/navycraft/MetricsLite.java b/src/main/java/com/maximuspayne/navycraft/MetricsLite.java new file mode 100644 index 0000000..0e14ac1 --- /dev/null +++ b/src/main/java/com/maximuspayne/navycraft/MetricsLite.java @@ -0,0 +1,344 @@ +package com.maximuspayne.navycraft; + + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + *

+ * Check out https://bStats.org/ to learn more about bStats! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class MetricsLite { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (MetricsLite.class.getPackage().getName().equals(defaultPackage) || MetricsLite.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public MetricsLite(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + enabled = config.getBoolean("enabled", true); + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JSONObject getPluginData() { + JSONObject data = new JSONObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.put("pluginName", pluginName); // Append the name of the plugin + data.put("pluginVersion", pluginVersion); // Append the version of the plugin + JSONArray customCharts = new JSONArray(); + data.put("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JSONObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JSONObject data = new JSONObject(); + + data.put("serverUUID", serverUUID); + + data.put("playerAmount", playerAmount); + data.put("onlineMode", onlineMode); + data.put("bukkitVersion", bukkitVersion); + + data.put("javaVersion", javaVersion); + data.put("osName", osName); + data.put("osArch", osArch); + data.put("osVersion", osVersion); + data.put("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JSONObject data = getServerData(); + + JSONArray pluginData = new JSONArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + } + } + } catch (NoSuchFieldException ignored) { } + } + + data.put("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JSONObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data.toString()); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + +} + diff --git a/src/main/java/com/maximuspayne/navycraft/NavyCraft.java b/src/main/java/com/maximuspayne/navycraft/NavyCraft.java index 20b4b09..ceb50d2 100644 --- a/src/main/java/com/maximuspayne/navycraft/NavyCraft.java +++ b/src/main/java/com/maximuspayne/navycraft/NavyCraft.java @@ -143,6 +143,8 @@ public void loadConfigManager() { public void onEnable() { instance = this; shutDown = false; + MetricsLite metrics = new MetricsLite(this); + this.saveDefaultConfig(); diff --git a/src/main/java/com/maximuspayne/navycraft/update.java b/src/main/java/com/maximuspayne/navycraft/update.java new file mode 100644 index 0000000..8fcf90c --- /dev/null +++ b/src/main/java/com/maximuspayne/navycraft/update.java @@ -0,0 +1,5 @@ +package com.maximuspayne.navycraft; + +public class update { + +} diff --git a/target/classes/com/maximuspayne/navycraft/NavyCraft.class b/target/classes/com/maximuspayne/navycraft/NavyCraft.class index ca79bbe48ea6ca81152f2fd45e7f7922df262c4c..9800c6d3d7c1b1285459b1e02fde19006b369083 100644 GIT binary patch literal 21642 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 literal 21362 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 bZ4#qsGp@j%2OUzpfEYYMW(97U_0RtSDR_vC