HomeJavaModsAutoUpdaterAPI
AutoUpdaterAPI

[​IMG]


Auto Updater API is an API for seamlessly updating your free and premium Spigot plugins without requiring a restart or reload.

[​IMG] [​IMG]
[​IMG] [​IMG]
[​IMG]
Hello everyone, recently I was working on an update for my other Spigot plugin Thirst and wanted to make an auto-updater for it that was completely seamless and didn't require a restart, auto updater API was my result.

FOR SERVER OWNERS
This plugin will do NOTHING on its own! It is only for use by developers who want to incorporate auto-updating into their plugin.


[​IMG]

SIMPLE - AutoUpdaterAPI is simple to use and looks great with your plugin.

LIGHTWEIGHT - With the right configuration, AutoUpdater can update your plugin in less than half a second.

POWERFUL - AutoUpdater can automatically download and install premium and free resources and utilizes Bukkit's multithreading API to make downloads as fast and non-intensive as possible.

SECURE - Since AutoUpdater needs to hold your users' spigot credentials (for premium resource updating) it uses 2048 bit AES encryption with randomly generated keys and has obfuscated the classes it uses to encrypt.

CLEAN - AutoUpdater has a clean and customizable UI. It has a custom format for logging errors, and you can even turn on a full debug mode through the main class.

OPEN - AutoUpdater is fully open source and can be found on GitHub here.

[​IMG]

I've created a short video showcasing the API in action and how to use it in your code.



[​IMG]
This plugin is currently in use with my other plugin Thirst (Yeah I know shameless plugging ok?). Anyways here's a gif of me updating from the dev version I had (V1.7.1) to the latest spigot version V1.6.2.
[​IMG]

[​IMG]

There are two main classes to AutoUpdaterAPI Updater and PremiumUpdater. To use them you just instantiate them and call the update method. Keep in mind both of these have Javadoc notation when you instantiate them.

EXAMPLES

Code (Text):
new Updater(player, javaPlugin, resourceId, updateLocale, deleteUpdater, deleteOld).update();
Code (Text):
new PremiumUpdater(player, javaPlugin, resourceId, updateLocale, deleteUpdater, deleteOld).update();

The updateLocale variable is a container class for all of the ActionBar messages sent while you might not want to change all of the messages you'll need to change the fileName and pluginName variables which are the name of the jar file that will be downloaded and the name of the plugin that will be enabled. All these messages can take ChatColors in the form of color codes starting with a & symbol. There are also a bunch of variables that can be replaced with plugin info, here is a list of the placeholders.

%plugin% - Name of the plugin being updated.
%old_version% - Version of the plugin that is being deleted.
%new_version% - Version of the plugin that is being installed.
%download_bar% - Progress bar of the download, only applicable to the UpdatingDownload string.
%download_percent% - Percent of the download, only applicable to the UpdatingDownload string.
%elapsed_time% - Time the updating process took in seconds, only relevant to the UpdateComplete string.

AutoUpdaterAPI works best when you download it yourself and enable it so that updating is entirely seamless. I've written a util class you can copy paste and then replace the variables to accomplish this. Please keep in mind that this WILL NOT WORK for premium resources. But for premium resources, you could just remove the checkForUpdate method and make the Updater a PremiumUpdater.

Please note this class uses Gson to parse the JSON responses from Spiget, you will need to have that in your dependencies.

Code (Text):
import com.gamerking195.dev.autoupdaterapi.UpdateLocale;
import com.gamerking195.dev.autoupdaterapi.Updater;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.*;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;

public class %CLASSNAME% {
    private %CLASSNAME%() {}
    private static %CLASSNAME% instance = new %CLASSNAME%();
    public static %CLASSNAME% getInstance() {
        return instance;
    }

    private String latestVersion;

    private boolean updateAvailable;
    private boolean updating;

    private JavaPlugin plugin = %MAINCLASS%;

    private Gson gson = new Gson();

    /*
     * UTILITIES
     */

