This commit is contained in:
Minecon724 2024-12-07 18:08:10 +01:00
parent 760e926bec
commit 239bce872d
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
4 changed files with 195 additions and 63 deletions

View file

@ -4,28 +4,26 @@ In `pom.xml`:
<dependency> <dependency>
<groupId>eu.m724</groupId> <groupId>eu.m724</groupId>
<artifactId>mstats-spigot</artifactId> <artifactId>mstats-spigot</artifactId>
<version>0.1.0</version>
</dependency> </dependency>
``` ```
In `plugin.yml`: In `plugin.yml`:
```yaml ```yaml
libraries: libraries:
- eu.m724:mstats-spigot - eu.m724:mstats-spigot:0.1.0
``` ```
In main class: In main class:
```java ```java
import eu.m724.mstats.MStats; import eu.m724.mstats.MStatsPlugin;
import org.bukkit.plugin.java.JavaPlugin;
public class MyPlugin extends JavaPlugin { public class MyPlugin extends MStatsPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// it's recommended that this is the last line of onEnable // It's recommended that this is the last line of onEnable
mStats(1); // Replace 1 of course with your plugin ID
int mStatsId = 1; // replace this of course with your plugin ID
MStats.init(this, mStatsId);
} }
} }
``` ```

84
pom.xml
View file

@ -8,6 +8,25 @@
<artifactId>mstats-spigot</artifactId> <artifactId>mstats-spigot</artifactId>
<version>0.1.0-SNAPSHOT</version> <version>0.1.0-SNAPSHOT</version>
<developers>
<developer>
<id>m724</id>
<name>Minecon724</name>
</developer>
</developers>
<licenses>
<license>
<name>GPL-3.0-or-later</name>
<url>https://www.gnu.org/licenses/gpl-3.0.en.html</url>
<distribution>repo</distribution>
<comments>The GNU General Public License is a free, copyleft license for software and other kinds of works.</comments>
</license>
</licenses>
<url>https://git.m724.eu/Minecon724/mstats-spigot</url>
<description>mStats client for Spigot</description>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
@ -35,7 +54,72 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.6.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.7</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.1.1</version>
</plugin>
</plugins>
</build>
<scm> <scm>
<connection>scm:git:git@git.m724.eu:Minecon724/mstats-spigot.git</connection>
<developerConnection>scm:git:git@git.m724.eu:Minecon724/mstats-spigot.git</developerConnection> <developerConnection>scm:git:git@git.m724.eu:Minecon724/mstats-spigot.git</developerConnection>
<url>https://git.m724.eu/Minecon724/mstats-spigot</url>
</scm> </scm>
</project> </project>

View file

