Fixed Update downloading, old jar deletion still broken

This commit is contained in:
Rsl1122 2018-04-14 12:56:38 +03:00
parent 4e0f1b38f1
commit 0ff4e22a02
6 changed files with 168 additions and 70 deletions

View File

@ -36,6 +36,7 @@ public class PlanCommand extends TreeCmdNode {
new ListCommand(),
new AnalyzeCommand(),
new NetworkCommand(),
new ListServersCommand(plugin)
},
new CommandNode[]{
new WebUserCommand(plugin, registerCommand, this),

View File

@ -6,17 +6,22 @@ import com.djrapitops.plan.command.commands.manage.ManageConDebugCommand;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.info.request.CheckConnectionRequest;
import com.djrapitops.plan.system.info.request.UpdateCancelRequest;
import com.djrapitops.plan.system.info.request.UpdateRequest;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.settings.Permissions;
import com.djrapitops.plan.system.settings.locale.Locale;
import com.djrapitops.plan.system.settings.locale.Msg;
import com.djrapitops.plan.system.update.VersionCheckSystem;
import com.djrapitops.plan.system.update.VersionInfo;
import com.djrapitops.plan.system.webserver.WebServerSystem;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.command.CommandNode;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.CommandUtils;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import java.util.List;
import java.util.Map;
@ -32,13 +37,13 @@ public class UpdateCommand extends CommandNode {
public UpdateCommand() {
super("update", Permissions.MANAGE.getPermission(), CommandType.ALL);
setArguments("[-update]/[cancel]");
setArguments("[-u]/[cancel]");
setShortHelp("Get change log link or update plugin.");
setInDepthHelp(
"/plan update",
" Used to update the plugin on the next shutdown\n",
" /plan update - get change log link",
" /plan update -update - Schedule update to happen on all network servers that are online next time they reboot.",
" /plan update -u - Schedule update to happen on all network servers that are online next time they reboot.",
" /plan update cancel - Cancel scheduled update on servers that haven't rebooted yet."
);
}
@ -62,24 +67,40 @@ public class UpdateCommand extends CommandNode {
}
if (args.length == 0) {
sender.sendLink("Change Log v" + available.getVersion().toString() + ": ", "Click me", available.getChangeLogUrl());
String message = "Change Log v" + available.getVersion().toString() + ": ";
String url = available.getChangeLogUrl();
if (CommandUtils.isConsole(sender)) {
sender.sendMessage(message + url);
} else {
sender.sendMessage(message);
sender.sendLink(" ", Locale.get(Msg.CMD_INFO_CLICK_ME).toString(), url);
}
return;
}
String firstArgument = args[0];
if ("-update".equals(firstArgument)) {
handleUpdate(sender, args);
} else if ("cancel".equals(firstArgument)) {
cancel(sender);
} else {
throw new IllegalArgumentException("Unknown argument, use '-update' or 'cancel'");
}
RunnableFactory.createNew("Update Command Task", new AbsRunnable() {
@Override
public void run() {
try {
if ("-u".equals(firstArgument)) {
handleUpdate(sender, args);
} else if ("cancel".equals(firstArgument)) {
handleCancel(sender);
} else {
throw new IllegalArgumentException("Unknown argument, use '-u' or 'cancel'");
}
} finally {
cancel();
}
}
}).runTaskAsynchronously();
}
private void cancel(ISender sender) {
private void handleCancel(ISender sender) {
try {
cancel(sender, Database.getActive().fetch().getServers());
sender.sendMessage("§aUpdate has been cancelled.");
sender.sendMessage("§aCancel operation performed.");
} catch (DBException e) {
sender.sendMessage("§cDatabase error occurred, cancel could not be performed.");
Log.toLog(this.getClass().getName(), e);
@ -90,24 +111,28 @@ public class UpdateCommand extends CommandNode {
sender.sendMessage("§aYou can cancel the update on servers that haven't rebooted yet with /plan update cancel.");
sender.sendMessage("Checking that all servers are online..");
if (!checkNetworkStatus(sender)) {
sender.sendMessage("§cNot all servers were online or accessible, you can still update available servers using -force as a 2nd argument.");
if (args.length <= 1 || !"-force".equals(args[1])) {
sender.sendMessage("§cNot all servers were online or accessible, you can still update available servers using /plan -update -force");
if (args.length > 1 && "-force".equals(args[1])) {
return;
}
}
try {
List<Server> servers = Database.getActive().fetch().getServers();
update(sender, servers);
update(sender, servers, args);
} catch (DBException e) {
Log.toLog(this.getClass().getName(), e);
}
}
private void update(ISender sender, List<Server> servers) {
private void update(ISender sender, List<Server> servers, String[] args) {
for (Server server : servers) {
if (update(sender, server)) {
sender.sendMessage("§a" + server.getName() + " scheduled for update.");
} else {
if (args.length > 1 && "-force".equals(args[1])) {
sender.sendMessage("§e" + server.getName() + " failed to update, -force specified, continuing update.");
continue;
}
sender.sendMessage("§cUpdate failed on a server, cancelling update on all servers..");
cancel(sender, servers);
sender.sendMessage("§cUpdate cancelled.");
@ -149,7 +174,7 @@ public class UpdateCommand extends CommandNode {
private boolean update(ISender sender, Server server) {
try {
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new CheckConnectionRequest(), server);
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new UpdateRequest(), server);
return true;
} catch (BadRequestException e) {
sender.sendMessage("§c" + server.getName() + " has Allow-Update set to false, aborting update.");
@ -186,6 +211,7 @@ public class UpdateCommand extends CommandNode {
FetchOperations fetch = Database.getActive().fetch();
Optional<Server> bungeeInformation = fetch.getBungeeInformation();
if (!bungeeInformation.isPresent()) {
sender.sendMessage("Bungee address not found in the database, assuming this is not a network.");
return true;
}
Map<UUID, Server> bukkitServers = fetch.getBukkitServers();

View File

@ -81,9 +81,9 @@ public abstract class PlanSystem implements SubSystem {
checkSubSystemInitialization();
SubSystem[] systems = new SubSystem[]{
versionCheckSystem,
fileSystem,
configSystem,
versionCheckSystem,
databaseSystem,
webServerSystem,
processing,

View File

@ -5,12 +5,10 @@ import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.utility.Version;
import com.djrapitops.plugin.api.utility.log.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.*;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.HashSet;
import java.util.Set;
/**
* Shutdown hook that updates the plugin on server shutdown.
@ -22,64 +20,59 @@ import java.nio.channels.ReadableByteChannel;
public class ShutdownUpdateHook extends Thread {
private static boolean activated = false;
private static File newJar;
private static Set<File> toDelete = new HashSet<>();
private static boolean isActivated() {
return activated;
}
private static void activate(ShutdownUpdateHook hook) {
public static void activate() {
activated = true;
Runtime.getRuntime().addShutdownHook(hook);
}
public static void deActivate() {
activated = false;
Log.infoColor("§aUpdate has been cancelled.");
}
public void register() {
if (isActivated()) {
return;
}
Log.infoColor("§aUpdate has been scheduled, The new jar will be downloaded on server shutdown.");
activate(this);
}
@Override
public void run() {
if (!activated) {
return;
}
activated = false;
VersionInfo available = VersionCheckSystem.getInstance().getNewVersionAvailable();
if (!Version.isNewVersionAvailable(new Version(VersionCheckSystem.getCurrentVersion()), available.getVersion())) {
return;
}
File dataFolder = PlanPlugin.getInstance().getDataFolder();
File pluginsFolder = Check.isSpongeAvailable()
? dataFolder.getParentFile()
: new File(dataFolder.getParentFile().getParentFile(), "mods");
if (pluginsFolder == null || !pluginsFolder.isDirectory()) {
System.out.println("Could not get plugin folder for Plan.");
return;
}
File newFileLocation = new File(pluginsFolder, "Plan-" + available.getVersion() + ".jar");
try {
downloadNewJar(available, newFileLocation);
deleteOldJar(pluginsFolder, newFileLocation);
File pluginsFolder = getPluginsFolder();
newJar = new File(pluginsFolder, "Plan-" + available.getVersion() + ".jar");
downloadNewJar(available, newJar);
registerOldJarForDeletion(pluginsFolder, newJar);
} catch (IOException e) {
Log.toLog(this.getClass().getName(), e);
e.printStackTrace();
}
}
private void deleteOldJar(File pluginsFolder, File newFileLocation) {
private static File getPluginsFolder() throws FileNotFoundException {
File dataFolder = PlanPlugin.getInstance().getDataFolder();
File pluginsFolder = Check.isSpongeAvailable()
? new File(dataFolder.getParentFile().getParentFile().getPath(), "mods")
: new File(dataFolder.getParentFile().getPath());
if (!pluginsFolder.isDirectory()) {
throw new FileNotFoundException("Could not get plugin folder for Plan.");
}
return pluginsFolder;
}
public static void deActivate() {
activated = false;
Log.infoColor("§aUpdate has been cancelled.");
if (newJar != null && newJar.exists()) {
if (!newJar.delete()) {
newJar.deleteOnExit();
}
}
toDelete.clear();
}
public static void registerOldJarForDeletion(File pluginsFolder, File newFileLocation) throws FileNotFoundException {
File[] files = pluginsFolder.listFiles();
if (files == null) {
System.out.println("Could not delete old jar.");
return;
throw new FileNotFoundException("Could not delete old jar.");
}
for (File file : files) {
String fileName = file.getName();
@ -88,17 +81,51 @@ public class ShutdownUpdateHook extends Thread {
|| fileName.equals("Plan.jar");
boolean isNewJar = fileName.equals(newFileLocation.getName());
if (isPlanJar && !isNewJar) {
file.deleteOnExit();
toDelete.add(file);
}
}
}
private void downloadNewJar(VersionInfo available, File newFileLocation) throws IOException {
public static void downloadNewJar(VersionInfo available, File newFileLocation) throws IOException {
URL downloadFrom = new URL(available.getDownloadUrl());
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
in = new BufferedInputStream(downloadFrom.openStream());
fout = new FileOutputStream(newFileLocation);
ReadableByteChannel rbc = Channels.newChannel(downloadFrom.openStream());
FileOutputStream fos = new FileOutputStream(newFileLocation);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
final byte data[] = new byte[1024];
int count;
while ((count = in.read(data, 0, 1024)) != -1) {
fout.write(data, 0, count);
}
} finally {
if (in != null) {
in.close();
}
if (fout != null) {
fout.close();
}
}
}
public void register() {
if (isActivated()) {
return;
}
Log.infoColor("§aUpdate has been scheduled, Downloading new jar.. Restart server to take effect.");
activate();
Runtime.getRuntime().addShutdownHook(this);
}
@Override
public void run() {
for (File f : toDelete
) {
if (!f.delete()) {
f.deleteOnExit();
}
}
}
}

View File

@ -55,10 +55,13 @@ public class VersionCheckSystem implements SubSystem {
}
VersionInfo newestVersion = versions.get(0);
if (Version.isNewVersionAvailable(new Version(currentVersion), newestVersion.getVersion())) {
newVersionAvailable = newestVersion;
String notification =
"New Release (" + newestVersion.getVersion().toString() + ") is available and can be updated " +
"to using update subcommand." + (newestVersion.isRelease() ? "" : " This is a DEV release.");
Log.info(notification);
Log.infoColor("§a----------------------------------------");
Log.infoColor("§a" + notification);
Log.infoColor("§a----------------------------------------");
NotificationCenter.addNotification(newestVersion.isRelease() ? Priority.HIGH : Priority.MEDIUM, notification);
} else {
Log.info("You're using the latest version.");

View File

@ -0,0 +1,41 @@
package com.djrapitops.plan.system.update;
import com.djrapitops.plugin.api.utility.Version;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* //TODO Class Javadoc Comment
*
* @author Rsl1122
*/
public class ShutdownUpdateHookTest {
@ClassRule
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void downloadNewJar() throws IOException {
File newJar = new File(temporaryFolder.getRoot(), "Plan-4.2.0.jar");
ShutdownUpdateHook.downloadNewJar(new VersionInfo(
true,
new Version("4.2.0"),
"https://github.com/Rsl1122/Plan-PlayerAnalytics/releases/download/4.2.0/Plan-4.2.0.jar",
""
), newJar
);
assertTrue(newJar.exists());
ShutdownUpdateHook.registerOldJarForDeletion(temporaryFolder.getRoot(), new File(temporaryFolder.getRoot(), "Plan-4.2.0-b1.jar"));
assertFalse(newJar.exists());
}
}