    public void checkForUpdate() {
        try {
            //Latest version number.
            String latestVersionInfo = readFrom("https://api.spiget.org/v2/resources/%RESOURCEID%/versions/latest");

            Type type = new TypeToken<JsonObject>() {}.getType();
            JsonObject object = gson.fromJson(latestVersionInfo, type);

            latestVersion = object.get("name").getAsString();
            updateAvailable = !latestVersion.equals(plugin.getDescription().getVersion());
        }
        catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    public void update(Player initiator) {
        checkForUpdate();

        if (updateAvailable && !updating) {
            sendActionBar(initiator, ChatColor.translateAlternateColorCodes('&', "&f&lUPDATING &1&l%PLUGINNAME% &b&lV" + plugin.getDescription().getVersion() + " &a&l» &b&lV" + latestVersion + " &8[RETREIVING UPDATER]"));

            updating = true;
            boolean delete = true;

            try {
                if (!Bukkit.getPluginManager().isPluginEnabled("AutoUpdaterAPI")) {
                    delete = false;

                    //Download AutoUpdaterAPI
                    URL url = new URL("https://api.spiget.org/v2/resources/39719/download");
                    HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
                    httpConnection.setRequestProperty("User-Agent", "SpigetResourceUpdater");
                    long completeFileSize = httpConnection.getContentLength();

                    BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream());
                    FileOutputStream fos = new FileOutputStream(new File(plugin.getDataFolder().getPath().substring(0, plugin.getDataFolder().getPath().lastIndexOf("/")) + "/AutoUpdaterAPI.jar"));
                    BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);

                    byte[] data = new byte[1024];
                    long downloadedFileSize = 0;
                    int x;
                    while ((x = in.read(data, 0, 1024)) >= 0) {
                        downloadedFileSize += x;

                        if (downloadedFileSize % 5000 == 0) {
                            final int currentProgress = (int) ((((double) downloadedFileSize) / ((double) completeFileSize)) * 15);

                            final String currentPercent = String.format("%.2f", (((double) downloadedFileSize) / ((double) completeFileSize)) * 100);

                            String bar = "&a:::::::::::::::";

                            bar = bar.substring(0, currentProgress + 2) + "&c" + bar.substring(currentProgress + 2);

                            sendActionBar(initiator, ChatColor.translateAlternateColorCodes('&', "&f&lUPDATING &1&l%PLUGINNAME% &b&lV" + plugin.getDescription().getVersion() + " &a&l» &b&lV" + latestVersion + " &8&l| " + bar + " &8&l| &2" + currentPercent + "% &8[DOWNLOADING UPDATER]"));
                        }

                        bout.write(data, 0, x);
                    }

                    bout.close();
                    in.close();

                    sendActionBar(initiator, ChatColor.translateAlternateColorCodes('&', "&f&lUPDATING &1&l%PLUGINNAME% &b&lV" + plugin.getDescription().getVersion() + " &a&l» &b&lV" + latestVersion + " &8[RUNNING UPDATER]"));

                    Plugin target = Bukkit.getPluginManager().loadPlugin(new File(plugin.getDataFolder().getPath().substring(0, plugin.getDataFolder().getPath().lastIndexOf("/")) + "/AutoUpdaterAPI.jar"));
                    target.onLoad();
                    Bukkit.getPluginManager().enablePlugin(target);
                }

                //TODO Plugin shutdown logic.

                UpdateLocale locale = new UpdateLocale();

                //TODO Message configuration.

                locale.setFileName("%PLUGINNAME%-" + latestVersion);
                locale.setPluginName("%PLUGINNAME%");

                new Updater(initiator, plugin, %RESOURCEID%, locale, delete, true).update();
            } catch (Exception ex) {
                ex.printStackTrace();
                sendActionBar(initiator, ChatColor.translateAlternateColorCodes('&', "&f&lUPDATING &1&l%PLUGINNAME% &b&lV" + plugin.getDescription().getVersion() + " &b&l» &1&lV" + latestVersion + " &8[&c&lUPDATE FAILED &7&o(Check Console)&8]"));
            }
        }
    }

    /*
     * GETTERS
     */

    public String getLatestVersion() {
        return latestVersion;
    }

    public boolean isUpdateAvailable() {
        return updateAvailable;
    }

    /*
     * PRIVATE UTILITIES
     */

    private String readFrom(String url) throws IOException
    {
        try (InputStream is = new URL(url).openStream())
        {
            BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));

            StringBuilder sb = new StringBuilder();
            int cp;
            while ((cp = rd.read()) != -1) {
                sb.append((char) cp);
            }

            return sb.toString();
        }
    }

    private void sendActionBar(Player player, String message) {
        if (player != null)
            player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(ChatColor.translateAlternateColorCodes('&', message)));
    }
}
If you copy/paste that into its class and find/replace %CLASSNAME% with the name of the class. %PLUGINNAME% with the name of the plugin, %RESOURCEID% with your Spigot resource id

Remember, your resource id is the little number after the name in the URL, for instance. spigotmc.org/resources/thirst.24610/ 24610 is the id of the resource.

[​IMG]

You can use the auto-update API through my maven repository.

REPO
Code (Text):
<repository>
    <id>flogic-releases</id>
    <url>https://repo.flogi.cc/artifactory/flogic-releases</url>
</repository>
DEPENDENCY
Code (Text):
<dependency>
    <groupId>com.gamerking195.dev</groupId>
    <artifactId>AutoUpdaterAPI</artifactId>
    <version>2.5.3</version>
    <scope>provided</scope>
</dependency>
[​IMG]
[​IMG]
[​IMG]

[​IMG] [​IMG]
This plugin is under the Apache License 2.0 as seen on GitHub. Which effectively means, feel free to take the code and use it in your way, however, you must credit me as the original author, and state any changes you made (That is not legal advice, click here to view the full license). If you're just using the API you don't have to credit me but that would be much appreciated.
[​IMG]

Plugin details

Read from the plugin's own plugin.yml.

Quick facts

Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.

AutoUpdaterAPI is a free Minecraft Java mod. Compatible with Minecraft 1.8, 1.9, 1.10, 1.11 and newer. Downloaded 3,839 times (via Spigot). Download it and open it directly in the game.

Explore more