feat: preparing for download and install of mode files

This commit is contained in:
lantzelot-swe 2021-12-04 22:16:41 +01:00
parent fee069f0cd
commit 33a37968f1
7 changed files with 303 additions and 190 deletions

View File

@ -46,9 +46,9 @@ import se.lantz.gui.install.VersionDownloadDialog;
import se.lantz.manager.BackupManager; import se.lantz.manager.BackupManager;
import se.lantz.manager.ExportManager; import se.lantz.manager.ExportManager;
import se.lantz.manager.ImportManager; import se.lantz.manager.ImportManager;
import se.lantz.manager.PCUAEInstallManager;
import se.lantz.manager.RestoreManager; import se.lantz.manager.RestoreManager;
import se.lantz.manager.SavedStatesManager; import se.lantz.manager.SavedStatesManager;
import se.lantz.manager.pcuae.PCUAEInstallManager;
import se.lantz.model.MainViewModel; import se.lantz.model.MainViewModel;
import se.lantz.model.data.GameListData; import se.lantz.model.data.GameListData;
import se.lantz.model.data.GameView; import se.lantz.model.data.GameView;

View File

@ -4,7 +4,7 @@ import java.awt.Dimension;
import java.awt.Frame; import java.awt.Frame;
import se.lantz.gui.BaseDialog; import se.lantz.gui.BaseDialog;
import se.lantz.manager.PCUAEInstallManager; import se.lantz.manager.pcuae.PCUAEInstallManager;
public class PCUAEVersionDownloadDialog extends BaseDialog public class PCUAEVersionDownloadDialog extends BaseDialog
{ {

View File

@ -1,4 +1,4 @@
package se.lantz.manager; package se.lantz.manager.pcuae;
import java.awt.AWTEvent; import java.awt.AWTEvent;
import java.awt.Toolkit; import java.awt.Toolkit;
@ -19,8 +19,6 @@ import java.util.Scanner;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -33,89 +31,75 @@ import dyorgio.runtime.out.process.CallableSerializable;
import dyorgio.runtime.run.as.root.RootExecutor; import dyorgio.runtime.run.as.root.RootExecutor;
import se.lantz.gui.MainWindow; import se.lantz.gui.MainWindow;
import se.lantz.gui.download.DownloadDialog; import se.lantz.gui.download.DownloadDialog;
import se.lantz.gui.install.PCUAEVersionDownloadDialog;
import se.lantz.util.ExceptionHandler; import se.lantz.util.ExceptionHandler;
public class PCUAEInstallManager implements AWTEventListener public abstract class BaseInstallManger implements AWTEventListener
{ {
public static final String INSTALL_FOLDER = "./pcuae-install/"; public static final String INSTALL_FOLDER = "./pcuae-install/";
private boolean blockEvents = false; private boolean blockEvents = false;
private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); protected ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
private static String latestVersion = ""; protected volatile boolean downloadIterrupted = false;
private static String tagloadUrl = "";
private String downloadUrl = "";
private String pcuaeMainInstallFile = "";
private static String pcuaeLatestInInstallFolder = "";
private static String latestReleaseDescription = "";
private JMenuItem exportMenuItem; public BaseInstallManger()
private volatile boolean downloadIterrupted = false;
public PCUAEInstallManager(JMenuItem exportMenuItem)
{ {
this.exportMenuItem = exportMenuItem;
Toolkit.getDefaultToolkit().addAWTEventListener(this, Toolkit.getDefaultToolkit().addAWTEventListener(this,
AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK); AWTEvent.MOUSE_MOTION_EVENT_MASK);
} }
public void installPCUAE() @Override
public void eventDispatched(AWTEvent event)
{ {
readVersionFromInstallFolder(); if (blockEvents)
if (isNewVersionAvailable())
{ {
askAndStartDownload(pcuaeLatestInInstallFolder.isEmpty()); if (event instanceof InputEvent)
{
((InputEvent) event).consume();
} }
else else if (event instanceof MouseEvent)
{ {
askToInstallExistingVersion(); ((MouseEvent) event).consume();
}
} }
} }
private void askAndStartDownload(boolean firstDownload) public void switchToBusyCursor(final javax.swing.JFrame frame)
{ {
PCUAEVersionDownloadDialog dialog = new PCUAEVersionDownloadDialog(MainWindow.getInstance(), firstDownload); startEventTrap(frame);
dialog.pack(); frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
dialog.setLocationRelativeTo(MainWindow.getInstance());
if (dialog.showDialog())
{
downloadLatestPCUAE();
}
else if (!firstDownload)
{
askToInstallExistingVersion();
}
} }
private void askToInstallExistingVersion() public void switchToNormalCursor(final javax.swing.JFrame frame)
{ {
int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(), frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
"Do you want to install PCUAE (" + pcuaeMainInstallFile + ") now?", stopEventTrap(frame);
"Install PCUAE",
JOptionPane.YES_NO_OPTION);
if (value == JOptionPane.YES_OPTION)
{
singleThreadExecutor.execute(() -> runAndWaitForInstallation());
}
} }
private boolean isNewVersionAvailable() protected void startEventTrap(javax.swing.JFrame frame)
{ {
fetchLatestPCUAEVersionFromGithub(); blockEvents = true;
return !pcuaeLatestInInstallFolder.equals(pcuaeMainInstallFile); frame.getGlassPane().setVisible(true);
} }
private void readVersionFromInstallFolder() protected void stopEventTrap(javax.swing.JFrame frame)
{ {
pcuaeLatestInInstallFolder = ""; blockEvents = false;
java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
frame.getGlassPane().setVisible(false);
}
protected String readVersionFromInstallFolder(String installFileName)
{
String latestInInstallFolder = "";
FilenameFilter filter = new FilenameFilter() FilenameFilter filter = new FilenameFilter()
{ {
@Override @Override
public boolean accept(File f, String name) public boolean accept(File f, String name)
{ {
return name.endsWith(".exe"); return name.contains(installFileName) && name.endsWith(".exe");
} }
}; };
File installFolder = new File(INSTALL_FOLDER); File installFolder = new File(INSTALL_FOLDER);
@ -134,91 +118,18 @@ public class PCUAEInstallManager implements AWTEventListener
if (latestFile != null) if (latestFile != null)
{ {
pcuaeLatestInInstallFolder = latestFile.getName(); latestInInstallFolder = latestFile.getName();
} }
return latestInInstallFolder;
} }
private void runAndWaitForInstallation() public GithubAssetInformation fetchLatestVersionFromGithub(String assetsName)
{
switchToBusyCursor(MainWindow.getInstance());
RootExecutor rootExecutor;
try
{
rootExecutor = new RootExecutor("-Xmx64m");
// Execute privileged action without return
CallableSerializable<Integer> installCallable = new InstallCallable(pcuaeMainInstallFile);
int value = rootExecutor.call(installCallable);
//0 -> installed
//255 -> aborted
if (value == 0)
{
launchExportDialog();
}
}
catch (Exception e1)
{
ExceptionHandler.logException(e1, "Could not execute RootExecutor");
}
finally
{
SwingUtilities.invokeLater(() -> switchToNormalCursor(MainWindow.getInstance()));
}
}
private void launchExportDialog()
{
SwingUtilities.invokeLater(() -> exportMenuItem.doClick());
}
public void switchToBusyCursor(final javax.swing.JFrame frame)
{
startEventTrap(frame);
frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
}
public void switchToNormalCursor(final javax.swing.JFrame frame)
{
frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
stopEventTrap(frame);
}
private void startEventTrap(javax.swing.JFrame frame)
{
blockEvents = true;
frame.getGlassPane().setVisible(true);
}
private void stopEventTrap(javax.swing.JFrame frame)
{
blockEvents = false;
java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
frame.getGlassPane().setVisible(false);
}
@Override
public void eventDispatched(AWTEvent event)
{
if (blockEvents)
{
if (event instanceof InputEvent)
{
((InputEvent) event).consume();
}
else if (event instanceof MouseEvent)
{
((MouseEvent) event).consume();
}
}
}
public void fetchLatestPCUAEVersionFromGithub()
{ {
GithubAssetInformation githubInfo = new GithubAssetInformation();
try try
{ {
//TODO: To get all releases, use "https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases"- //TODO: To get all releases, use "https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases"-
//How to handle mode packs? //Get all releases, check which one contains the latest file with assetName (part of the name)
URL url = new URL("https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases/latest"); URL url = new URL("https://CommodoreOS@api.github.com/repos/CommodoreOS/PCUAE/releases/latest");
@ -238,57 +149,50 @@ public class PCUAEInstallManager implements AWTEventListener
reader.setLenient(true); reader.setLenient(true);
JsonElement root = new JsonParser().parse(reader); JsonElement root = new JsonParser().parse(reader);
JsonObject jsonObject = root.getAsJsonObject(); JsonObject jsonObject = root.getAsJsonObject();
latestVersion = jsonObject.get("tag_name").getAsString(); githubInfo.setLatestVersion(jsonObject.get("tag_name").getAsString());
tagloadUrl = jsonObject.get("html_url").getAsString(); githubInfo.setReleaseTagUrl(jsonObject.get("html_url").getAsString());
downloadUrl = jsonObject.get("assets").getAsJsonArray().get(0).getAsJsonObject() //TODO: fix
.get("browser_download_url").getAsString(); String downloadUrl =
latestReleaseDescription = jsonObject.get("body").getAsString(); jsonObject.get("assets").getAsJsonArray().get(0).getAsJsonObject().get("browser_download_url").getAsString();
githubInfo.setDownloadUrl(downloadUrl);
pcuaeMainInstallFile = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1); githubInfo.setInstallFile(downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1));
} }
catch (IOException ex) catch (IOException ex)
{ {
ExceptionHandler.handleException(ex, "Could not check version"); ExceptionHandler.handleException(ex, "Could not check version");
} }
return githubInfo;
} }
private void downloadLatestPCUAE() protected void runAndWaitForInstallation(String fileToInstall)
{ {
DownloadDialog progressDialog = new DownloadDialog("Downloading PCUAE version " + latestVersion); switchToBusyCursor(MainWindow.getInstance());
singleThreadExecutor.execute(() -> startDownload(progressDialog)); RootExecutor rootExecutor;
progressDialog.pack();
progressDialog.setLocationRelativeTo(MainWindow.getInstance());
if (progressDialog.showDialog())
{
pcuaeLatestInInstallFolder = pcuaeMainInstallFile;
int value =
JOptionPane.showConfirmDialog(MainWindow.getInstance(),
"Download completed, do you want to install PCUAE " + latestVersion + " now?",
"Download Complete",
JOptionPane.YES_NO_OPTION);
if (value == JOptionPane.YES_OPTION)
{
singleThreadExecutor.execute(() -> runAndWaitForInstallation());
}
}
else
{
downloadIterrupted = true;
//Make sure this executes after the downloading has been interrupted
singleThreadExecutor.execute(() -> {
try try
{ {
Files.deleteIfExists(new File(INSTALL_FOLDER + pcuaeMainInstallFile).toPath()); rootExecutor = new RootExecutor("-Xmx64m");
} // Execute privileged action without return
catch (IOException e) CallableSerializable<Integer> installCallable = new InstallCallable(fileToInstall);
int value = rootExecutor.call(installCallable);
//0 -> installed
//255 -> aborted
if (value == 0)
{ {
ExceptionHandler.handleException(e, "Could not delete partially downloaded file"); executeAfterInstallation();
} }
}); }
catch (Exception e1)
{
ExceptionHandler.logException(e1, "Could not execute RootExecutor");
}
finally
{
SwingUtilities.invokeLater(() -> switchToNormalCursor(MainWindow.getInstance()));
} }
} }
public void startDownload(final DownloadDialog downloadDialog) public void startDownload(final DownloadDialog downloadDialog, GithubAssetInformation assetInfo)
{ {
downloadIterrupted = false; downloadIterrupted = false;
JProgressBar progressBar = downloadDialog.getProgressBar(); JProgressBar progressBar = downloadDialog.getProgressBar();
@ -296,13 +200,13 @@ public class PCUAEInstallManager implements AWTEventListener
URL url; URL url;
try try
{ {
url = new URL(downloadUrl); url = new URL(assetInfo.getDownloadUrl());
Files.createDirectories(new File(INSTALL_FOLDER).toPath()); Files.createDirectories(new File(INSTALL_FOLDER).toPath());
HttpURLConnection httpConnection = (HttpURLConnection) (url.openConnection()); HttpURLConnection httpConnection = (HttpURLConnection) (url.openConnection());
long completeFileSize = httpConnection.getContentLength(); long completeFileSize = httpConnection.getContentLength();
BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream()); BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream());
FileOutputStream fos = new FileOutputStream(INSTALL_FOLDER + pcuaeMainInstallFile); FileOutputStream fos = new FileOutputStream(INSTALL_FOLDER + assetInfo.getInstallFile());
BufferedOutputStream bout = new BufferedOutputStream(fos, 1024); BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024]; byte[] data = new byte[1024];
long downloadedFileSize = 0; long downloadedFileSize = 0;
@ -337,23 +241,21 @@ public class PCUAEInstallManager implements AWTEventListener
} }
} }
public static String getLatestInInstallFolder() protected void cleanupInterruptedDownload(String fileName)
{ {
return pcuaeLatestInInstallFolder; downloadIterrupted = true;
//Make sure this executes after the downloading has been interrupted
singleThreadExecutor.execute(() -> {
try
{
Files.deleteIfExists(new File(INSTALL_FOLDER + fileName).toPath());
}
catch (IOException e)
{
ExceptionHandler.handleException(e, "Could not delete partially downloaded file");
}
});
} }
public static String getLatestVersion() protected abstract void executeAfterInstallation();
{
return latestVersion;
}
public static String getDownloadUrl()
{
return tagloadUrl;
}
public static String getLatestReleaseDescription()
{
return latestReleaseDescription;
}
} }

