Advertisement
claxon007

Untitled

Apr 24th, 2019
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 31.29 KB | None | 0 0
  1.  
  2.     /* Constants */
  3.  
  4.     // Remote file's title
  5.     private static final String TITLE_VALUE = "name";
  6.     // Remote file's download link
  7.     private static final String LINK_VALUE = "downloadUrl";
  8.     // Remote file's release type
  9.     private static final String TYPE_VALUE = "releaseType";
  10.     // Remote file's build version
  11.     private static final String VERSION_VALUE = "gameVersion";
  12.     // Path to GET
  13.     private static final String QUERY = "/servermods/files?projectIds=";
  14.     // Slugs will be appended to this to get to the project's RSS feed
  15.     private static final String HOST = "https://api.curseforge.com";
  16.     // User-agent when querying Curse
  17.     private static final String USER_AGENT = "Updater (by Gravity)";
  18.     // Used for locating version numbers in file names
  19.     private static final String DELIMETER = "^v|[\\s_-]V";
  20.     // If the version number contains one of these, don't update.
  21.     private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" };
  22.     // Used for downloading files
  23.     private static final int BYTE_SIZE = 1024;
  24.     // Config key for api key
  25.     private static final String API_KEY_CONFIG_KEY = "api-key";
  26.     // Config key for disabling Updater
  27.     private static final String DISABLE_CONFIG_KEY = "disable";
  28.     // Default api key value in config
  29.     private static final String API_KEY_DEFAULT = "PUT_API_KEY_HERE";
  30.     // Default disable value in config
  31.     private static final boolean DISABLE_DEFAULT = false;
  32.  
  33.     /* User-provided variables */
  34.  
  35.     // Plugin running Updater
  36.     private final Plugin plugin;
  37.     // Type of update check to run
  38.     private final UpdateType type;
  39.     // Whether to announce file downloads
  40.     private final boolean announce;
  41.     // The plugin file (jar)
  42.     private final File file;
  43.     // The folder that downloads will be placed in
  44.     private final File updateFolder;
  45.     // The provided callback (if any)
  46.     private final UpdateCallback callback;
  47.     // Project's Curse ID
  48.     private int id = -1;
  49.     // BukkitDev ServerMods API key
  50.     private String apiKey = null;
  51.  
  52.     /* Collected from Curse API */
  53.  
  54.     private String versionName;
  55.     private String versionLink;
  56.     private String versionType;
  57.     private String versionGameVersion;
  58.  
  59.     /* Update process variables */
  60.  
  61.     // Connection to RSS
  62.     private URL url;
  63.     // Updater thread
  64.     private Thread thread;
  65.     // Used for determining the outcome of the update process
  66.     private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS;
  67.  
  68.     /**
  69.      * Gives the developer the result of the update process. Can be obtained by called {@link #getResult()}
  70.      */
  71.     public enum UpdateResult {
  72.         /**
  73.          * The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
  74.          */
  75.         SUCCESS,
  76.         /**
  77.          * The updater did not find an update, and nothing was downloaded.
  78.          */
  79.         NO_UPDATE,
  80.         /**
  81.          * The server administrator has disabled the updating system.
  82.          */
  83.         DISABLED,
  84.         /**
  85.          * The updater found an update, but was unable to download it.
  86.          */
  87.         FAIL_DOWNLOAD,
  88.         /**
  89.          * For some reason, the updater was unable to contact dev.bukkit.org to download the file.
  90.          */
  91.         FAIL_DBO,
  92.         /**
  93.          * When running the version check, the file on DBO did not contain a recognizable version.
  94.          */
  95.         FAIL_NOVERSION,
  96.         /**
  97.          * The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
  98.          */
  99.         FAIL_BADID,
  100.         /**
  101.          * The server administrator has improperly configured their API key in the configuration.
  102.          */
  103.         FAIL_APIKEY,
  104.         /**
  105.          * The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
  106.          */
  107.         UPDATE_AVAILABLE
  108.     }
  109.  
  110.     /**
  111.      * Allows the developer to specify the type of update that will be run.
  112.      */
  113.     public enum UpdateType {
  114.         /**
  115.          * Run a version check, and then if the file is out of date, download the newest version.
  116.          */
  117.         DEFAULT,
  118.         /**
  119.          * Don't run a version check, just find the latest update and download it.
  120.          */
  121.         NO_VERSION_CHECK,
  122.         /**
  123.          * Get information about the version and the download size, but don't actually download anything.
  124.          */
  125.         NO_DOWNLOAD
  126.     }
  127.  
  128.     /**
  129.      * Represents the various release types of a file on BukkitDev.
  130.      */
  131.     public enum ReleaseType {
  132.         /**
  133.          * An "alpha" file.
  134.          */
  135.         ALPHA,
  136.         /**
  137.          * A "beta" file.
  138.          */
  139.         BETA,
  140.         /**
  141.          * A "release" file.
  142.          */
  143.         RELEASE
  144.     }
  145.  
  146.     /**
  147.      * Initialize the updater.
  148.      *
  149.      * @param plugin - ASkyBlock plugin object   The plugin that is checking for an update.
  150.      * @param id       The dev.bukkit.org id of the project.
  151.      * @param file     The file that the plugin is running from, get this by doing this.getFile() from within your main class.
  152.      * @param type     Specify the type of update this will be. See {@link UpdateType}
  153.      * @param announce True if the program should announce the progress of new updates in console.
  154.      */
  155.     public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) {
  156.         this(plugin, id, file, type, null, announce);
  157.     }
  158.  
  159.     /**
  160.      * Initialize the updater with the provided callback.
  161.      *
  162.      * @param plugin - ASkyBlock plugin object   The plugin that is checking for an update.
  163.      * @param id       The dev.bukkit.org id of the project.
  164.      * @param file     The file that the plugin is running from, get this by doing this.getFile() from within your main class.
  165.      * @param type     Specify the type of update this will be. See {@link UpdateType}
  166.      * @param callback The callback instance to notify when the Updater has finished
  167.      */
  168.     public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback) {
  169.         this(plugin, id, file, type, callback, false);
  170.     }
  171.  
  172.     /**
  173.      * Initialize the updater with the provided callback.
  174.      *
  175.      * @param plugin - ASkyBlock plugin object   The plugin that is checking for an update.
  176.      * @param id       The dev.bukkit.org id of the project.
  177.      * @param file     The file that the plugin is running from, get this by doing this.getFile() from within your main class.
  178.      * @param type     Specify the type of update this will be. See {@link UpdateType}
  179.      * @param callback The callback instance to notify when the Updater has finished
  180.      * @param announce True if the program should announce the progress of new updates in console.
  181.      */
  182.     public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback, boolean announce) {
  183.         this.plugin = plugin;
  184.         this.type = type;
  185.         this.announce = announce;
  186.         this.file = file;
  187.         this.id = id;
  188.         this.updateFolder = this.plugin.getServer().getUpdateFolderFile();
  189.         this.callback = callback;
  190.  
  191.         final File pluginFile = this.plugin.getDataFolder().getParentFile();
  192.         final File updaterFile = new File(pluginFile, "Updater");
  193.         final File updaterConfigFile = new File(updaterFile, "config.yml");
  194.  
  195.         YamlConfiguration config = new YamlConfiguration();
  196.         config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n'
  197.                 + "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n'
  198.                 + "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration.");
  199.         config.addDefault(API_KEY_CONFIG_KEY, API_KEY_DEFAULT);
  200.         config.addDefault(DISABLE_CONFIG_KEY, DISABLE_DEFAULT);
  201.  
  202.         if (!updaterFile.exists()) {
  203.             this.fileIOOrError(updaterFile, updaterFile.mkdir(), true);
  204.         }
  205.  
  206.         boolean createFile = !updaterConfigFile.exists();
  207.         try {
  208.             if (createFile) {
  209.                 this.fileIOOrError(updaterConfigFile, updaterConfigFile.createNewFile(), true);
  210.                 config.options().copyDefaults(true);
  211.                 config.save(updaterConfigFile);
  212.             } else {
  213.                 config.load(updaterConfigFile);
  214.             }
  215.         } catch (final Exception e) {
  216.             final String message;
  217.             if (createFile) {
  218.                 message = "The updater could not create configuration at " + updaterFile.getAbsolutePath();
  219.             } else {
  220.                 message = "The updater could not load configuration at " + updaterFile.getAbsolutePath();
  221.             }
  222.             this.plugin.getLogger().log(Level.SEVERE, message, e);
  223.         }
  224.  
  225.         if (config.getBoolean(DISABLE_CONFIG_KEY)) {
  226.             this.result = UpdateResult.DISABLED;
  227.             return;
  228.         }
  229.  
  230.         String key = config.getString(API_KEY_CONFIG_KEY);
  231.         if (API_KEY_DEFAULT.equalsIgnoreCase(key) || "".equals(key)) {
  232.             key = null;
  233.         }
  234.  
  235.         this.apiKey = key;
  236.  
  237.         try {
  238.             this.url = new URL(Updater.HOST + Updater.QUERY + this.id);
  239.         } catch (final MalformedURLException e) {
  240.             this.plugin.getLogger().log(Level.SEVERE, "The project ID provided for updating, " + this.id + " is invalid.", e);
  241.             this.result = UpdateResult.FAIL_BADID;
  242.         }
  243.  
  244.         if (this.result != UpdateResult.FAIL_BADID) {
  245.             this.thread = new Thread(new UpdateRunnable());
  246.             this.thread.start();
  247.         } else {
  248.             runUpdater();
  249.         }
  250.     }
  251.  
  252.     /**
  253.      * Get the result of the update process.
  254.      *
  255.      * @return result of the update process.
  256.      * @see UpdateResult
  257.      */
  258.     public Updater.UpdateResult getResult() {
  259.         this.waitForThread();
  260.         return this.result;
  261.     }
  262.  
  263.     /**
  264.      * Get the latest version's release type.
  265.      *
  266.      * @return latest version's release type.
  267.      * @see ReleaseType
  268.      */
  269.     public ReleaseType getLatestType() {
  270.         this.waitForThread();
  271.         if (this.versionType != null) {
  272.             for (ReleaseType type : ReleaseType.values()) {
  273.                 if (this.versionType.equalsIgnoreCase(type.name())) {
  274.                     return type;
  275.                 }
  276.             }
  277.         }
  278.         return null;
  279.     }
  280.  
  281.     /**
  282.      * Get the latest version's game version (such as "CB 1.2.5-R1.0").
  283.      *
  284.      * @return latest version's game version.
  285.      */
  286.     public String getLatestGameVersion() {
  287.         this.waitForThread();
  288.         return this.versionGameVersion;
  289.     }
  290.  
  291.     /**
  292.      * Get the latest version's name (such as "Project v1.0").
  293.      *
  294.      * @return latest version's name.
  295.      */
  296.     public String getLatestName() {
  297.         this.waitForThread();
  298.         return this.versionName;
  299.     }
  300.  
  301.     /**
  302.      * Get the latest version's direct file link.
  303.      *
  304.      * @return latest version's file link.
  305.      */
  306.     public String getLatestFileLink() {
  307.         this.waitForThread();
  308.         return this.versionLink;
  309.     }
  310.  
  311.     /**
  312.      * As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
  313.      * before allowing anyone to check the result.
  314.      */
  315.     private void waitForThread() {
  316.         if ((this.thread != null) && this.thread.isAlive()) {
  317.             try {
  318.                 this.thread.join();
  319.             } catch (final InterruptedException e) {
  320.                 this.plugin.getLogger().log(Level.SEVERE, null, e);
  321.                 // Restore interrupted state...
  322.                 Thread.currentThread().interrupt();
  323.             }
  324.         }
  325.     }
  326.  
  327.     /**
  328.      * Save an update from dev.bukkit.org into the server's update folder.
  329.      *
  330.      * @param file the name of the file to save it as.
  331.      */
  332.     private void saveFile(String file) {
  333.         final File folder = this.updateFolder;
  334.  
  335.         deleteOldFiles();
  336.         if (!folder.exists()) {
  337.             this.fileIOOrError(folder, folder.mkdir(), true);
  338.         }
  339.         downloadFile();
  340.  
  341.         // Check to see if it's a zip file, if it is, unzip it.
  342.         final File dFile = new File(folder.getAbsolutePath(), file);
  343.         if (dFile.getName().endsWith(".zip")) {
  344.             // Unzip
  345.             this.unzip(dFile.getAbsolutePath());
  346.         }
  347.         if (this.announce) {
  348.             this.plugin.getLogger().info("Finished updating.");
  349.         }
  350.     }
  351.  
  352.     /**
  353.      * Download a file and save it to the specified folder.
  354.      */
  355.     private void downloadFile() {
  356.         BufferedInputStream in = null;
  357.         FileOutputStream fout = null;
  358.         try {
  359.             URL fileUrl = followRedirects(this.versionLink);
  360.             final int fileLength = fileUrl.openConnection().getContentLength();
  361.             in = new BufferedInputStream(fileUrl.openStream());
  362.             fout = new FileOutputStream(new File(this.updateFolder, file.getName()));
  363.  
  364.             final byte[] data = new byte[Updater.BYTE_SIZE];
  365.             int count;
  366.             if (this.announce) {
  367.                 this.plugin.getLogger().info("About to download a new update: " + this.versionName);
  368.             }
  369.             long downloaded = 0;
  370.             while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) {
  371.                 downloaded += count;
  372.                 fout.write(data, 0, count);
  373.                 final int percent = (int) ((downloaded * 100) / fileLength);
  374.                 if (this.announce && ((percent % 10) == 0)) {
  375.                     this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
  376.                 }
  377.             }
  378.         } catch (Exception ex) {
  379.             this.plugin.getLogger().log(Level.WARNING, "The auto-updater tried to download a new update, but was unsuccessful.", ex);
  380.             this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
  381.         } finally {
  382.             try {
  383.                 if (in != null) {
  384.                     in.close();
  385.                 }
  386.             } catch (final IOException ex) {
  387.                 this.plugin.getLogger().log(Level.SEVERE, null, ex);
  388.             }
  389.             try {
  390.                 if (fout != null) {
  391.                     fout.close();
  392.                 }
  393.             } catch (final IOException ex) {
  394.                 this.plugin.getLogger().log(Level.SEVERE, null, ex);
  395.             }
  396.         }
  397.     }
  398.  
  399.     private URL followRedirects(String location) throws IOException {
  400.         URL resourceUrl, base, next;
  401.         HttpURLConnection conn;
  402.         String redLoc;
  403.         while (true) {
  404.             resourceUrl = new URL(location);
  405.             conn = (HttpURLConnection) resourceUrl.openConnection();
  406.  
  407.             conn.setConnectTimeout(15000);
  408.             conn.setReadTimeout(15000);
  409.             conn.setInstanceFollowRedirects(false);
  410.             conn.setRequestProperty("User-Agent", "Mozilla/5.0...");
  411.  
  412.             switch (conn.getResponseCode()) {
  413.             case HttpURLConnection.HTTP_MOVED_PERM:
  414.             case HttpURLConnection.HTTP_MOVED_TEMP:
  415.                 redLoc = conn.getHeaderField("Location");
  416.                 base = new URL(location);
  417.                 next = new URL(base, redLoc);  // Deal with relative URLs
  418.                 location = next.toExternalForm();
  419.                 continue;
  420.             }
  421.             break;
  422.         }
  423.         return conn.getURL();
  424.     }
  425.  
  426.     /**
  427.      * Remove possibly leftover files from the update folder.
  428.      */
  429.     private void deleteOldFiles() {
  430.         //Just a quick check to make sure we didn't leave any files from last time...
  431.         File[] list = listFilesOrError(this.updateFolder);
  432.         for (final File xFile : list) {
  433.             if (xFile.getName().endsWith(".zip")) {
  434.                 this.fileIOOrError(xFile, xFile.mkdir(), true);
  435.             }
  436.         }
  437.     }
  438.  
  439.     /**
  440.      * Part of Zip-File-Extractor, modified by Gravity for use with Updater.
  441.      *
  442.      * @param file the location of the file to extract.
  443.      */
  444.     private void unzip(String file) {
  445.         final File fSourceZip = new File(file);
  446.         try {
  447.             final String zipPath = file.substring(0, file.length() - 4);
  448.             try (ZipFile zipFile = new ZipFile(fSourceZip)) {
  449.                 Enumeration<? extends ZipEntry> e = zipFile.entries();
  450.                 while (e.hasMoreElements()) {
  451.                     ZipEntry entry = e.nextElement();
  452.                     File destinationFilePath = new File(zipPath, entry.getName());
  453.                     this.fileIOOrError(destinationFilePath.getParentFile(), destinationFilePath.getParentFile().mkdirs(), true);
  454.                     if (!entry.isDirectory()) {
  455.                         final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
  456.                         int b;
  457.                         final byte[] buffer = new byte[Updater.BYTE_SIZE];
  458.                         try (final FileOutputStream fos = new FileOutputStream(destinationFilePath)) {
  459.                             try (final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE)) {
  460.                                 while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) {
  461.                                     bos.write(buffer, 0, b);
  462.                                 }
  463.                             }
  464.                         }
  465.                         bis.close();
  466.                         final String name = destinationFilePath.getName();
  467.                         if (name.endsWith(".jar") && this.pluginExists(name)) {
  468.                             File output = new File(this.updateFolder, name);
  469.                             this.fileIOOrError(output, destinationFilePath.renameTo(output), true);
  470.                         }
  471.                     }
  472.                 }
  473.             }
  474.  
  475.             // Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
  476.             moveNewZipFiles(zipPath);
  477.  
  478.         } catch (final IOException e) {
  479.             this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e);
  480.             this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
  481.         } finally {
  482.             this.fileIOOrError(fSourceZip, fSourceZip.delete(), false);
  483.         }
  484.     }
  485.  
  486.     /**
  487.      * Find any new files extracted from an update into the plugin's data directory.
  488.      * @param zipPath path of extracted files.
  489.      */
  490.     private void moveNewZipFiles(String zipPath) {
  491.         File[] list = listFilesOrError(new File(zipPath));
  492.         for (final File dFile : list) {
  493.             if (dFile.isDirectory() && this.pluginExists(dFile.getName())) {
  494.                 // Current dir
  495.                 final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName());
  496.                 // List of existing files in the new dir
  497.                 final File[] dList = listFilesOrError(dFile);
  498.                 // List of existing files in the current dir
  499.                 final File[] oList = listFilesOrError(oFile);
  500.                 for (File cFile : dList) {
  501.                     // Loop through all the files in the new dir
  502.                     boolean found = false;
  503.                     for (final File xFile : oList) {
  504.                         // Loop through all the contents in the current dir to see if it exists
  505.                         if (xFile.getName().equals(cFile.getName())) {
  506.                             found = true;
  507.                             break;
  508.                         }
  509.                     }
  510.                     if (!found) {
  511.                         // Move the new file into the current dir
  512.                         File output = new File(oFile, cFile.getName());
  513.                         this.fileIOOrError(output, cFile.renameTo(output), true);
  514.                     } else {
  515.                         // This file already exists, so we don't need it anymore.
  516.                         this.fileIOOrError(cFile, cFile.delete(), false);
  517.                     }
  518.                 }
  519.             }
  520.             this.fileIOOrError(dFile, dFile.delete(), false);
  521.         }
  522.         File zip = new File(zipPath);
  523.         this.fileIOOrError(zip, zip.delete(), false);
  524.     }
  525.  
  526.     /**
  527.      * Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip.
  528.      *
  529.      * @param name a name to check for inside the plugins folder.
  530.      * @return true if a file inside the plugins folder is named this.
  531.      */
  532.     private boolean pluginExists(String name) {
  533.         File[] plugins = listFilesOrError(new File("plugins"));
  534.         for (final File file : plugins) {
  535.             if (file.getName().equals(name)) {
  536.                 return true;
  537.             }
  538.         }
  539.         return false;
  540.     }
  541.  
  542.     /**
  543.      * Check to see if the program should continue by evaluating whether the plugin is already updated, or shouldn't be updated.
  544.      *
  545.      * @return true if the version was located and is not the same as the remote's newest.
  546.      */
  547.     private boolean versionCheck() {
  548.         final String title = this.versionName;
  549.         if (this.type != UpdateType.NO_VERSION_CHECK) {
  550.             final String localVersion = this.plugin.getDescription().getVersion();
  551.             if (title.split(DELIMETER).length >= 2) {
  552.                 // Get the newest file's version number
  553.                 final String remoteVersion = title.split(DELIMETER)[title.split(DELIMETER).length - 1].split(" ")[0];
  554.  
  555.                 if (this.hasTag(localVersion) || !this.shouldUpdate(localVersion, remoteVersion)) {
  556.                     // We already have the latest version, or this build is tagged for no-update
  557.                     this.result = Updater.UpdateResult.NO_UPDATE;
  558.                     return false;
  559.                 }
  560.             } else {
  561.                 // The file's name did not contain the string 'vVersion'
  562.                 final String authorInfo = this.plugin.getDescription().getAuthors().isEmpty() ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")";
  563.                 this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system");
  564.                 this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
  565.                 this.plugin.getLogger().warning("Please notify the author of this error.");
  566.                 this.result = Updater.UpdateResult.FAIL_NOVERSION;
  567.                 return false;
  568.             }
  569.         }
  570.         return true;
  571.     }
  572.  
  573.     /**
  574.      * <b>If you wish to run mathematical versioning checks, edit this method.</b>
  575.      * <p>
  576.      * With default behavior, Updater will NOT verify that a remote version available on BukkitDev
  577.      * which is not this version is indeed an "update".
  578.      * If a version is present on BukkitDev that is not the version that is currently running,
  579.      * Updater will assume that it is a newer version.
  580.      * This is because there is no standard versioning scheme, and creating a calculation that can
  581.      * determine whether a new update is actually an update is sometimes extremely complicated.
  582.      * </p>
  583.      * <p>
  584.      * Updater will call this method from {@link #versionCheck()} before deciding whether
  585.      * the remote version is actually an update.
  586.      * If you have a specific versioning scheme with which a mathematical determination can
  587.      * be reliably made to decide whether one version is higher than another, you may
  588.      * revise this method, using the local and remote version parameters, to execute the
  589.      * appropriate check.
  590.      * </p>
  591.      * <p>
  592.      * Returning a value of <b>false</b> will tell the update process that this is NOT a new version.
  593.      * Without revision, this method will always consider a remote version at all different from
  594.      * that of the local version a new update.
  595.      * </p>
  596.      * @param localVersion the current version
  597.      * @param remoteVersion the remote version
  598.      * @return true if Updater should consider the remote version an update, false if not.
  599.      */
  600.     public boolean shouldUpdate(String localVersion, String remoteVersion) {
  601.         //plugin.getLogger().info("DEBUG: localVersion = " + localVersion + " remoteVersion = " + remoteVersion);
  602.         // Check to see if the latest file is newer that this one
  603.         // Need to escape the period in the regex expression
  604.         String[] updateVer = remoteVersion.split("\\.");
  605.         //plugin.getLogger().info("DEBUG: split length = " + updateVer.length);
  606.         // Check the version #'s
  607.         String[] pluginVer = localVersion.split("\\.");
  608.         //getLogger().info("DEBUG: split length = " + pluginVer.length);
  609.         // Run through major, minor, sub
  610.         for (int i = 0; i < Math.max(updateVer.length, pluginVer.length); i++) {
  611.             try {
  612.                 int updateCheck = 0;
  613.                 if (i < updateVer.length) {
  614.                     updateCheck = Integer.valueOf(updateVer[i]);
  615.                 }
  616.                 int pluginCheck = 0;
  617.                 if (i < pluginVer.length) {
  618.                     pluginCheck = Integer.valueOf(pluginVer[i]);
  619.                 }
  620.                 //plugin.getLogger().info("DEBUG: update is " + updateCheck + " plugin is " + pluginCheck);
  621.                 if (updateCheck < pluginCheck) {
  622.                     //plugin.getLogger().info("DEBUG: plugin is newer!");
  623.                     //plugin is newer
  624.                     return false;
  625.                 } else if (updateCheck > pluginCheck) {
  626.                     //plugin.getLogger().info("DEBUG: update is newer!");
  627.                     return true;
  628.                 }
  629.             } catch (Exception e) {
  630.                 plugin.getLogger().warning("Could not determine update's version # ");
  631.                 plugin.getLogger().warning("Plugin version: "+ localVersion);
  632.                 plugin.getLogger().warning("Update version: " + remoteVersion);
  633.             }
  634.         }
  635.         return false;
  636.     }
  637.  
  638.     /**
  639.      * Evaluate whether the version number is marked showing that it should not be updated by this program.
  640.      *
  641.      * @param version a version number to check for tags in.
  642.      * @return true if updating should be disabled.
  643.      */
  644.     private boolean hasTag(String version) {
  645.         for (final String string : Updater.NO_UPDATE_TAG) {
  646.             if (version.contains(string)) {
  647.                 return true;
  648.             }
  649.         }
  650.         return false;
  651.     }
  652.  
  653.     /**
  654.      * Make a connection to the BukkitDev API and request the newest file's details.
  655.      *
  656.      * @return true if successful.
  657.      */
  658.     private boolean read() {
  659.         try {
  660.             final URLConnection conn = this.url.openConnection();
  661.             conn.setConnectTimeout(5000);
  662.  
  663.             if (this.apiKey != null) {
  664.                 conn.addRequestProperty("X-API-Key", this.apiKey);
  665.             }
  666.             conn.addRequestProperty("User-Agent", Updater.USER_AGENT);
  667.  
  668.             conn.setDoOutput(true);
  669.  
  670.             final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
  671.             final String response = reader.readLine();
  672.  
  673.             final JSONArray array = (JSONArray) JSONValue.parse(response);
  674.  
  675.             if (array.isEmpty()) {
  676.                 this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id);
  677.                 this.result = UpdateResult.FAIL_BADID;
  678.                 return false;
  679.             }
  680.  
  681.             JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1);
  682.             this.versionName = (String) latestUpdate.get(Updater.TITLE_VALUE);
  683.             this.versionLink = (String) latestUpdate.get(Updater.LINK_VALUE);
  684.             this.versionType = (String) latestUpdate.get(Updater.TYPE_VALUE);
  685.             this.versionGameVersion = (String) latestUpdate.get(Updater.VERSION_VALUE);
  686.  
  687.             return true;
  688.         } catch (final IOException e) {
  689.             if (e.getMessage().contains("HTTP response code: 403")) {
  690.                 this.plugin.getLogger().severe("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml");
  691.                 this.plugin.getLogger().severe("Please double-check your configuration to ensure it is correct.");
  692.                 this.result = UpdateResult.FAIL_APIKEY;
  693.             } else {
  694.                 this.plugin.getLogger().severe("The updater could not contact dev.bukkit.org for updating.");
  695.                 this.plugin.getLogger().severe("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
  696.                 this.result = UpdateResult.FAIL_DBO;
  697.             }
  698.             this.plugin.getLogger().log(Level.SEVERE, null, e);
  699.             return false;
  700.         }
  701.     }
  702.  
  703.     /**
  704.      * Perform a file operation and log any errors if it fails.
  705.      * @param file file operation is performed on.
  706.      * @param result result of file operation.
  707.      * @param create true if a file is being created, false if deleted.
  708.      */
  709.     private void fileIOOrError(File file, boolean result, boolean create) {
  710.         if (!result) {
  711.             this.plugin.getLogger().severe("The updater could not " + (create ? "create" : "delete") + " file at: " + file.getAbsolutePath());
  712.         }
  713.     }
  714.  
  715.     private File[] listFilesOrError(File folder) {
  716.         File[] contents = folder.listFiles();
  717.         if (contents == null) {
  718.             this.plugin.getLogger().severe("The updater could not access files at: " + this.updateFolder.getAbsolutePath());
  719.             return new File[0];
  720.         } else {
  721.             return contents;
  722.         }
  723.     }
  724.  
  725.     /**
  726.      * Called on main thread when the Updater has finished working, regardless
  727.      * of result.
  728.      */
  729.     public interface UpdateCallback {
  730.         /**
  731.          * Called when the updater has finished working.
  732.          * @param updater The updater instance
  733.          */
  734.         void onFinish(Updater updater);
  735.     }
  736.  
  737.     private class UpdateRunnable implements Runnable {
  738.         @Override
  739.         public void run() {
  740.             runUpdater();
  741.         }
  742.     }
  743.  
  744.     private void runUpdater() {
  745.         if (this.url != null && (this.read() && this.versionCheck())) {
  746.             // Obtain the results of the project's file feed
  747.             if ((this.versionLink != null) && (this.type != UpdateType.NO_DOWNLOAD)) {
  748.                 String name = this.file.getName();
  749.                 // If it's a zip file, it shouldn't be downloaded as the plugin's name
  750.                 if (this.versionLink.endsWith(".zip")) {
  751.                     name = this.versionLink.substring(this.versionLink.lastIndexOf("/") + 1);
  752.                 }
  753.                 this.saveFile(name);
  754.             } else {
  755.                 this.result = UpdateResult.UPDATE_AVAILABLE;
  756.             }
  757.         }
  758.  
  759.         if (this.callback != null) {
  760.             new BukkitRunnable() {
  761.                 @Override
  762.                 public void run() {
  763.                     runCallback();
  764.                 }
  765.             }.runTask(this.plugin);
  766.         }
  767.     }
  768.  
  769.     private void runCallback() {
  770.         this.callback.onFinish(this);
  771.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement