Package net.hearthstats.updater.application

Source Code of net.hearthstats.updater.application.HearthStatsUpdater

package net.hearthstats.updater.application;

import net.hearthstats.updater.UpdaterConfiguration;
import net.hearthstats.updater.exception.UpdaterException;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


class HearthStatsUpdater implements ActionListener {

  private static final Set<String> FILES_TO_SKIP = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
    "instructions-osx.txt"
  )));

  private static final int BUFFER_SIZE = 8096// 8kb

  private final ProgressWindow window;

  private final String version;
  private final long assetId;
  private final String hearthstatsLocation;
  private final String downloadFile;

  private SwingWorker<Object, Object> downloadWorker;

  private HearthStatsUpdater(String version, long assetId, String hearthstatsLocation, String downloadFile) {
    window = new ProgressWindow(this);
    this.version = version;
    this.assetId = assetId;
    this.hearthstatsLocation = hearthstatsLocation;
    this.downloadFile = downloadFile;

    window.open();
  }


  private void download() {
    downloadWorker = new SwingWorker<Object, Object>() {
      private boolean errorOccurred = false;

      @Override
      protected Object doInBackground() throws Exception {

        window.setProgress("Starting download...");
        window.log("Downloading version " + version + " of the HearthStats Companion.");
        window.enableCancelButton();

        String assetUrlString = UpdaterConfiguration.getNewAssetApiUrl(assetId);
        boolean downloadedFromNewUrl = downloadAsset(assetUrlString);
        if (!downloadedFromNewUrl) {
          assetUrlString = UpdaterConfiguration.getOldAssetApiUrl(assetId);
          downloadAsset(assetUrlString);
        }

        return null;
      }


      private boolean downloadAsset(String assetUrlString) {
        String currentUrlString = assetUrlString;

        try {
          URL assetUrl = new URL(assetUrlString);

          HttpURLConnection connection = (HttpURLConnection) assetUrl.openConnection();
          connection.addRequestProperty("User-Agent", UpdaterConfiguration.getClientUserAgent());
          connection.addRequestProperty("Accept", "application/octet-stream");

          // During development you can set an OAuth token to test with draft releases.
          if (!UpdaterConfiguration.getGitHubOAuthToken().isEmpty()) {
            connection.addRequestProperty("Authorization", "token " + UpdaterConfiguration.getGitHubOAuthToken());
          }

          // Do not redirect automatically because we should not pass GitHub authorisation tokens to a redirected URL,
          // such as to Amazon S3 where most GitHub binaries are stored.
          connection.setInstanceFollowRedirects(false);

          logRequestHeaders(connection);
          connection.connect();
          logResponseHeaders(connection);

          int responseCode = connection.getResponseCode();
          if (responseCode == 404) {
            // Asset was not found
            return false;
          }
          if (responseCode == 302 || responseCode == 307) {
            // We have been redirected to the download, which is the normal behaviour
            String redirectUrlString = connection.getHeaderField("location");
            currentUrlString = redirectUrlString;
            connection.disconnect();

            URL redirectUrl = new URL(redirectUrlString);
            System.out.println("Downloading from " + urlWithoutQuery(redirectUrl));
            connection = (HttpURLConnection) redirectUrl.openConnection();
            connection.addRequestProperty("User-Agent", UpdaterConfiguration.getClientUserAgent());

            logRequestHeaders(connection);
            connection.connect();
            logResponseHeaders(connection);
          }

          // Download the file
          byte[] buffer = new byte[BUFFER_SIZE];
          int bytesRead = -1;
          long totalBytesRead = 0;
          long fileSize = connection.getContentLengthLong();

          window.setProgress("Downloaded", 0, (int) fileSize);
          window.log(String.format("File size is %1$.1fMB.", fileSize / 1048576f));
          try (InputStream in = connection.getInputStream();
               FileOutputStream fos = new FileOutputStream(downloadFile)) {
            while ((bytesRead = in.read(buffer)) != -1 && !isCancelled()) {
              fos.write(buffer, 0, bytesRead);
              totalBytesRead += bytesRead;
              int percentCompleted = (int) (totalBytesRead * 100 / fileSize);
              setProgress(percentCompleted > 100 ? 100 : percentCompleted);
              window.setProgress("Downloaded", (int) totalBytesRead, (int) fileSize);
            }
          }

          return true;

        } catch (IOException e) {
          String error = "Unable to open connection to URL " + currentUrlString + " due to exception " + e.getMessage();
          window.log(error);
          errorOccurred = true;
          throw new UpdaterException(error, e);
        }
      }


      @Override
      protected void done() {
        window.disableCancelButton();

        if (!isCancelled() && !errorOccurred) {
          window.setProgress("Download Complete");
          window.log("Download complete.");
          extractZip();
        } else {
          window.setProgress("Download Cancelled");
          window.log("Download cancelled. Please restart the updater if you want to try again.");
        }
      }
    };

    downloadWorker.execute();

  }


  private void extractZip() {
    SwingWorker<Object, Object> extractWorker = new SwingWorker<Object, Object>() {
      private boolean errorOccurred = false;

      @Override
      protected Object doInBackground() throws Exception {
        window.log("Extracting " + version + " to " + hearthstatsLocation + "...");

        File updateZip = new File(downloadFile);
        if (updateZip.isFile()) {
          byte[] buffer = new byte[1024];

          try {
            // create output directory if it does not exist
            File folder = new File(hearthstatsLocation);
            if (!folder.exists()) {
              folder.mkdir();
            }

            // get the zip file content
            ZipInputStream zis = new ZipInputStream(new FileInputStream(updateZip.getPath()));
            // get the zipped file list entry
            ZipEntry ze = zis.getNextEntry();

            while (ze != null) {
              String fileName = ze.getName();
              if (!FILES_TO_SKIP.contains(fileName)) {
                File newFile = new File(hearthstatsLocation + File.separator + fileName);
                System.out.println("Unzipping file: " + newFile.getAbsoluteFile());

                // Create parent folders for files in the archive because FileOutputStream expects them to exist
                new File(newFile.getParent()).mkdirs();

                if (!ze.isDirectory()) {
                  FileOutputStream fos = new FileOutputStream(newFile);
                  try {
                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                      fos.write(buffer, 0, len);
                    }
                  } finally {
                    fos.close();
                  }
                }
              }
              ze = zis.getNextEntry();
            }

            zis.closeEntry();
            zis.close();

            System.out.println("Done");

          } catch (IOException ex) {
            String error = "Unable to uncompress file " + updateZip.getPath() + " due to exception " + ex.getMessage();
            window.log(error);
            errorOccurred = true;
            throw new UpdaterException(error, ex);
          }

          window.log("HearthStats Companion is now updated.");
        } else {
          window.log("Updater Error: unable to locate " + updateZip.getPath());
        }

        return null;
      }

      @Override
      protected void done() {
        if (!isCancelled() && !errorOccurred) {
          runMain();
        }
      }

    };

    extractWorker.execute();
  }


  public void runMain() {
    window.log("Update complete. Attempting to restart...");
    try {
      // Attempt to open HearthStats
      switch(getOperatingSystem()) {
        case "WINDOWS":
          Runtime.getRuntime().exec("HearthStats.exe");
          break;
        case "OSX":
          Desktop.getDesktop().open(new File(hearthstatsLocation + "/HearthStats.app"));
          break;
      }
      window.close();

      // If no exception occurred then quit
      System.exit(0);

    } catch (Exception e) {
      window.log("Error: " + e.getMessage());
      e.printStackTrace();
    }
  }


  @Override
  public void actionPerformed(ActionEvent e) {
    if (e.getID() == ProgressWindow.EVENT_CANCEL) {
      if (downloadWorker != null && !downloadWorker.isDone()) {
        System.out.println("Cancel download has been requested");
        downloadWorker.cancel(false);
      }
    }
  }


  /**
   * @param args
   */
  public static void main(String[] args) {
    Map<String, String> arguments = getCommandArguments(args);

    HearthStatsUpdater updater = new HearthStatsUpdater(
      arguments.get("version"),
      Long.parseLong(arguments.get("assetId")),
      arguments.get("hearthstatsLocation"),
      arguments.get("downloadFile")
    );

    updater.download();

  }


  private static Map<String, String> getCommandArguments(String[] args) {
    Map<String, String> result = new HashMap<>();

    for (String arg : args) {
      String[] argSplit = arg.split("=");
      if (argSplit.length == 2) {
        result.put(argSplit[0], argSplit[1]);
      }
    }

    return result;
  }


  private static String getOperatingSystem() {
    String osString = null;
    try {
      osString = System.getProperty("os.name");
    } catch ( SecurityException ex ) {
      // Some system properties may not be available if the user has their security settings locked down
      System.err.println("Caught a SecurityException reading the system property 'os.name', defaulting to blank string.");
    }
    if (osString == null) {
      return null;
    } else if ( osString.startsWith( "Windows" ) ) {
      return "WINDOWS";
    } else if ( osString.startsWith( "Mac OS X" ) ) {
      return "OSX";
    } else {
      return null;
    }
  }


  private static String urlWithoutQuery(URL url) {
    if (url == null) {
      return "";
    } else {
      return url.getProtocol()
        + "://"
        + url.getHost()
        + url.getPath();
    }
  }


  private static void logRequestHeaders(HttpURLConnection connection) {
    System.out.println("-----------------------------------------------------------------");
    System.out.println("Request headers for " + connection.getURL().toExternalForm());
    for (Map.Entry<String, List<String>> entry : connection.getRequestProperties().entrySet()) {
      System.out.println("  " + entry.getKey() + "=" + entry.getValue());
    }
  }


  private static void logResponseHeaders(HttpURLConnection connection) {
    System.out.println("-----------------------------------------------------------------");
    System.out.println("Response headers for " + connection.getURL().toExternalForm());
    for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
      System.out.println(" " + entry.getKey() + "=" + entry.getValue());
    }
    System.out.println("-----------------------------------------------------------------");
  }


}
TOP

Related Classes of net.hearthstats.updater.application.HearthStatsUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.