View File

@ -0,0 +1,54 @@
package se.lantz.manager.pcuae;
public class GithubAssetInformation
{
String latestVersion = "";
String releaseTagUrl = "";
String downloadUrl = "";
String installFile = "";
public GithubAssetInformation()
{
}
public String getLatestVersion()
{
return latestVersion;
}
public void setLatestVersion(String latestVersion)
{
this.latestVersion = latestVersion;
}
public String getReleaseTagUrl()
{
return releaseTagUrl;
}
public void setReleaseTagUrl(String releaseTagUrl)
{
this.releaseTagUrl = releaseTagUrl;
}
public String getDownloadUrl()
{
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl)
{
this.downloadUrl = downloadUrl;
}
public String getInstallFile()
{
return installFile;
}
public void setInstallFile(String installFile)
{
this.installFile = installFile;
}
}

View File

@ -1,4 +1,4 @@
package se.lantz.manager; package se.lantz.manager.pcuae;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@ -0,0 +1,128 @@
package se.lantz.manager.pcuae;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import se.lantz.gui.MainWindow;
import se.lantz.gui.download.DownloadDialog;
import se.lantz.gui.install.PCUAEVersionDownloadDialog;
import se.lantz.util.ManagerVersionChecker;
public class PCUAEInstallManager extends BaseInstallManger
{
public static final String INSTALL_FOLDER = "./pcuae-install/";
private static final String PCUAE_INSTALL_NAME = "pcuae";
// private static final String AMIGA_MODE_INSTALL_NAME = "amiga";
// private static final String ATARI_MODE_INSTALL_NAME = "atari";
// private static final String LINUX_MODE_INSTALL_NAME = "linux";
// private static final String RETROARCH_MODE_INSTALL_NAME = "retroarch";
// private static final String VICE_MODE_INSTALL_NAME = "vice";
private static String pcuaeLatestInInstallFolder = "";
private static GithubAssetInformation gitHubReleaseInformation = new GithubAssetInformation();
private JMenuItem exportMenuItem;
public PCUAEInstallManager(JMenuItem exportMenuItem)
{
this.exportMenuItem = exportMenuItem;
}
public void installPCUAE()
{
pcuaeLatestInInstallFolder = readVersionFromInstallFolder(PCUAE_INSTALL_NAME);
if (isNewVersionAvailable())
{
askAndStartDownload(pcuaeLatestInInstallFolder.isEmpty());
}
else
{
askToInstallExistingVersion();
}
}
private void askAndStartDownload(boolean firstDownload)
{
PCUAEVersionDownloadDialog dialog = new PCUAEVersionDownloadDialog(MainWindow.getInstance(), firstDownload);
dialog.pack();
dialog.setLocationRelativeTo(MainWindow.getInstance());
if (dialog.showDialog())
{
downloadLatestPCUAE();
}
else if (!firstDownload)
{
askToInstallExistingVersion();
}
}
private void askToInstallExistingVersion()
{
int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(),
"Do you want to install PCUAE (" + pcuaeLatestInInstallFolder + ") now?",
"Install PCUAE",
JOptionPane.YES_NO_OPTION);
if (value == JOptionPane.YES_OPTION)
{
singleThreadExecutor.execute(() -> runAndWaitForInstallation(pcuaeLatestInInstallFolder));
}
}
private boolean isNewVersionAvailable()
{
gitHubReleaseInformation = fetchLatestVersionFromGithub(PCUAE_INSTALL_NAME);
return ManagerVersionChecker.getIntVersion(pcuaeLatestInInstallFolder) < ManagerVersionChecker
.getIntVersion(gitHubReleaseInformation.getInstallFile());
}
@Override
protected void executeAfterInstallation()
{
SwingUtilities.invokeLater(() -> exportMenuItem.doClick());
}
private void downloadLatestPCUAE()
{
DownloadDialog progressDialog =
new DownloadDialog("Downloading PCUAE version " + gitHubReleaseInformation.getLatestVersion());
singleThreadExecutor.execute(() -> startDownload(progressDialog, gitHubReleaseInformation));
progressDialog.pack();
progressDialog.setLocationRelativeTo(MainWindow.getInstance());
if (progressDialog.showDialog())
{
pcuaeLatestInInstallFolder = gitHubReleaseInformation.getInstallFile();
int value = JOptionPane.showConfirmDialog(MainWindow.getInstance(),
"Download completed, do you want to install PCUAE " +
gitHubReleaseInformation.getLatestVersion() + " now?",
"Download Complete",
JOptionPane.YES_NO_OPTION);
if (value == JOptionPane.YES_OPTION)
{
singleThreadExecutor.execute(() -> runAndWaitForInstallation(pcuaeLatestInInstallFolder));
}
}
else
{
cleanupInterruptedDownload(gitHubReleaseInformation.getInstallFile());
}
}
public static String getLatestInInstallFolder()
{
return pcuaeLatestInInstallFolder;
}
public static String getLatestVersion()
{
return gitHubReleaseInformation.getLatestVersion();
}
public static String getDownloadUrl()
{
return gitHubReleaseInformation.getDownloadUrl();
}
}

