package kcauldron.updater; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import kcauldron.KCauldron; import kcauldron.updater.KVersionRetriever.IVersionCheckCallback; import net.minecraft.server.MinecraftServer; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.LaxRedirectStrategy; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import com.google.common.base.Joiner; public class KCauldronUpdater implements Runnable, IVersionCheckCallback { private static final class LatestVersionCallback extends CommandSenderUpdateCallback { public LatestVersionCallback(CommandSender sender) { super(sender); } @Override public void newVersion(String newVersion) { startUpdate(getSender(), newVersion); } @Override public void upToDate() { KCauldron.sUpdateInProgress = false; CommandSender sender = getSender(); if (sender != null) { sender.sendMessage(ChatColor.DARK_PURPLE + "Current version (" + KCauldron.getCurrentVersion() + ") is up to date"); } } @Override public void error(Throwable t) { super.error(t); KCauldron.sUpdateInProgress = false; } } public static void initUpdate(CommandSender sender, String version) { if (KCauldron.sUpdateInProgress) { sender.sendMessage(ChatColor.RED + "Update stopped: another update in progress"); return; } KCauldron.sUpdateInProgress = true; if (version == null) { sender.sendMessage(ChatColor.DARK_PURPLE + "Fetching latest version..."); KVersionRetriever.startServer(new LatestVersionCallback(sender), false); } else { startUpdate(sender, version); } } private static void startUpdate(CommandSender sender, String version) { if (sender != null) { sender.sendMessage(ChatColor.DARK_PURPLE + "Starting update to " + version + "..."); } new KCauldronUpdater(sender, version); } private final CommandSender mSender; private final String mVersion; private final Thread mThread; public KCauldronUpdater(CommandSender sender, String version) { mSender = sender; mVersion = version; mThread = new Thread(this); mThread.setName("KCauldron updater"); mThread.setPriority(Thread.MIN_PRIORITY); mThread.start(); } @Override public void run() { if (!MinecraftServer.kcauldronConfig.updatecheckerQuite.getValue()) { mSender.sendMessage(ChatColor.DARK_PURPLE + "Retrieving latest KBootstrap version..."); } new KVersionRetriever(this, false, false, "pw.prok", "KBootstrap"); } @Override public void upToDate() { } @Override public void newVersion(String kbootstrapVersion) { boolean quite = MinecraftServer.kcauldronConfig.updatecheckerQuite .getValue(); try { if (!quite) { mSender.sendMessage(ChatColor.DARK_PURPLE + "Downloading KBootstrap " + kbootstrapVersion + "..."); } File kbootstrap = File.createTempFile("kbootstrap", String.valueOf(System.currentTimeMillis())); download( "https://api.prok.pw/repo/blob/pw.prok/KBootstrap/latest/app", kbootstrap); if (!quite) { mSender.sendMessage(ChatColor.DARK_PURPLE + "Installing KCauldron " + mVersion + " via KBootstrap " + kbootstrapVersion + "..."); } String javahome = System.getProperty("java.home"); String javapath = javahome + "/bin/java"; List command = new ArrayList(); command.add(javapath); command.add("-jar"); command.add(kbootstrap.getCanonicalPath()); command.add("--serverDir"); command.add(KCauldron.getServerHome().getCanonicalPath()); command.add("--installKCauldron"); command.add(String.format("%s:%s:%s", KCauldron.getGroup(), KCauldron.getChannel(), mVersion)); final String[] symlinks = MinecraftServer.kcauldronConfig.updatecheckerSymlinks .getValue().trim().split(File.pathSeparator); for (String symlink : symlinks) { command.add("--serverSymlinks"); command.add(symlink); } Bukkit.getConsoleSender().sendMessage( "Starting command: " + Joiner.on(' ').join(command)); ProcessBuilder builder = new ProcessBuilder(command); builder.environment().put("JAVA_HOME", javahome); switch (builder.start().waitFor()) { case 0: mSender.sendMessage(ChatColor.GREEN + "KCauldron " + mVersion + " installed"); break; default: mSender.sendMessage(ChatColor.RED + "Failed to install KCauldron " + mVersion); } } catch (Exception e) { if (!quite) { e.printStackTrace(); } if (mSender != null) { mSender.sendMessage(ChatColor.RED + "Failed update to " + mVersion); } } finally { KCauldron.sUpdateInProgress = false; } } @Override public void error(Throwable t) { KCauldron.sUpdateInProgress = false; t.printStackTrace(); } private static void download(String url, File destination) throws IOException { HttpUriRequest request = RequestBuilder .get() .setUri(url) .addParameter("hostname", MinecraftServer.getServer().getHostname()) .addParameter("port", String.valueOf(MinecraftServer.getServer().getPort())) .build(); CloseableHttpClient client = HttpClientBuilder.create() .setRedirectStrategy(new LaxRedirectStrategy()) .setUserAgent("KCauldron Updater").build(); HttpResponse response = client.execute(request); if (response.getStatusLine().getStatusCode() != 200) { client.close(); throw new IllegalStateException("Could not download " + url); } InputStream is = response.getEntity().getContent(); OutputStream os = new FileOutputStream(destination); IOUtils.copy(is, os); is.close(); os.close(); client.close(); } }