@ -1,76 +1,88 @@
package eu.m724.mstats; package eu.m724.mstats;
import com.google.gson.*; import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors;
public class MStats extends BukkitRunnable { public class MStats extends BukkitRunnable {
private static final int VERSION = 1; static final int PROT_VERSION = 1;
private BukkitTask task;
private final Map<Plugin, Integer> registeredPlugins = new HashMap<>();
private final Plugin plugin; private final Plugin plugin;
private final URI server;
private final Map<Plugin, Integer> registeredPlugins = new HashMap<>();
private final Logger logger = Logger.getLogger("mStats"); private final Logger logger = Logger.getLogger("mStats");
private String token = ""; private String token = "";
private static MStats INSTANCE; public MStats(MStatsPlugin plugin) {
public MStats(Plugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.server = plugin.getMStatsServer();
} }
public static void init(Plugin plugin, int id) { void init() {
if (INSTANCE != null && INSTANCE.plugin.isEnabled()) {
INSTANCE.registeredPlugins.put(plugin, id);
return;
}
var mStats = new MStats(plugin);
mStats.registeredPlugins.put(plugin, id);
mStats.init();
}
private void init() {
if (INSTANCE != null) {
logger.info("Plugin crashed. Restarting mStats.");
task.cancel();
// some plugins may have registered before the one that crashed
this.registeredPlugins.putAll(INSTANCE.registeredPlugins);
}
INSTANCE = this;
// a scheduler starts running the first tick after everything was loaded // a scheduler starts running the first tick after everything was loaded
task = new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
firstRun(); firstRun();
} }
}.runTaskLater(plugin, 0); }.runTaskLater(plugin, 0);
logger.info("mStats running as " + plugin.getName()); //logger.info("mStats running as " + plugin.getName());
} }
private void firstRun() { private void firstRun() {
for (Plugin plugin : this.registeredPlugins.keySet()) { for (Plugin plugin : plugin.getServer().getPluginManager().getPlugins()) {
if (!plugin.isEnabled()) { //System.out.println(plugin.getName());
// remove broken plugins if (!plugin.isEnabled()) continue;
this.registeredPlugins.remove(plugin); //System.out.println("a");
try {
Method method = plugin.getClass().getMethod("getMStatsId");
int id = (int) method.invoke(plugin);
method = plugin.getClass().getMethod("getMStatsServer");
URI server = (URI) method.invoke(plugin);
if (id > 0 && server.equals(this.server))
registeredPlugins.put(plugin, id);
} catch (NoSuchMethodException e) {
// plugin is not a mstats plugin
} catch (InvocationTargetException | IllegalAccessException e) {
// this should never happen
throw new RuntimeException(e);
} }
} }
task.cancel(); String first = registeredPlugins.keySet().stream().map(Plugin::getName).sorted().findFirst().get();
task = this.runTaskTimerAsynchronously(plugin, 0, 72000);
if (!plugin.getName().equals(first)) {
//logger.info("I pass control to " + first);
return;
}
// basically "PluginName #21, AnotherPlugin* #32" - (plugin name) + (* if stats runs on the plugin) + (# plugin id) joined with ", "
logger.info(server.getHost() + " " +
registeredPlugins.entrySet().stream().map(
e -> e.getKey().getName()
+ (first.equals(e.getKey().getName()) ? "*" : "")
+ " #" + e.getValue())
.collect(Collectors.joining(", ")
)
);
this.runTaskTimerAsynchronously(plugin, 0, 72000);
} }
// TODO don't send this every time // TODO don't send this every time
@ -78,37 +90,34 @@ public class MStats extends BukkitRunnable {
public void run() { public void run() {
var json = new JsonObject(); var json = new JsonObject();
var pla = new JsonArray(); var pla = new JsonArray();
registeredPlugins.forEach((key, value) -> { registeredPlugins.forEach((p, id) -> {
var o1 = new JsonObject(); var o1 = new JsonObject();
o1.addProperty("id", value); o1.addProperty("id", id);
o1.addProperty("version", key.getDescription().getVersion()); o1.addProperty("version", p.getDescription().getVersion());
pla.add(o1); pla.add(o1);
}); });
json.add("plugins", pla); json.add("plugins", pla);
json.addProperty("serverVersion", plugin.getServer().getVersion()); json.addProperty("serverVersion", plugin.getServer().getVersion());
json.addProperty("statsVersion", VERSION); json.addProperty("statsVersion", PROT_VERSION);
HttpRequest request; HttpRequest request = HttpRequest
try { .newBuilder(server)
request = HttpRequest
.newBuilder(new URI("http://localhost:8080/api/server/heartbeat"))
.POST(HttpRequest.BodyPublishers.ofString(new Gson().toJson(json))) .POST(HttpRequest.BodyPublishers.ofString(new Gson().toJson(json)))
.header("X-Server-Token", token) .header("X-Server-Token", token)
.build(); .build();
} catch (URISyntaxException e) { throw new RuntimeException(e); }
try (HttpClient httpClient = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NEVER).build()) { try (HttpClient httpClient = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NEVER).build()) {
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(resp -> { httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(resp -> {
JsonObject response = JsonParser.parseString(resp.body()).getAsJsonObject(); JsonObject response = JsonParser.parseString(resp.body()).getAsJsonObject();
if (response.has("message")) { if (response.has("message")) {
logger.info("Message from metrics server: " + response.get("message").getAsString()); logger.info("Message from mStats server: " + response.get("message").getAsString());
} }
if (resp.statusCode() != 200) { if (resp.statusCode() != 200) {
logger.severe("Unable to contact metrics. It's not known why. " + resp.statusCode()); logger.severe("Unable to contact mStats. It's not known why. " + resp.statusCode());
logger.severe(resp.body()); //logger.severe(resp.body());
return; return;
} }
@ -119,6 +128,9 @@ public class MStats extends BukkitRunnable {
if (response.has("version")) { if (response.has("version")) {
// TODO // TODO
} }
}).exceptionally(e -> {
logger.severe("Unable to contact mStats. Error. " + e.getMessage());
return null;
}); });
} }
} }

View file

@ -0,0 +1,38 @@
package eu.m724.mstats;
import org.bukkit.plugin.java.JavaPlugin;
import java.net.URI;
public class MStatsPlugin extends JavaPlugin {
private int id = -1;
private URI server = URI.create("https://mstats.m724.eu/api/server/heartbeat");
/**
* Enable mStats for this plugin<br>
* If you don't call this, mStats will not be enabled
*
* @param id the mStats plugin ID
*/
public void mStats(int id) {
this.id = id;
new MStats(this).init();
}
/**
* Set the mStats backend server
*
* @param server the server URL
*/
public void mStatsServer(String server) {
this.server = URI.create(server + "/api/server/heartbeat");
}
public int getMStatsId() {
return id;
}
public URI getMStatsServer() {
return server;
}
}