me.hqm.plugindev.wget.WGCommand.java Source code

Java tutorial

Introduction

Here is the source code for me.hqm.plugindev.wget.WGCommand.java

Source

// The MIT License (MIT)
//
// Copyright  2014 Alexander Chauncey (aka HmmmQuestionMark)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package me.hqm.plugindev.wget;

import com.iciql.Db;
import mkremins.fanciful.FancyMessage;
import net.minecraft.util.org.apache.commons.io.IOUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.entity.Player;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.AccessDeniedException;
import java.sql.Timestamp;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * CommandExecutor for
 */
public class WGCommand implements CommandExecutor {
    // -- STATIC CONSTANTS -- //

    static final String PREFIX = ChatColor.YELLOW + "[wget] ";
    static final ConcurrentMap<String, URL> CACHE = new ConcurrentHashMap<>();

    // -- FINAL -- //

    private final WGET plugin;
    private final ConversationFactory factory;

    // -- CONSTRUCTOR -- //

    protected WGCommand(WGET plugin) {
        this.plugin = plugin;
        factory = new ConversationFactory(plugin);
    }

    // -- BUKKIT METHODS -- //

    /**
     * Standard Bukkit command executor.
     *
     * @param sender  The command sender
     * @param command The command being sent
     * @param label   The label/alias being used
     * @param args    The arguments following the command
     * @return The command ran successfully
     */
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        // Check for correct arg length
        if (args.length == 1) {
            // make a valid url when possible
            String input = args[0];
            if (!input.startsWith("http://") && !input.startsWith("https://")) {
                input = ("http://" + input);
            }

            // Attempt to get a valid url
            URL url = getUrl(input);

            // Check for a valid url
            if (url != null) {
                // If sender is the console, skip verification
                if (sender instanceof ConsoleCommandSender) {
                    downloadTask(sender, url);
                } else {
                    // Add url to cache before asking for verification
                    Player player = (Player) sender;
                    CACHE.put(player.getName(), url);

                    // Send cool click text verification
                    FancyMessage message = new FancyMessage("[wget] Confirm download: ");
                    message.color(ChatColor.YELLOW).then("continue").style(ChatColor.ITALIC)
                            .command("/wget " + player.getName() + " continue")
                            .tooltip("Download " + fileName(url) + "?").then(" / ").color(ChatColor.YELLOW)
                            .then("cancel").style(ChatColor.ITALIC).command("/wget " + sender.getName() + " cancel")
                            .send(player);
                }
                return true;
            } else if (WGET.DB_USE && "history".equalsIgnoreCase(args[0])) {
                sender.sendMessage("Coming soon."); // TODO
            } else if (WGET.DB_USE && sender instanceof Player) {
                Player player = (Player) sender;
                if ("register".equalsIgnoreCase(args[0])) {
                    factory.withEscapeSequence("/cancel").withFirstPrompt(new PasswordPrompt()).withLocalEcho(false)
                            .buildConversation(player).begin();
                    return true;
                } else if ("login".equalsIgnoreCase(args[0])) {
                    factory.withEscapeSequence("/cancel")
                            .withFirstPrompt(new ConfirmPrompt(ConfirmPrompt.Type.LOGIN)).withLocalEcho(false)
                            .buildConversation(player).begin();
                    return true;
                }
            }
        }

