1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

Merge pull request #2107 from WalshyDev/feature/metrics-module

Metrics!
This commit is contained in:
TheBusyBiscuit 2020-07-24 16:06:53 +02:00 committed by GitHub
commit d69ef1effb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 351 additions and 396 deletions

View File

@ -24,6 +24,7 @@
#### Additions #### Additions
* Added "Bone Block -> Bone meal" recipe to the Grind Stone * Added "Bone Block -> Bone meal" recipe to the Grind Stone
* Added a [Metrics module](https://github.com/Slimefun/MetricsModule) which allows us to deploy changes to metrics (bStats) without another Slimefun build.
#### Changes #### Changes
* Refactored and reworked the Generator API * Refactored and reworked the Generator API

11
pom.xml
View File

@ -327,6 +327,17 @@
<version>1.7</version> <version>1.7</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.8.06</version>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>io.papermc</groupId> <groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId> <artifactId>paperlib</artifactId>

View File

@ -2,17 +2,16 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Collection; import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils; import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.Plugin;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
class VersionsCommand extends SubCommand { class VersionsCommand extends SubCommand {
@ -42,8 +41,11 @@ class VersionsCommand extends SubCommand {
sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + SlimefunPlugin.getCSCoreLibVersion())); sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + SlimefunPlugin.getCSCoreLibVersion()));
sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion())); sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion()));
if (SlimefunPlugin.getMetricsService().getVersion() != null)
sender.sendMessage(ChatColors.color("&aMetrics: &2#" + SlimefunPlugin.getMetricsService().getVersion() + ')'));
if (SlimefunPlugin.getRegistry().isBackwardsCompatible()) { if (SlimefunPlugin.getRegistry().isBackwardsCompatible()) {
sender.sendMessage(ChatColor.YELLOW + "Backwards compatiblity enabled!"); sender.sendMessage(ChatColor.YELLOW + "Backwards compatibility enabled!");
} }
sender.sendMessage(""); sender.sendMessage("");

View File

