Updater 2.3- Easy, Safe, and Policy-Compliant auto-updating for your plugins [NEW!]

Discussion in 'Resources' started by Gravity, Aug 28, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Gravity

    Updater - Version 2.3
    Updater is an easy-to-use but robust and fully policy-compliant plugin updating system. It provides plugin developers with the ability to both check for and download new updates straight from BukkitDev, and requires no web server setup to function.

    Download and Source:
    Updater is a single class file that you need to add to your plugin. Simply create a new class somewhere in your plugin named "Updater", and populate it with Updater's source code, which you can find by clicking the "Get Updater" link below. Then, go to the "How to use it" section to learn how adding one line of code to your plugin will implement Updater.

    Get Updater

    Features:

    • No more hassle! Never worry about configuring your Dropbox text files to the latest build's url, or forgetting to update external files again. Upload once to BukkitDev, and as soon as your file is approved clients will start downloading it, even if the approval comes at 4am and you're fast asleep.
    • Setup is as easy as copying a class and giving it your BukkitDev project slug. Updater will do the rest.
    • Ability to tag certain builds as non-update builds. For instance, on my Jenkins system every build is tagged with -DEV, so that people who are using it do not get switched to the official latest build, and can stay testing the pre-release. Simply edit the "noUpdateTag" array in the class to define what kind of builds should be left alone.
    • Don't hassle your users anymore. Server admins have enough on their hands, don't concern them with updates, because they just will /not/ update. From personal experience, I know that the only time I cared about a plugin update was when something broke. It's far too difficult to worry about a new file every day, but if you let Updater automatically install updates, your users will rejoice!
    • Be safe. EVERY file that Updater downloads has been approved by BukkitDev staff. Real humans go line-by-line through the code of each plugin that is approved on dev.bukkit.org, to verify it is free of any malicious code. Your user's shouldn't have to blindly accept your trust, you can instead show and prove to them that by using updater, you are keeping them secure.
    • Works with both .jar file and .zip file updates.
    -- Get Updater --


    How it works:

    - First, Updater connects to BukkitDev API and requests information about your project.

    - It then searches the information for the latest file, and obtains information about it like its name and version number.

    - Optionally, Updater will run a version check, comparing the newest file with the plugin's current version. NOTE: For this to work, your file titles must be named in this format: 'PluginName vVersionNumber', such as 'AntiCheat v1.0' (or simply 'v1.0', the name is not needed, but suggested). Here's a screenshot of how this should look, if done properly:
    File titles with proper version numbers (open)

    [​IMG]

    - Assuming that an update is needed, Updater will download the file from dev.bukkit.org and store it in the update folder. This is a folder defined in the bukkit.yml file where any stored jars will be switched with its currently-in-use counterpart when the system is reloaded or restarted. This means that the user does not need to worry about replacing the downloaded file with the current file; it's all done in the background.

    How to use it:

    If you are using Maven to manage your project you can use my Maven repository to get the dependency. To do this, edit your pom.xml to add the following repository:
    Code:
        <repositories>
            <repository>
                <id>gravity-repo</id>
                <url>http://repo.gravitydevelopment.net</url>
            </repository>
        </repositories>
    
    Then, add the following dependency:
    Code:
        <dependencies>
            <dependency>
                <groupId>net.gravitydevelopment.updater</groupId>
                <artifactId>updater</artifactId>
                <version>2.1</version>
            </dependency>
        </dependencies>
    
    Otherwise, you can use the traditional way and download the source code for Updater. Simply place this somewhere within your plugin's packages, and then switch over to your main class to get to work.

    As with most of my projects, I boast the fact that you only need one line of code added to your main class (the one that extends JavaPlugin) to make this work (along with my Updater class, of course), so here's what it is:

    Code:
    Updater updater = new Updater(this, id, this.getFile(), Updater.UpdateType.DEFAULT, false);
    That's it! This single line of code will literally keep the user updated for the rest of their life. Here's a breakdown of what all these values are:

    1) "this" - The plugin instance. I suggest using this in your onEnable() method, so that you can properly issue the 'this' keyword. Other methods that are called before onEnable() will not work (but anything after it, or that is called BY onEnable() does work).

    2) "id" - This is how Updater finds your project on BukkitDev. If you don't know what this is, follow the instructions on this wiki article.

    3) "this.getFile()" - The plugin's file, this is so that Updater can properly replace your plugin with the update when it is downloaded. Note that this is a protected value, and so it can only be accessed within your plugin's main class

    4) "Updater.UpdateType.DEFAULT" - This allows you to choose which type of update you would like to take place. Currently there are 3 options:
    - DEFAULT - Typically what you would want. Do an update check, and then if it's out of date download and install the latest update.
    - NO_VERSION_CHECK - In case you know you need (or want) to update, skip version checking and just download the latest file, regardless of any it's details.
    - NO_DOWNLOAD - In case you just want to do a version check. No files will be downloaded, but you still get information about the newest build on DBO, like it's version number and size.

    5) "false" - This is a value declaring whether you want Updater to announce the progress of the download, as it takes place. This is similar to what this output (to the console) will look like:
    Output (open)

    2012-08-29 16:30:56 [INFO] [AntiCheat] Enabling AntiCheat v1.3.6-DEV
    2012-08-29 16:30:57 [INFO] About to download a new update: AntiCheat v1.3.5
    2012-08-29 16:30:57 [INFO] Downloading update: 10% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 20% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 30% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 50% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 70% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 80% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 90% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 100% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Finished updating.

    If this option is true, and there is no update, there will be no output to the console.

    You can also see these values documented in JavaDocs here: http://gravitydevelopment.net/docs/updater/

    ------------------------------------------------------------------------------------------------------------------------------------
    NOTICE:
    As of Updater 2.0, a configuration file is created to allow server administrators to globally toggle updating for any plugin using this class. While this option does provide a convenient method for server admins to disable all Updater instances, Bukkit project submission guidelines still require that you make your plugin's Updater instance specifically toggleable with its own configuration option. This gives server administrators the opportunity to only disable the updating capabilities of one plugin in particular, should they choose to do so. You may read more about compliance with this policy here.
    ------------------------------------------------------------------------------------------------------------------------------------


    Expanding updater:

    Note: The following contains more advanced user information on controlling Updater. While Updater is very simple to use, it also gives a great deal of feedback and control to the developer if they want to use it. If you are just starting to develop plugins, it is recommended that you stop here and just use Updater as you have learned to use it so far. If you are an advanced user, you may continue on, but know that all of the following info is optional, and only necessary if you want to customize your experience.

    Now, of course you may want to know what the outcome of the process was, so you can inform the user or update some values in your plugin to reflect that it is now updated. This result can easily be obtained by using the "getResult()" call. This returns an UpdateResult that reflects what happened.​

    Code:
            Updater.UpdateResult result = updater.getResult();
            switch(result)
            {
                case SUCCESS:
                    // Success: The updater found an update, and has readied it to be loaded the next time the server restarts/reloads
                    break;
                case NO_UPDATE:
                    // No Update: The updater did not find an update, and nothing was downloaded.
                    break;
                case DISABLED:
                    // Won't Update: The updater was disabled in its configuration file.
                    break;
                case FAIL_DOWNLOAD:
                    // Download Failed: The updater found an update, but was unable to download it.
                    break;
                case FAIL_DBO:
                    // dev.bukkit.org Failed: For some reason, the updater was unable to contact DBO to download the file.
                    break;
                case FAIL_NOVERSION:
                    // No version found: When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'.
                    break;
                case FAIL_BADID:
                    // Bad id: The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
                    break;
                case FAIL_APIKEY:
                    // Bad API key: The user provided an invalid API key for the updater to use.
                    break;
                case UPDATE_AVAILABLE:
                  // There was an update found, but because you had the UpdateType set to NO_DOWNLOAD, it was not downloaded.
            }
    All these values, of course, are documented in easy-to-read HTML here: http://gravitydevelopment.net/docs/updater/

    You also may want to know information about the newest update. Some people prefer to have Updater run a version check ONLY (using UpdateType.NO_DOWNLOAD), then, if there is an update available, start notifying admins as they log in that there is a new version ready, with information like file size and version. An admin would then issue a command, and the developer would run Updater again but this time with UpdateType set to NO_VERSION_CHECK, thus downloading the newest build at the admin's request.

    We have a few methods available for you to use for this information. We already know that we can determine the outcome of the version check by calling getResult(), but here are some more methods you can call to get information about the newest file:

    - getLatestName() - Returns the name of the latest file you have uploaded to BukkitDev (Ex: "AntiCheat v1.5.9")
    - getLatestType() - Returns the type of the latest file you have uploaded to BukkitDev (Alpha, Beta, Release)
    - getLatestGameVersion() - Returns the compatible Game Version of the latest file you have uploaded to BukkitDev (Ex: "CB 1.6.2-R1.0")
    - getLatestFileLink() - Returns the link to the latest file you have uploaded.

    The scenario mentioned about would look something like this (pseudocode):

    Code:
    // In main class
    
    public static boolean update = false;
    public static String name = "";
    public static ReleaseType type = null;
    public static String version = "";
    public static String link = "";
    // You would want to make getter methods in your class, this is just for simplicity.
    
    public void onEnable()
    {
      Updater updater = new Updater(this, YOUR_ID_HERE, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false); // Start Updater but just do a version check
      update = updater.getResult() == Updater.UpdateResult.UPDATE_AVAILABLE; // Determine if there is an update ready for us
      name = updater.getLatestName(); // Get the latest name
      version = updater.getLatestGameVersion(); // Get the latest game version
      type = updater.getLatestType(); // Get the latest file's type
      link = updater.getLatestFileLink(); // Get the latest link
    }
    
    // In a listener class:
    
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event)
    {
      Player player = event.getPlayer();
      if(player.hasPermission("foo.bar") && Main.update)
      {
        player.sendMessage("An update is available: " + Main.name + ", a " + Main.type + " for " + Main.version + " available at " + Main.link);
        // Will look like - An update is available: AntiCheat v1.5.9, a release for CB 1.6.2-R0.1 available at http://media.curseforge.com/XYZ
        player.sendMessage("Type /update if you would like to automatically update.");
      }
    }
    
    // And then later in a CommandExecutor class, when they type /update:
    
    Updater updater = new Updater(this, YOUR_ID_HERE, this.getFile(), Updater.UpdateType.NO_VERSION_CHECK, true); // Go straight to downloading, and announce progress to console.
    

     
    Last edited: May 6, 2016
    FisheyLP, Nathat23, Eathuis and 36 others like this.
  2. Offline

    Shevchik

    You should really add a check that pwns out plugin if the updater package is not changed from default.
     
  3. Offline

    Gravity

    Why? Some people just shade in the class from Maven and don't need to change it.
     
  4. Offline

    Shevchik

    That ends up in class loading conflict if many plugins use the same package for this. Basic java class loading conflict. Only the latest loaded plugin will have the right classes definitions loaded. Other ones will receive those definitions and if some of them used different ones the plugin will fail to load properly.
     
  5. Offline

    TechAttax

    Keep getting this error. My key has been double checked, its fine!
    Code:
    [15:42:13] [Thread-11/ERROR]: [FastLeave] dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml
    [15:42:13] [Thread-11/ERROR]: [FastLeave] Please double-check your configuration to ensure it is correct.
    [15:42:13] [Thread-11/ERROR]: [FastLeave] null
    java.io.IOException: Server returned HTTP response code: 403 for URL: https://api.curseforge.com/servermods/files?projectIds=82248
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1626) ~[?:1.7.0_45]
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) ~[?:1.7.0_45]
        at net.gravitydevelopment.updater.Updater.read(Updater.java:547) [FastLeave.jar:?]
        at net.gravitydevelopment.updater.Updater.access$1(Updater.java:535) [FastLeave.jar:?]
        at net.gravitydevelopment.updater.Updater$UpdateRunnable.run(Updater.java:585) [FastLeave.jar:?]
        at java.lang.Thread.run(Thread.java:744) [?:1.7.0_45]
    
     
  6. Offline

    x0pk1n

    Hey! Just copying and pasting in the raw source code... Getting around 60 errors and 5 warnings; which out touching it... Anyone have any ideas how to fix it etc? Changed the package to the correct one and the clA has a capital U... So I don't know what's wrong...


    Attached file is a screen shot of the list of errors I get in eclipse.


    Okay sorted the problem. It was the Execution Environment I was using. I was using CDC-1.0, changed it to JavaSE-1.7, can anyone explain the different Execution Environment's? And why 1.7(7) is there when i'm using JDK 8?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     

    Attached Files:

    Last edited by a moderator: Jan 4, 2016
  7. Offline

    Squawkers13

    Just curious, is there a way to alter the shouldUpdate() method when using the Maven install?

    Could you possibly put 2.3 in the Maven repository? :|
    I need the UpdateCallback for the code I'm writing.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 4, 2016
  8. Offline

    _LB

    You extend the class with your own class and override it - it's how you're supposed to do it either way.
     
  9. Offline

    Gravity

    Yes! Sorry about that, there seemed to be an issue with my Jenkins system. Now that it's fixed, it's in the repo. Thanks for letting me know!
     
  10. Offline

    Dinosaurs

    Hello Gravity,
    Updater is an lovely extension to add to your plugin, however I am getting an few errors. When using the updater, at the beginning it gives me an error ... "The updater could not load configuration at pluginFolder\updater" and that the config.yml in the Updater folder is denied access.
    I am using Updater 2.2 with Bukkit 1.7.9. Is there any quickfix regarding this?
    Thanks for the resource!
    - Dinosaurs
     
  11. Offline

    sunny.zhang

    Gravity I got everything but the command line to update the plugin please help me. I put
    Code:java
    1. if(commandLabel.equalsIgnoreCase("update")){
    2. Updater Updater = new Updater((Plugin) this, 80827, this.getFile(), Updater.UpdateType.DEFAULT, false);
    3. }
    but getFile() is undefined and UpdateType cannot be resolved. They are in a seperate class.
     
  12. Offline

    Ultimate_n00b

    It looks like you're running this in a different class. You need to either:
    a) Run this in your main JavaPlugin class
    b) Get your plugin instance and file instance over to whatever class you're using.
     
    sunny.zhang likes this.
  13. Offline

    sunny.zhang

  14. Offline

    FiberSprite

    Hey man i was wondering how i would get getFile() working if i had my commands in a different class

    Code:java
    1. package me.FiberSprite.FiberCore.Commands;
    2.  
    3. import me.FiberSprite.FiberCore.FiberCore;
    4. import me.FiberSprite.FiberCore.Updater.Updater;
    5.  
    6. import com.not2excel.api.command.CommandHandler;
    7. import com.not2excel.api.command.CommandListener;
    8. import com.not2excel.api.command.objects.CommandInfo;
    9.  
    10. public class Command_Update implements CommandListener
    11. {
    12. static FiberCore plugin;
    13.  
    14. @CommandHandler(command = "test")
    15. public static void updateCommand(CommandInfo info)
    16. {
    17. Updater update = new Updater(plugin, plugin.ID, this.getFile(), Updater.UpdateType.DEFAULT, true);
    18. }
    19. }
    20.  
     
  15. Offline

    feildmaster

    http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
     
  16. Offline

    dart2112

    I have the latest version from github today, but when it downloads an update it downloads a really old update, not the newest, is there something i missed.
    Here is the code: Main Class
     
  17. Offline

    Squawkers13

    Just curious, how would I go about modifying this to download the file from Spigot?
     
  18. Offline

    Gravity

    This was designed for BukkitDev. Spigot does not, to my knowledge, have a similar API. I would suggest you ask on the forum relevant to that software, as this one has nothing to do with it.
     
  19. Offline

    AcpSoldier

    @Gravity
    Hey man. Amazing work you have done here with Updater. I'm setting up automatic updating for my plugin, and I was wondering if you could give me a bit of help. Every time I try to update, I get this message in the console: "File versions should follow the format 'PluginName vVERSION'". I've looked into the error, and I think I've done everything right. Just like the example of AntiCheat, my files follow the same version names.

    Why does it keep giving me this error? By any change do you what I've done wrong?
    Part of code that uses Updater: http://pastebin.com/9ynKehFR
     
  20. Offline

    mrCookieSlime

    @AcpSoldier
    You forgot to name your file. You added the version to Bukkit's file but it must be included in the name of the actual jar as well.
     
  21. Offline

    AcpSoldier

    @mrCookieSlime
    It looks like I made that post to quickly. It seems to be working, and I haven't changed anything since last night. I guess I just had to wait a couple of hours after I changed the version names. Also anti-cheats files have don't change the jar name, so I don't think that would have fixed it.
     
  22. Offline

    Gravity

    @AcpSoldier there's a slight delay in the curseforge API in updating your file feeds, I'm guessing you started out with a different versioning scheme, decided to use Updater, and then renamed all your files to follow the format? If that's right, there's just an hour or two difference in the API getting updated so if it works now you should be good to go from here on out.
    That is incorrect, files need not include a version number except in their plugin.yml.
     
  23. Offline

    ProZifro

    @Gravity When I start my server with the Plugin including the Updater.class, my console-output says: "File versions should follow the format 'PluginName vVERSION'. I setted the Updater up but I won't work. Please help me
     
  24. Offline

    Gravity

    Your files on BukkitDev need to follow the proper versioning scheme. Please follow the instructions in the OP.
     
  25. Offline

    ProZifro

  26. @Gravity Hey, when I copy the class into Eclipse I get a couple of errors. I've tried everything to fix this. Here are the errors:

    Error 1:
    Code:
    final JSONArray array = (JSONArray) JSONValue.parse(response); // I get an error on JSONArray and JSONValue
    Error 2:
    Code:
    JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1); // I get an error on JSONObject.
    Both of the errors say JSONObject, JSONArray or JSONValue "cannot be resolved as a type"
    I understand that this is more and likely my problem I was just wondering if you could help. Thanks! :)

    EDIT: Nevermind! I fixed it :p If anyone else is having the issue try downloading SimpleJSON :p

    EDIT by Timtower: merged posts
     
    Last edited by a moderator: Feb 7, 2015
  27. Offline

    Gravity

    With regards to the post by @MrBlackIsBack

    Updater is a Maven3 project and lists Bukkit as a necessary dependency for compilation. If you are not including the file in a project which is using Bukkit, you will need to manually add the library for SimpleJSON. I'm not really sure why you would be doing this because Bukkit's YAML API is also a necessary aspect of the class file, but FYI.
     
  28. Offline

    mttprvst13

    I have a problem when I start my local server using this, here is the output:

    Code:
    [07:44:25 INFO]: [mttsFly] Enabling mttsFly v1.5
    [07:44:26 WARN]: Exception in thread "Thread-24"
    [07:44:26 WARN]: java.lang.NullPointerException
    [07:44:26 WARN]:     at me.mttprvst13.Updater.versionCheck(Updater.java:558)
    [07:44:26 WARN]:     at me.mttprvst13.Updater.runUpdater(Updater.java:718)
    [07:44:26 WARN]:     at me.mttprvst13.Updater.access$0(Updater.java:717)
    [07:44:26 WARN]:     at me.mttprvst13.Updater$UpdateRunnable.run(Updater.java:713)
    [07:44:26 WARN]:     at java.lang.Thread.run(Thread.java:745)
    [07:44:26 INFO]: [mttsFly] [mtt's Fly] has been enabled.
    
    Here is my code:

    Code:
        protected Logger log;
        public boolean retur = true;
    
        @SuppressWarnings("static-access")
        @Override
        public void onEnable() {
            this.log = this.getLogger();
           
            Updater updater = new Updater(this, 88761, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false);
           
            Updater.UpdateResult result = updater.getResult();
            if (updater.getResult() == result.UPDATE_AVAILABLE) {
                this.log.info("New version available! " + updater.getLatestName());
                this.log.info("Here is a direct link to it: " + updater.getLatestFileLink() );
            }
            getLogger().info("[mtt's Fly] has been enabled.");
        }
    I recopied the updater file and now I'm getting this:
    Code:
    [08:01:10 INFO]: [mttsFly] Enabling mttsFly v1.5
    [08:01:13 WARN]: [mttsFly] The author of this plugin (mttprvst13) has misconfigured their Auto Update system
    [08:01:13 WARN]: [mttsFly] File versions should follow the format 'PluginName vVERSION'
    [08:01:13 WARN]: [mttsFly] Please notify the author of this error.
    [08:01:13 INFO]: [mttsFly] Enabled.
    <Edit by mrCookieSlime: Merged posts. Please don't double post. There is an Edit Button right next to the Date.>
     
    Last edited by a moderator: Mar 1, 2015
  29. Offline

    Lolmewn

  30. Offline

    mttprvst13

    Never mind, my versions were changed, and that fixed it.
     
Thread Status:
Not open for further replies.

Share This Page