View File

@ -15,10 +15,15 @@ import java.nio.file.StandardCopyOption;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
@ -29,6 +34,7 @@ import se.lantz.gui.download.DownloadDialog;
public class ManagerVersionChecker public class ManagerVersionChecker
{ {
private static final Logger logger = LoggerFactory.getLogger(FileManager.class);
public static final String TEMP_FOLDER = "./temp/"; public static final String TEMP_FOLDER = "./temp/";
private static String latestVersion = ""; private static String latestVersion = "";
private static String tagloadUrl = ""; private static String tagloadUrl = "";
@ -178,8 +184,31 @@ public class ManagerVersionChecker
public static boolean isNewVersionAvailable() public static boolean isNewVersionAvailable()
{ {
//Ignore all versions that starts with 1 logger.debug("Manifest version=" + FileManager.getPcuVersionFromManifest());
return !latestVersion.startsWith("1") && !FileManager.getPcuVersionFromManifest().equals(latestVersion); //Ignore versions starting with 1, the comparison does not work well with that.
//Once 2.x is available it will be calculated correctly
if (latestVersion.startsWith("1"))
{
return false;
}
return getIntVersion(FileManager.getPcuVersionFromManifest()) < getIntVersion(latestVersion);
}
public static int getIntVersion(String versionString)
{
//Regular expression to match digits in a string
String regex = "\\d+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(versionString);
String numbers = "";
while(matcher.find()) {
numbers = numbers + matcher.group();
}
if (numbers.isEmpty())
{
return 0;
}
return Integer.parseInt(numbers);
} }
public static String getLatestVersion() public static String getLatestVersion()