@ -0,0 +1,239 @@
package io.github.thebusybiscuit.slimefun4.core.services;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.UnirestException;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import org.bukkit.plugin.Plugin;
/**
* This Class represents a Metrics Service that sends data to https://bstats.org/
* This data is used to analyse the usage of this {@link Plugin}.
* <p>
* You can find more info in the README file of this Project on GitHub. <br>
* <b>Note:</b> To start the metrics you will need to be calling {@link #start()}
*
* @author TheBusyBiscuit
* @author WalshyDev
*/
public class MetricsService {
private static final String REPO_NAME = "MetricsModule";
private static final String GH_API = "https://api.github.com/repos/Slimefun/" + REPO_NAME;
private static final String GH_REPO_RELEASES = "https://github.com/Slimefun/" + REPO_NAME
+ "/releases/download";
private final SlimefunPlugin plugin;
private final File parentFolder;
private final File metricFile;
private URLClassLoader moduleClassLoader;
private String metricVersion = null;
private boolean newlyDownloaded = false;
static {
Unirest.config()
.concurrency(2, 1)
.setDefaultHeader("User-Agent", "MetricsModule Auto-Updater")
.setDefaultHeader("Accept", "application/vnd.github.v3+json")
.enableCookieManagement(false)
.cookieSpec("ignoreCookies");
}
public MetricsService(SlimefunPlugin plugin) {
this.plugin = plugin;
this.parentFolder = new File(plugin.getDataFolder(), "cache" + File.separatorChar + "modules");
if (!parentFolder.exists())
parentFolder.mkdirs();
this.metricFile = new File(parentFolder, REPO_NAME + ".jar");
}
/**
* This method loads the metric module and starts the metrics collection.
*/
public void start() {
if (!metricFile.exists()) {
plugin.getLogger().info(REPO_NAME + " does not exist, downloading...");
if (!download(getLatestVersion())) {
plugin.getLogger().warning("Failed to start metrics as the file could not be downloaded.");
return;
}
}
try {
// Load the jar file into a child class loader using the SF PluginClassLoader
// as a parent.
moduleClassLoader = URLClassLoader.newInstance(new URL[] { metricFile.toURI().toURL() },
plugin.getClass().getClassLoader());
Class<?> cl = moduleClassLoader.loadClass("dev.walshy.sfmetrics.MetricsModule");
metricVersion = cl.getPackage().getImplementationVersion();
// If it has not been newly downloaded, auto-updates are on AND there's a new version
// then cleanup, download and start
if (!newlyDownloaded
&& hasAutoUpdates()
&& checkForUpdate(metricVersion)
) {
plugin.getLogger().info("Cleaning up and re-loading Metrics.");
cleanUp();
start();
return;
}
// Finally, we're good to start this.
Method start = cl.getDeclaredMethod("start");
String version = cl.getPackage().getImplementationVersion();
// This is required to be sync due to bStats.
Slimefun.runSync(() -> {
try {
start.invoke(null);
plugin.getLogger().info("Metrics build #" + version + " started.");
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING, "Failed to start metrics.", e);
}
});
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING,
"Failed to load the metrics module. Maybe the jar is corrupt?", e);
}
}
/**
* This will close the child classloader and mark all the resources held under this no longer
* in use, they will be cleaned up the next GC run.
*/
public void cleanUp() {
try {
if (this.moduleClassLoader != null)
this.moduleClassLoader.close();
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING,
"Could not clean up module class loader. Some memory may have been leaked.");
}
}
/**
* Checks for a new update and compares it against the current version.
* If there is a new version available then this returns true.
*
* @param currentVersion The current version which is being used.
* @return True if there is an update available.
*/
public boolean checkForUpdate(String currentVersion) {
if (currentVersion == null || !PatternUtils.NUMERIC.matcher(currentVersion).matches()) {
return false;
}
int latest = getLatestVersion();
if (latest > Integer.parseInt(currentVersion)) {
return download(latest);
}
return false;
}
/**
* Gets the latest version available as an int.
* This is an internal method used by {@link #checkForUpdate(String)}.
* If it cannot get the version for whatever reason this will return 0, effectively always
* being behind.
*
* @return The latest version as an integer or -1 if it failed to fetch.
*/
private int getLatestVersion() {
try {
HttpResponse<JsonNode> response = Unirest.get(GH_API + "/releases/latest")
.asJson();
if (!response.isSuccess()) return -1;
JsonNode node = response.getBody();
if (node == null) return -1;
return node.getObject().getInt("tag_name");
} catch (UnirestException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to fetch latest builds for SFMetrics");
return -1;
}
}
/**
* Downloads the version specified to Slimefun's data folder.
*
* @param version The version to download.
*/
private boolean download(int version) {
File f = new File(parentFolder, "Metrics-" + version + ".jar");
try {
plugin.getLogger().info("# Starting download of MetricsModule build: #" + version);
AtomicInteger lastPercentPosted = new AtomicInteger();
HttpResponse<File> response = Unirest.get(GH_REPO_RELEASES + "/" + version
+ "/" + REPO_NAME + ".jar")
.downloadMonitor((b, fileName, bytesWritten, totalBytes) -> {
int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20)));
if (percent != 0 && percent != lastPercentPosted.get()) {
plugin.getLogger().info("# Downloading... " + percent + "% " +
"(" + bytesWritten + "/" + totalBytes + " bytes)");
lastPercentPosted.set(percent);
}
})
.asFile(f.getPath());
if (response.isSuccess()) {
plugin.getLogger().info("Successfully downloaded " + REPO_NAME + " build: " + version);
// Replace the metric file with the new one
Files.move(f.toPath(), metricFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
metricVersion = String.valueOf(version);
newlyDownloaded = true;
return true;
}
} catch (UnirestException e) {
plugin.getLogger().log(Level.WARNING, "Failed to fetch the latest jar file from the" +
" builds page. Perhaps GitHub is down.");
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING, "Failed to replace the old metric file with the " +
"new one. Please do this manually! Error: {0}", e.getMessage());
}
return false;
}
/**
* Returns the currently downloaded metric version. This CAN change! It may be null or an
* older version before it has downloaded a newer one.
*
* @return The current version or null if not loaded.
*/
@Nullable
public String getVersion() {
return metricVersion;
}
/**
* Returns if the current server has metric auto-updates enabled.
*
* @return True if the current server has metric auto-updates enabled.
*/
public boolean hasAutoUpdates() {
return SlimefunPlugin.instance().getConfig().getBoolean("metrics.auto-update");
}
}

View File