        // Verification command
        if (sender instanceof Player && args.length == 2) {
            Player player = (Player) sender;
            String name = args[0];
            // If verified correctly start the download task
            if ("continue".equalsIgnoreCase(args[1])) {
                if (CACHE.get(name) == null) {
                    sender.sendMessage(PREFIX + "Please use /wget <link> to select a download.");
                    return true;
                }

                // DB
                if (WGET.DB_USE) {
                    if (!WGET.isRegistered(player)) {
                        player.sendMessage(ChatColor.RED + "[wget] You are not registered.");
                        player.sendMessage(PREFIX + "Register now, or type \"/cancel\" at any time.");
                        player.performCommand("wget register");
                        return true;
                    }
                    if (!WGET.isLoggedIn(player)) {
                        player.performCommand("wget login");
                        return true;
                    }
                }

                downloadTask(player, CACHE.get(name));
                CACHE.remove(name);
            } else {
                // Cancel download and alert the sender.
                CACHE.remove(name);
                player.sendMessage(PREFIX + "Download cancelled.");
            }
            return true;
        }
        return false;
    }

    // -- PRIVATE HELPER/UTIL METHODS -- //

    /**
     * Easy method to grab the plugin's Logger.
     *
     * @return the Logger
     */
    private Logger getLogger() {
        return plugin.getLogger();
    }

    /**
     * Get a URL from an input string.
     *
     * @param input URL String
     * @return Valid URL
     */
    private URL getUrl(String input) {
        // We only accept jar or zip files
        if (input.endsWith(".jar") || input.endsWith(".zip")) {
            // Try to create the object, and test the connection
            try {
                URI uri = new URI(input);
                URL url = uri.toURL();
                URLConnection conn = url.openConnection();
                conn.connect();
                // Return the url
                return url;
            } catch (IOException | URISyntaxException ignored) {
            }
        }
        // Failed, return null
        return null;
    }

    /**
     * Get the file name from the URL.
     *
     * @param url Valid URL
     * @return Filename
     */
    private String fileName(URL url) {
        // Split up the url by each '/'
        String[] fileNameParts = url.toString().split("/");
        // Return the last section, removing duplicate periods
        return fileNameParts[fileNameParts.length - 1].replace("..", ".");
    }

    /**
     * Create and start a download (async) task.
     *
     * @param sender The sender who started the task
     * @param url    Valid URL
     */
    private void downloadTask(final CommandSender sender, final URL url) {
        // Alert the sender the download has begun
        sender.sendMessage(PREFIX + "Downloading...");

        // Create and schedule the new async task
        Bukkit.getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
            @Override
            public void run() {
                // Download the file
                if (download(url)) {
                    // Log the download
                    logDownload(sender, url, true);
                    // If the sender is the console just let it know the download is complete
                    if (sender instanceof ConsoleCommandSender) {
                        sender.sendMessage(PREFIX + "Download complete, reload for update.");
                    } else {
                        // Send the player a fancy message allowing them to click to reload
                        Player player = (Player) sender;
                        FancyMessage message = new FancyMessage("[wget] Download complete, ");
                        message.color(ChatColor.YELLOW).then("reload").style(ChatColor.ITALIC).command("/reload")
                                .tooltip("Reload the server?").then(" for update.").color(ChatColor.YELLOW)
                                .send(player);
                    }
                } else {
                    // Oops, something went wrong during download
                    logDownload(sender, url, false);
                    sender.sendMessage(PREFIX + ChatColor.RED + "ERR: Could not finish downloading.");
                }
            }
        });
    }

    private void logDownload(CommandSender sender, URL url, boolean success) {
        if (WGET.DB_USE) {
            Db db = Db.open(WGET.DB_URL);

            WGDownload download = new WGDownload();
            download.downloadLink = url.toString();
            download.downloadTime = new Timestamp(System.currentTimeMillis());
            download.success = success;

            if (sender instanceof Player) {
                download.userId = ((Player) sender).getUniqueId().toString();

                WGUser alias = new WGUser();
                WGUser user = db.from(alias).where(alias.minecraftId).is(((Player) sender).getUniqueId().toString())
                        .selectFirst();

                user.downloadCount++;
                db.update(user);
            }

            db.insert(download);

            db.close();
        }
    }

    /**
     * Download a URL (jar or zip) to a file
     *
     * @param url Valid URL
     * @return Success or failure
     */
    private boolean download(URL url) {
        // The plugin folder path
        String path = plugin.getDataFolder().getParentFile().getPath();

        // Wrap everything in a try/catch
        try {
            // Get the filename from the url
            String fileName = fileName(url);

            // Create a new input stream and output file
            InputStream in = url.openStream();
            File outFile = new File(path + "/" + fileName);

            // If the file already exists, delete it
            if (outFile.exists()) {
                outFile.delete();
            }

            // Create the output stream and download the file
            FileOutputStream out = new FileOutputStream(outFile);
            IOUtils.copy(in, out);

            // Close the streams
            in.close();
            out.close();

            // If downloaded file is a zip file...
            if (fileName.endsWith(".zip")) {
                // Declare a new input stream outside of a try/catch
                ZipInputStream zis = null;
                try {
                    // Define the input stream
                    zis = new ZipInputStream(new FileInputStream(outFile));

                    // Decalre a zip entry for the while loop
                    ZipEntry entry;
                    while ((entry = zis.getNextEntry()) != null) {
                        // Make a new file object for the entry
                        File entryFile = new File(path, entry.getName());

                        // If it is a directory and doesn't already exist, create the new directory
                        if (entry.isDirectory()) {
                            if (!entryFile.exists()) {
                                entryFile.mkdirs();
                            }
                        } else {
                            // Make sure all folders exist
                            if (entryFile.getParentFile() != null && !entryFile.getParentFile().exists()) {
                                entryFile.getParentFile().mkdirs();
                            }

                            // Create file on disk
                            if (!entryFile.exists() && !entryFile.createNewFile()) {
                                // Access denied, let the console know
                                throw new AccessDeniedException(entryFile.getPath());
                            }

                            // Write data to file from zip.
                            OutputStream os = null;
                            try {
                                os = new FileOutputStream(entryFile);
                                IOUtils.copy(zis, os);
                            } finally {
                                // Silently close the output stream
                                IOUtils.closeQuietly(os);
                            }
                        }
                    }
                } finally {
                    // Always close streams
                    IOUtils.closeQuietly(zis);
                }

                // Delete the zip file
                outFile.delete();
            }

            // Return success
            return true;
        } catch (NullPointerException | IOException oops) {
            getLogger().severe("---------- WGET BEGIN -----------");
            getLogger().severe("An error occurred during a file download/extraction:");
            oops.printStackTrace();
            getLogger().severe("----------- WGET END ------------");
        }

        // The download failed, report failure
        return false;
    }
}