diff --git a/MelooonCensor.iml b/MelooonCensor.iml index 05b723a..06a8ede 100644 --- a/MelooonCensor.iml +++ b/MelooonCensor.iml @@ -24,5 +24,7 @@ + + \ No newline at end of file diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index cdff835..0d7a09b 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.github.jacobmarshall.meloooncensor - MelooonCensor + meloooncensor 3.0.0-SNAPSHOT @@ -34,12 +34,22 @@ org.mcstats.*:* + com.bugsnag:* + org.json:* org.mcstats - io.github.jacobmarshall.meloooncensor.metrics + io.github.jacobmarshall.meloooncensor.lib.org.mcstats + + + com.bugsnag + io.github.jacobmarshall.meloooncensor.lib.com.bugsnag + + + org.json + io.github.jacobmarshall.meloooncensor.lib.org.json diff --git a/pom.xml b/pom.xml index 54ad322..121615b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 io.github.jacobmarshall.meloooncensor - MelooonCensor + meloooncensor 3.0.0-SNAPSHOT @@ -32,12 +32,22 @@ org.mcstats.*:* + com.bugsnag:* + org.json:* org.mcstats - io.github.jacobmarshall.meloooncensor.metrics + io.github.jacobmarshall.meloooncensor.lib.org.mcstats + + + com.bugsnag + io.github.jacobmarshall.meloooncensor.lib.com.bugsnag + + + org.json + io.github.jacobmarshall.meloooncensor.lib.org.json @@ -91,6 +101,16 @@ R8-SNAPSHOT compile + + com.bugsnag + bugsnag + 1.3.0 + + + org.json + json + 20151123 + \ No newline at end of file diff --git a/src/main/java/io/github/jacobmarshall/meloooncensor/MelooonCensor.java b/src/main/java/io/github/jacobmarshall/meloooncensor/MelooonCensor.java index 7bac700..f91ed92 100644 --- a/src/main/java/io/github/jacobmarshall/meloooncensor/MelooonCensor.java +++ b/src/main/java/io/github/jacobmarshall/meloooncensor/MelooonCensor.java @@ -1,9 +1,13 @@ package io.github.jacobmarshall.meloooncensor; +import com.bugsnag.Client; import io.github.jacobmarshall.meloooncensor.config.Configuration; import io.github.jacobmarshall.meloooncensor.listener.ChatEventListener; import io.github.jacobmarshall.meloooncensor.command.CensorCommandExecutor; +import io.github.jacobmarshall.meloooncensor.listener.PlayerJoinEventListener; +import io.github.jacobmarshall.meloooncensor.updater.CheckForUpdatesTask; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; import org.mcstats.Metrics; import java.io.IOException; @@ -11,6 +15,13 @@ public class MelooonCensor extends JavaPlugin { private Configuration config; + private CheckForUpdatesTask updater; + private Client bugsnag; + + protected void startBugsnag () { + bugsnag = new Client("b5347687fe92ee7494d20cdf5a725fad"); + bugsnag.setProjectPackages("io.github.jacobmarshall.meloooncensor"); + } protected void startMetrics () { try { @@ -22,10 +33,18 @@ protected void startMetrics () { } protected void registerEvents () { + getServer().getScheduler().runTaskTimerAsynchronously( + this, updater = new CheckForUpdatesTask(this, bugsnag), 0L, 36000L + ); + getServer().getPluginManager().registerEvents( new ChatEventListener(this.config), this ); + getServer().getPluginManager().registerEvents( + new PlayerJoinEventListener(this.updater), this + ); + getCommand("censor").setExecutor( new CensorCommandExecutor(this.config) ); @@ -37,6 +56,7 @@ protected void setupConfig () { @Override public void onEnable () { + startBugsnag(); setupConfig(); startMetrics(); registerEvents(); diff --git a/src/main/java/io/github/jacobmarshall/meloooncensor/listener/PlayerJoinEventListener.java b/src/main/java/io/github/jacobmarshall/meloooncensor/listener/PlayerJoinEventListener.java index c93a9a3..797bdbf 100644 --- a/src/main/java/io/github/jacobmarshall/meloooncensor/listener/PlayerJoinEventListener.java +++ b/src/main/java/io/github/jacobmarshall/meloooncensor/listener/PlayerJoinEventListener.java @@ -1,7 +1,30 @@ package io.github.jacobmarshall.meloooncensor.listener; +import io.github.jacobmarshall.meloooncensor.config.Configuration; +import io.github.jacobmarshall.meloooncensor.updater.CheckForUpdatesTask; +import io.github.jacobmarshall.meloooncensor.updater.Release; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; public class PlayerJoinEventListener implements Listener { + CheckForUpdatesTask updater; + + public PlayerJoinEventListener (CheckForUpdatesTask updater) { + this.updater = updater; + } + + @EventHandler + public void onPlayerJoin (PlayerJoinEvent event) { + Player player = event.getPlayer(); + + if (player.isOp() && updater.isUpdateAvailable()) { + Release latestRelease = updater.getLatestRelease(); + player.sendMessage(ChatColor.AQUA + "A new version of MelooonCensor is available, please visit " + latestRelease.getReleaseUrl() + "."); + } + } + } diff --git a/src/main/java/io/github/jacobmarshall/meloooncensor/updater/CheckForUpdatesTask.java b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/CheckForUpdatesTask.java new file mode 100644 index 0000000..cb1d494 --- /dev/null +++ b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/CheckForUpdatesTask.java @@ -0,0 +1,120 @@ +package io.github.jacobmarshall.meloooncensor.updater; + +import com.bugsnag.Client; +import io.github.jacobmarshall.meloooncensor.MelooonCensor; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Iterator; + +public class CheckForUpdatesTask implements Runnable { + + public static final String API_URL = "https://api.github.com"; + public static final String API_ACCEPT = "application/vnd.github.v3+json"; + public static final String REPO = "jacobmarshall/meloooncensor"; + + private MelooonCensor plugin; + private Version version; + private Client bugsnag; + + private boolean isOutdated; + private Release latestRelease; + + public CheckForUpdatesTask (MelooonCensor plugin, Client bugsnag) { + this.plugin = plugin; + this.bugsnag = bugsnag; + this.version = new Version(plugin.getDescription().getVersion()); + } + + @Override + public void run () { + boolean isOutdated = false; + Release latestRelease = null; + + try { + String releasesText = sendRequest("/repos/" + REPO + "/releases"); + if (releasesText != null) { + JSONArray releases = new JSONArray(releasesText); + + if (releases.length() > 0) { + for (int index = 0; index < releases.length(); index++) { + Release release = Release.from(releases.getJSONObject(index)); + + if ( ! release.isPreRelease()) { + Version releaseVersion = new Version(release.getVersion()); + + if (releaseVersion.compareTo(version) > 0) { + isOutdated = true; + latestRelease = release; + } + + break; + } + } + } + } + } catch (Exception err) { + bugsnag.notify(err); + } finally { + this.isOutdated = isOutdated; + this.latestRelease = latestRelease; + } + } + + private String sendRequest (String api) { + HttpURLConnection connection = null; + + try { + URL url = new URL(API_URL + "/" + api); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Accept", API_ACCEPT); + + int statusCode = connection.getResponseCode(); + + if (statusCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = null; + + try { + reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + String line; + StringBuilder response = new StringBuilder(); + + while ((line = reader.readLine()) != null) { + response.append(line); + } + + return response.toString(); + } catch (IOException err) { + bugsnag.notify(err); + } finally { + if (reader != null) { + reader.close(); + } + } + } + } catch (Exception err) { + bugsnag.notify(err); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + return null; + } + + public boolean isUpdateAvailable () { + return isOutdated; + } + + public Release getLatestRelease () { + return latestRelease; + } + +} diff --git a/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Release.java b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Release.java new file mode 100644 index 0000000..1f7c296 --- /dev/null +++ b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Release.java @@ -0,0 +1,50 @@ +package io.github.jacobmarshall.meloooncensor.updater; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class Release { + + String version; + String description; + String downloadUrl; + String releaseUrl; + boolean isPreRelease; + + private Release () {} + + public String getVersion () { + return version; + } + + public String getDescription () { + return description; + } + + public String getDownloadUrl () { + return downloadUrl; + } + + public String getReleaseUrl () { + return releaseUrl; + } + + public boolean isPreRelease () { + return isPreRelease; + } + + public static Release from (JSONObject json) { + Release release = new Release(); + release.version = json.getString("tag_name"); + release.description = json.getString("body"); + { + JSONArray assets = json.getJSONArray("assets"); + JSONObject jar = assets.getJSONObject(0); + release.downloadUrl = jar.getString("browser_download_url"); + } + release.releaseUrl = json.getString("html_url"); + release.isPreRelease = json.getBoolean("prerelease"); + return release; + } + +} diff --git a/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Version.java b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Version.java new file mode 100644 index 0000000..6782a2a --- /dev/null +++ b/src/main/java/io/github/jacobmarshall/meloooncensor/updater/Version.java @@ -0,0 +1,61 @@ +package io.github.jacobmarshall.meloooncensor.updater; + +/** + * http://stackoverflow.com/a/11024200 + */ +public class Version implements Comparable { + + private String version; + + public final String get () { + return this.version; + } + + public Version (String version) { + if (version == null) { + throw new IllegalArgumentException("Version can not be null"); + } + if ( ! version.matches("[0-9]+(\\.[0-9]+)*")) { + throw new IllegalArgumentException("Invalid version format"); + } + this.version = version; + } + + @Override + public int compareTo (Version that) { + if (that == null) { + return 1; + } + String[] thisParts = this.get().split("\\."); + String[] thatParts = that.get().split("\\."); + int length = Math.max(thisParts.length, thatParts.length); + for (int i = 0; i < length; i++) { + int thisPart = i < thisParts.length ? + Integer.parseInt(thisParts[i]) : 0; + int thatPart = i < thatParts.length ? + Integer.parseInt(thatParts[i]) : 0; + if (thisPart < thatPart) { + return -1; + } + if (thisPart > thatPart) { + return 1; + } + } + return 0; + } + + @Override + public boolean equals (Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (this.getClass() != that.getClass()) { + return false; + } + return this.compareTo((Version) that) == 0; + } + +} \ No newline at end of file