@ -10,6 +10,9 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;
import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.Slimefun;
class ContributionsConnector extends GitHubConnector { class ContributionsConnector extends GitHubConnector {
@ -57,10 +60,10 @@ class ContributionsConnector extends GitHubConnector {
} }
@Override @Override
public void onSuccess(JsonElement element) { public void onSuccess(JsonNode element) {
finished = true; finished = true;
if (element.isJsonArray()) { if (element.isArray()) {
computeContributors(element.getAsJsonArray()); computeContributors(element.getArray());
} }
else { else {
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", element); Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", element);
@ -82,13 +85,13 @@ class ContributionsConnector extends GitHubConnector {
return "/contributors?per_page=100&page=" + page; return "/contributors?per_page=100&page=" + page;
} }
private void computeContributors(JsonArray array) { private void computeContributors(JSONArray array) {
for (int i = 0; i < array.size(); i++) { for (int i = 0; i < array.length(); i++) {
JsonObject object = array.get(i).getAsJsonObject(); JSONObject object = array.getJSONObject(i);
String name = object.get("login").getAsString(); String name = object.getString("login");
int commits = object.get("contributions").getAsInt(); int commits = object.getInt("contributions");
String profile = object.get("html_url").getAsString(); String profile = object.getString("html_url");
if (!blacklist.contains(name)) { if (!blacklist.contains(name)) {
github.addContributor(aliases.getOrDefault(name, name), profile, role, commits); github.addContributor(aliases.getOrDefault(name, name), profile, role, commits);

View File

@ -4,19 +4,18 @@ import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.logging.Level; import java.util.logging.Level;
import com.google.gson.JsonElement; import kong.unirest.HttpResponse;
import com.google.gson.JsonParser; import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import kong.unirest.UnirestException;
import kong.unirest.json.JSONException;
import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.Slimefun;
abstract class GitHubConnector { abstract class GitHubConnector {
@ -34,7 +33,7 @@ abstract class GitHubConnector {
public abstract String getURLSuffix(); public abstract String getURLSuffix();
public abstract void onSuccess(JsonElement element); public abstract void onSuccess(JsonNode element);
public void onFailure() { public void onFailure() {
// Don't do anything by default // Don't do anything by default
@ -48,58 +47,51 @@ abstract class GitHubConnector {
} }
try { try {
URL website = new URL("https://api.github.com/repos/" + repository + getURLSuffix()); HttpResponse<JsonNode> resp = Unirest
.get("https://api.github.com/repos/" + repository + getURLSuffix())
.header("User-Agent", "Slimefun4 (https://github.com/Slimefun)")
.asJson();
URLConnection connection = website.openConnection(); if (resp.isSuccess()) {
connection.setConnectTimeout(8000); onSuccess(resp.getBody());
connection.addRequestProperty("Accept-Charset", "UTF-8"); writeCacheFile(resp.getBody());
connection.addRequestProperty("User-Agent", "Slimefun 4 GitHub Agent (by TheBusyBiscuit)"); } else
connection.setDoOutput(true); Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}",
repository + getURLSuffix());
try (ReadableByteChannel channel = Channels.newChannel(connection.getInputStream())) { } catch (UnirestException e) {
try (FileOutputStream stream = new FileOutputStream(file)) {
stream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);
parseData();
}
}
}
catch (IOException e) {
if (github.isLoggingEnabled()) { if (github.isLoggingEnabled()) {
Slimefun.getLogger().log(Level.WARNING, "Could not connect to GitHub in time."); Slimefun.getLogger().log(Level.WARNING, "Could not connect to GitHub in time.");
} }
if (hasData()) { // It has the cached file, let's just read that then
parseData(); if (file.exists()) {
} JsonNode cache = readCacheFile();
else { if (cache != null) {
onFailure(); onSuccess(cache);
} return;
} }
}
public boolean hasData() {
return getFile().exists();
}
public File getFile() {
return file;
}
public void parseData() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getFile()), StandardCharsets.UTF_8))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
} }
JsonElement element = new JsonParser().parse(builder.toString()); // If the request failed and it failed to read the cache then call onFailure.
onSuccess(element);
}
catch (IOException x) {
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing GitHub-Data for Slimefun " + SlimefunPlugin.getVersion());
onFailure(); onFailure();
} }
} }
private JsonNode readCacheFile() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
return new JsonNode(br.readLine());
} catch (IOException | JSONException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to read Github cache file: {0}",
file.getName());
return null;
}
}
private void writeCacheFile(JsonNode node) {
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(node.toString().getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to populate GitHub cache");
}
}
} }

View File

