Make the update class easier to work with.

This commit is contained in:
Kristian S. Stangeland 2012-11-02 18:55:23 +01:00
parent 4328072f49
commit 3d0dce7e8d

View File

@ -12,12 +12,17 @@ import java.net.URLConnection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import org.bukkit.Server;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -38,21 +43,33 @@ import org.bukkit.plugin.Plugin;
*/ */
public class Updater public class Updater
{ {
// If the version number contains one of these, don't update.
private static final String[] noUpdateTag = {"-DEV", "-PRE", "-SNAPSHOT"};
// Slugs will be appended to this to get to the project's RSS feed
private static final String DBOUrl = "http://dev.bukkit.org/server-mods/";
private static final int BYTE_SIZE = 1024; // Used for downloading files
private Plugin plugin; private Plugin plugin;
private UpdateType type; private UpdateType type;
private String downloadedVersion;
private String versionTitle; private String versionTitle;
private String versionLink; private String versionLink;
private long totalSize; // Holds the total size of the file private long totalSize; // Holds the total size of the file
//private double downloadedSize; TODO: Holds the number of bytes downloaded
private int sizeLine; // Used for detecting file size private int sizeLine; // Used for detecting file size
private int multiplier; // Used for determining when to broadcast download updates private int multiplier; // Used for determining when to broadcast download updates
private boolean announce; // Whether to announce file downloads private boolean announce; // Whether to announce file downloads
private URL url; // Connecting to RSS private URL url; // Connecting to RSS
private static final String DBOUrl = "http://dev.bukkit.org/server-mods/"; // Slugs will be appended to this to get to the project's RSS feed
private String [] noUpdateTag = {"-DEV","-PRE"}; // If the version number contains one of these, don't update.
private static final int BYTE_SIZE = 1024; // Used for downloading files
private String updateFolder = YamlConfiguration.loadConfiguration(new File("bukkit.yml")).getString("settings.update-folder"); // The folder that downloads will be placed in private String updateFolder = YamlConfiguration.loadConfiguration(new File("bukkit.yml")).getString("settings.update-folder"); // The folder that downloads will be placed in
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; // Used for determining the outcome of the update process
// Used for determining the outcome of the update process
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS;
private String slug;
private File file;
// Used to announce progress
private Logger logger;
// Strings for reading RSS // Strings for reading RSS
private static final String TITLE = "title"; private static final String TITLE = "title";
@ -174,34 +191,79 @@ public class Updater
* The dev.bukkit.org slug of the project (http://dev.bukkit.org/server-mods/SLUG_IS_HERE) * The dev.bukkit.org slug of the project (http://dev.bukkit.org/server-mods/SLUG_IS_HERE)
* @param file * @param file
* The file that the plugin is running from, get this by doing this.getFile() from within your main class. * The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param permission
* Permission needed to read the output of the update process.
*/
public Updater(Plugin plugin, String slug, File file, String permission)
{
this.plugin = plugin;
this.file = file;
this.slug = slug;
// Prevent issues with older versions of Bukkit
try {
logger = plugin.getLogger();
logger.getLevel();
} catch (Throwable e) {
logger = Logger.getLogger("Minecraft");
}
broadcastUsers(plugin.getServer(), permission);
}
private void broadcastUsers(final Server server, final String permission) {
// Broadcast information to every user too
logger.addHandler(new Handler() {
@Override
public void publish(LogRecord record) {
server.broadcast(record.getMessage(), permission);
}
@Override
public void flush() {
// Not needed.
}
@Override
public void close() throws SecurityException {
// Do nothing.
}
});
}
/**
* Update the plugin.
*
* @param type * @param type
* Specify the type of update this will be. See {@link UpdateType} * Specify the type of update this will be. See {@link UpdateType}
* @param announce * @param announce
* True if the program should announce the progress of new updates in console * True if the program should announce the progress of new updates in console
* @return The result of the update process.
*/ */
public Updater(Plugin plugin, String slug, File file, UpdateType type, boolean announce) public UpdateResult update(UpdateType type, boolean announce)
{ {
this.plugin = plugin; this.type = type;
this.type = type; this.announce = announce;
this.announce = announce;
try try
{ {
// Obtain the results of the project's file feed // Obtain the results of the project's file feed
url = null;
url = new URL(DBOUrl + slug + "/files.rss"); url = new URL(DBOUrl + slug + "/files.rss");
} }
catch (MalformedURLException ex) catch (MalformedURLException ex)
{ {
// The slug doesn't exist // The slug doesn't exist
plugin.getLogger().warning("The author of this plugin has misconfigured their Auto Update system"); logger.warning("The author of this plugin has misconfigured their Auto Update system");
plugin.getLogger().warning("The project slug added ('" + slug + "') is invalid, and does not exist on dev.bukkit.org"); logger.warning("The project slug added ('" + slug + "') is invalid, and does not exist on dev.bukkit.org");
result = Updater.UpdateResult.FAIL_BADSLUG; // Bad slug! Bad! result = Updater.UpdateResult.FAIL_BADSLUG; // Bad slug! Bad!
} }
if(url != null) if (url != null)
{ {
// Obtain the results of the project's file feed // Obtain the results of the project's file feed
readFeed(); readFeed();
if(versionCheck(versionTitle)) if(versionCheck(versionTitle))
{ {
String fileLink = getFile(versionLink); String fileLink = getFile(versionLink);
if(fileLink != null && type != UpdateType.NO_DOWNLOAD) if(fileLink != null && type != UpdateType.NO_DOWNLOAD)
{ {
@ -212,7 +274,16 @@ public class Updater
String [] split = fileLink.split("/"); String [] split = fileLink.split("/");
name = split[split.length-1]; name = split[split.length-1];
} }
saveFile(new File("plugins/" + updateFolder), name, fileLink);
// Never download the same file twice
if (!downloadedVersion.equalsIgnoreCase(versionLink)) {
saveFile(new File("plugins/" + updateFolder), name, fileLink);
downloadedVersion = versionLink;
result = UpdateResult.SUCCESS;
} else {
result = UpdateResult.UPDATE_AVAILABLE;
}
} }
else else
{ {
@ -220,8 +291,10 @@ public class Updater
} }
} }
} }
return result;
} }
/** /**
* Get the result of the update process. * Get the result of the update process.
*/ */
@ -267,7 +340,7 @@ public class Updater
byte[] data = new byte[BYTE_SIZE]; byte[] data = new byte[BYTE_SIZE];
int count; int count;
if(announce) plugin.getLogger().info("About to download a new update: " + versionTitle); if(announce) logger.info("About to download a new update: " + versionTitle);
long downloaded = 0; long downloaded = 0;
while ((count = in.read(data, 0, BYTE_SIZE)) != -1) while ((count = in.read(data, 0, BYTE_SIZE)) != -1)
{ {
@ -276,7 +349,7 @@ public class Updater
int percent = (int) (downloaded * 100 / fileLength); int percent = (int) (downloaded * 100 / fileLength);
if(announce & (percent % 10 == 0)) if(announce & (percent % 10 == 0))
{ {
plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes."); logger.info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
} }
} }
//Just a quick check to make sure we didn't leave any files from last time... //Just a quick check to make sure we didn't leave any files from last time...
@ -294,11 +367,11 @@ public class Updater
// Unzip // Unzip
unzip(dFile.getCanonicalPath()); unzip(dFile.getCanonicalPath());
} }
if(announce) plugin.getLogger().info("Finished updating."); if(announce) logger.info("Finished updating.");
} }
catch (Exception ex) catch (Exception ex)
{ {
plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful."); logger.warning("The auto-updater tried to download a new update, but was unsuccessful.");
result = Updater.UpdateResult.FAIL_DOWNLOAD; result = Updater.UpdateResult.FAIL_DOWNLOAD;
} }
finally finally
@ -407,7 +480,7 @@ public class Updater
catch(IOException ex) catch(IOException ex)
{ {
ex.printStackTrace(); ex.printStackTrace();
plugin.getLogger().warning("The auto-updater tried to unzip a new update file, but was unsuccessful."); logger.warning("The auto-updater tried to unzip a new update file, but was unsuccessful.");
result = Updater.UpdateResult.FAIL_DOWNLOAD; result = Updater.UpdateResult.FAIL_DOWNLOAD;
} }
new File(file).delete(); new File(file).delete();
@ -474,7 +547,7 @@ public class Updater
catch (Exception ex) catch (Exception ex)
{ {
ex.printStackTrace(); ex.printStackTrace();
plugin.getLogger().warning("The auto-updater tried to contact dev.bukkit.org, but was unsuccessful."); logger.warning("The auto-updater tried to contact dev.bukkit.org, but was unsuccessful.");
result = Updater.UpdateResult.FAIL_DBO; result = Updater.UpdateResult.FAIL_DBO;
return null; return null;
} }
@ -486,7 +559,7 @@ public class Updater
*/ */
private boolean versionCheck(String title) private boolean versionCheck(String title)
{ {
if(type != UpdateType.NO_VERSION_CHECK) if (type != UpdateType.NO_VERSION_CHECK)
{ {
String version = plugin.getDescription().getVersion(); String version = plugin.getDescription().getVersion();
if(title.split("v").length == 2) if(title.split("v").length == 2)
@ -512,9 +585,9 @@ public class Updater
else else
{ {
// The file's name did not contain the string 'vVersion' // The file's name did not contain the string 'vVersion'
plugin.getLogger().warning("The author of this plugin has misconfigured their Auto Update system"); logger.warning("The author of this plugin has misconfigured their Auto Update system");
plugin.getLogger().warning("Files uploaded to BukkitDev should contain the version number, seperated from the name by a 'v', such as PluginName v1.0"); logger.warning("Files uploaded to BukkitDev should contain the version number, seperated from the name by a 'v', such as PluginName v1.0");
plugin.getLogger().warning("Please notify the author (" + plugin.getDescription().getAuthors().get(0) + ") of this error."); logger.warning("Please notify the author (" + plugin.getDescription().getAuthors().get(0) + ") of this error.");
result = Updater.UpdateResult.FAIL_NOVERSION; result = Updater.UpdateResult.FAIL_NOVERSION;
return false; return false;
} }