@ -6,6 +6,10 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONElement;
import kong.unirest.json.JSONObject;
import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.Slimefun;
class GitHubIssuesTracker extends GitHubConnector { class GitHubIssuesTracker extends GitHubConnector {
@ -25,15 +29,15 @@ class GitHubIssuesTracker extends GitHubConnector {
} }
@Override @Override
public void onSuccess(JsonElement element) { public void onSuccess(JsonNode element) {
if (element.isJsonArray()) { if (element.isArray()) {
JsonArray array = element.getAsJsonArray(); JSONArray array = element.getArray();
int issues = 0; int issues = 0;
int pullRequests = 0; int pullRequests = 0;
for (JsonElement elem : array) { for (int i = 0; i < array.length(); i++) {
JsonObject obj = elem.getAsJsonObject(); JSONObject obj = array.getJSONObject(i);
if (obj.has("pull_request")) { if (obj.has("pull_request")) {
pullRequests++; pullRequests++;

View File

@ -17,6 +17,8 @@ import io.github.thebusybiscuit.slimefun4.core.services.localization.Translators
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONObject;
/** /**
* This Service is responsible for grabbing every {@link Contributor} to this project * This Service is responsible for grabbing every {@link Contributor} to this project
@ -108,11 +110,11 @@ public class GitHubService {
connectors.add(new GitHubConnector(this, repository) { connectors.add(new GitHubConnector(this, repository) {
@Override @Override
public void onSuccess(JsonElement element) { public void onSuccess(JsonNode element) {
JsonObject object = element.getAsJsonObject(); JSONObject object = element.getObject();
forks = object.get("forks").getAsInt(); forks = object.getInt("forks");
stars = object.get("stargazers_count").getAsInt(); stars = object.getInt("stargazers_count");
lastUpdate = NumberUtils.parseGitHubDate(object.get("pushed_at").getAsString()); lastUpdate = NumberUtils.parseGitHubDate(object.getString("pushed_at"));
} }
@Override @Override

View File

@ -1,27 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class AddonsChart extends AdvancedPie {
AddonsChart() {
super("installed_addons", () -> {
Map<String, Integer> addons = new HashMap<>();
for (Plugin plugin : SlimefunPlugin.getInstalledAddons()) {
if (plugin.isEnabled()) {
addons.put(plugin.getName(), 1);
}
}
return addons;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class AutoUpdaterChart extends SimplePie {
AutoUpdaterChart() {
super("auto_updates", () -> {
boolean enabled = SlimefunPlugin.getUpdater().isEnabled();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,25 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class CommandChart extends AdvancedPie {
CommandChart() {
super("commands_ran", () -> {
Map<String, Integer> commands = new HashMap<>();
for (Map.Entry<SubCommand, Integer> entry : SlimefunPlugin.getCommand().getCommandUsage().entrySet()) {
commands.put("/sf " + entry.getKey().getName(), entry.getValue());
}
return commands;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class CompatibilityModeChart extends SimplePie {
CompatibilityModeChart() {
super("compatibility_mode", () -> {
boolean enabled = SlimefunPlugin.getRegistry().isBackwardsCompatible();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,17 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class GuideLayoutChart extends SimplePie {
GuideLayoutChart() {
super("guide_layout", () -> {
boolean book = SlimefunPlugin.getCfg().getBoolean("guide.default-view-book");
return book ? "Book" : "Chest GUI";
});
}
}

View File

@ -1,55 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
/**
* This Class represents a Metrics Service that sends data to https://bstats.org/
* This data is used to analyse the usage of this {@link Plugin}.
*
* You can find more info in the README file of this Project on GitHub.
*
* @author TheBusyBiscuit
*
*/
public class MetricsService {
private final SlimefunPlugin plugin;
/**
* This creates a new {@link MetricsService}. The constructor does not set up
* anything related to bStats yet, that happens in the {@link MetricsService#start()} method.
*
* @param plugin
* The instance of our {@link SlimefunPlugin}
*/
public MetricsService(SlimefunPlugin plugin) {
this.plugin = plugin;
}
/**
* This method intializes and starts the metrics collection.
*/
public void start() {
Metrics metrics = new Metrics(plugin, 4574);
if (SlimefunPlugin.getUpdater().getBranch().isOfficial()) {
// We really do not need this data if it is an unofficially modified build...
metrics.addCustomChart(new AutoUpdaterChart());
}
metrics.addCustomChart(new ResourcePackChart());
metrics.addCustomChart(new SlimefunVersionChart());
metrics.addCustomChart(new ServerLanguageChart());
metrics.addCustomChart(new PlayerLanguageChart());
metrics.addCustomChart(new ResearchesEnabledChart());
metrics.addCustomChart(new GuideLayoutChart());
metrics.addCustomChart(new AddonsChart());
metrics.addCustomChart(new CommandChart());
metrics.addCustomChart(new ServerSizeChart());
metrics.addCustomChart(new CompatibilityModeChart());
}
}

View File

@ -1,31 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class PlayerLanguageChart extends AdvancedPie {
PlayerLanguageChart() {
super("player_languages", () -> {
Map<String, Integer> languages = new HashMap<>();
for (Player p : Bukkit.getOnlinePlayers()) {
Language language = SlimefunPlugin.getLocalization().getLanguage(p);
boolean supported = SlimefunPlugin.getLocalization().isLanguageLoaded(language.getId());
String lang = supported ? language.getId() : "Unsupported Language";
languages.merge(lang, 1, Integer::sum);
}
return languages;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ResearchesEnabledChart extends SimplePie {
ResearchesEnabledChart() {
super("servers_with_researches_enabled", () -> {
boolean enabled = SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,25 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ResourcePackChart extends SimplePie {
ResourcePackChart() {
super("resourcepack", () -> {
String version = SlimefunPlugin.getItemTextureService().getVersion();
if (version != null && version.startsWith("v")) {
return version + " (Official)";
}
else if (SlimefunPlugin.getItemTextureService().isActive()) {
return "Custom / Modified";
}
else {
return "None";
}
});
}
}

View File

@ -1,18 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ServerLanguageChart extends SimplePie {
ServerLanguageChart() {
super("language", () -> {
Language language = SlimefunPlugin.getLocalization().getDefaultLanguage();
boolean supported = SlimefunPlugin.getLocalization().isLanguageLoaded(language.getId());
return supported ? language.getId() : "Unsupported Language";
});
}
}

View File

@ -1,40 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import org.bukkit.Bukkit;
class ServerSizeChart extends SimplePie {
ServerSizeChart() {
super("server_size", () -> {
int players = Bukkit.getOnlinePlayers().size();
if (players < 10) {
return "0-10";
}
if (players < 25) {
return "10-25";
}
if (players < 50) {
return "25-50";
}
if (players < 100) {
return "50-100";
}
if (players < 200) {
return "100-200";
}
if (players < 300) {
return "200-300";
}
return "300+";
});
}
}

View File

@ -1,24 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.DrilldownPie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class SlimefunVersionChart extends DrilldownPie {
SlimefunVersionChart() {
super("slimefun_version", () -> {
Map<String, Map<String, Integer>> outerMap = new HashMap<>();
Map<String, Integer> innerMap = new HashMap<>();
innerMap.put(SlimefunPlugin.getVersion(), 1);
outerMap.put(SlimefunPlugin.getUpdater().getBranch().getName(), innerMap);
return outerMap;
});
}
}

View File

@ -1,4 +0,0 @@
/**
* This package contains everything related to bStats Metrics
*/
package io.github.thebusybiscuit.slimefun4.core.services.metrics;

View File

@ -41,7 +41,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.PerWorldSettingsService;
import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService; import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService;
import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService; import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService;
import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService; import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService;
import io.github.thebusybiscuit.slimefun4.core.services.metrics.MetricsService; import io.github.thebusybiscuit.slimefun4.core.services.MetricsService;
import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPluginService; import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPluginService;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler; import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
@ -196,7 +196,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
networkManager = new NetworkManager(networkSize); networkManager = new NetworkManager(networkSize);
// Setting up bStats // Setting up bStats
metricsService.start(); new Thread(metricsService::start).start();
// Starting the Auto-Updater // Starting the Auto-Updater
if (config.getBoolean("options.auto-update")) { if (config.getBoolean("options.auto-update")) {
@ -367,6 +367,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Create a new backup zip // Create a new backup zip
backupService.run(); backupService.run();
metricsService.cleanUp();
// Prevent Memory Leaks // Prevent Memory Leaks
// These static Maps should be removed at some point... // These static Maps should be removed at some point...
AContainer.processing = null; AContainer.processing = null;
@ -564,6 +566,16 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.updaterService; return instance.updaterService;
} }
/**
* This method returns the {@link MetricsService} of Slimefun.
* It is used to handle sending metric information to bStats.
*
* @return The {@link MetricsService} for Slimefun
*/
public static MetricsService getMetricsService() {
return instance.metricsService;
}
/** /**
* This method returns the {@link GitHubService} of Slimefun. * This method returns the {@link GitHubService} of Slimefun.
* It is used to retrieve data from GitHub repositories. * It is used to retrieve data from GitHub repositories.

View File

@ -6,7 +6,7 @@ options:
auto-update: true auto-update: true
backwards-compatibility: true backwards-compatibility: true
chat-prefix: '&a&lSlimefun 4 &7>' chat-prefix: '&a&lSlimefun 4&7> '
armor-update-interval: 10 armor-update-interval: 10
enable-armor-effects: true enable-armor-effects: true
auto-save-delay-in-minutes: 10 auto-save-delay-in-minutes: 10
@ -40,6 +40,9 @@ items:
backpacks: true backpacks: true
soulbound: true soulbound: true
metrics:
auto-update: true
research-ranks: research-ranks:
- Chicken - Chicken
- Cow - Cow