Merge pull request #60 from runiter/master

Avoid corrupted resources when download is interrupted
This commit is contained in:
Michael Bayne
2016-11-04 16:54:26 -07:00
committed by GitHub
5 changed files with 73 additions and 6 deletions
@@ -35,6 +35,7 @@ public class Resource
_path = path;
_remote = remote;
_local = local;
_local_new = new File(local.toString() + "_new");
String lpath = _local.getPath();
_marker = new File(lpath + "v");
@@ -66,6 +67,11 @@ public class Resource
return _local;
}
public File getLocalNew ()
{
return _local_new;
}
/**
* Returns the location of the unpacked resource.
*/
@@ -106,7 +112,16 @@ public class Resource
public String computeDigest (MessageDigest md, ProgressObserver obs)
throws IOException
{
return computeDigest(_local, md, obs);
File file;
if (_local.toString().toLowerCase().endsWith(Application.CONFIG_FILE))
file = _local;
else {
if (_local_new.exists())
file = _local_new;
else
file = _local;
}
return computeDigest(file, md, obs);
}
/**
@@ -284,7 +299,7 @@ public class Resource
protected static boolean isJar (String path)
{
return path.endsWith(".jar");
return path.endsWith(".jar") || path.endsWith(".jar_new");
}
protected static boolean isPacked200Jar (String path)
@@ -294,7 +309,7 @@ public class Resource
protected String _path;
protected URL _remote;
protected File _local, _marker, _unpacked;
protected File _local, _local_new, _marker, _unpacked;
protected boolean _unpack, _isJar, _isPacked200Jar;
/** Used to sort the entries in a jar file. */
@@ -49,6 +49,10 @@ public class SysProps
return System.getProperty("silent") != null;
}
public static boolean install () {
return System.getProperty("no_install") == null;
}
/** If true, Getdown installs the app without ever bringing up a UI and then launches it.
* Usage: {@code -Dsilent=launch}. */
public static boolean launchInSilent () {
@@ -68,6 +68,7 @@ import com.threerings.getdown.net.HTTPDownloader;
import com.threerings.getdown.tools.Patcher;
import com.threerings.getdown.util.ConfigUtil;
import com.threerings.getdown.util.ConnectionUtil;
import com.threerings.getdown.util.FileUtil;
import com.threerings.getdown.util.LaunchUtil;
import com.threerings.getdown.util.ProgressAggregator;
import com.threerings.getdown.util.ProgressObserver;
@@ -100,6 +101,7 @@ public abstract class Getdown extends Thread
// If the silent property exists, install without bringing up any gui. If it equals
// launch, start the application after installing. Otherwise, just install and exit.
_silent = SysProps.silent();
_install = SysProps.install();
if (_silent) {
_launchInSilent = SysProps.launchInSilent();
}
@@ -410,6 +412,9 @@ public abstract class Getdown extends Thread
// we'll keep track of all the resources we unpack
Set<Resource> unpacked = new HashSet<Resource>();
toBeInstalledResouces = new ArrayList<Resource>();
readyToInstall = false;
//setStep(Step.START);
for (int ii = 0; ii < MAX_LOOPS; ii++) {
// if we aren't running in a JVM that meets our version requirements, either
@@ -442,6 +447,7 @@ public abstract class Getdown extends Thread
setStep(Step.VERIFY_RESOURCES);
setStatusAsync("m.validating", -1, -1L, false);
List<Resource> failures = _app.verifyResources(_progobs, alreadyValid, unpacked);
addToBeInstalledResources(failures);
if (failures == null) {
log.info("Resources verified.");
@@ -471,6 +477,10 @@ public abstract class Getdown extends Thread
}
}
readyToInstall = true;
if (_install)
install();
// Only launch if we aren't in silent mode. Some mystery program starting out
// of the blue would be disconcerting.
if (!_silent || _launchInSilent) {
@@ -531,7 +541,16 @@ public abstract class Getdown extends Thread
}
}
// documentation inherited from interface
private void addToBeInstalledResources(List<Resource> resources) {
if (resources == null)
return;
else
for (Resource r : resources)
if (!toBeInstalledResouces.contains(r))
toBeInstalledResouces.add(r);
}
// documentation inherited from interface
public void updateStatus (String message)
{
setStatusAsync(message, -1, -1L, true);
@@ -755,6 +774,31 @@ public abstract class Getdown extends Thread
}
}
public static void install ()
throws IOException, InterruptedException
{
if (readyToInstall) {
log.info("Installing downloaded resources:");
for (Resource resource : toBeInstalledResouces) {
log.info(resource);
if (!FileUtil.renameTo(resource.getLocalNew(), resource.getLocal()))
throw new IOException("Failed to rename(" + resource.getLocalNew() + ", " + resource.getLocal() + ")");
if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped");
}
}
toBeInstalledResouces.clear();
readyToInstall = false;
log.info("Install completed.");
} else {
log.info("Nothing to install.");
}
}
public static boolean isUpdateAvailable() {
return readyToInstall && !toBeInstalledResouces.isEmpty();
}
/**
* Called to launch the application if everything is determined to be ready to go.
*/
@@ -1219,6 +1263,7 @@ public abstract class Getdown extends Thread
protected boolean _dead;
protected boolean _silent;
protected boolean _install;
protected boolean _launchInSilent;
protected long _startup;
@@ -1239,4 +1284,6 @@ public abstract class Getdown extends Thread
protected static final long PLAY_AGAIN_TIME = 3000L;
protected static final String PROXY_REGISTRY =
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
protected static List<Resource> toBeInstalledResouces;
protected static boolean readyToInstall;
}
@@ -78,7 +78,7 @@ public class HTTPDownloader extends Downloader
long currentSize = 0L;
try {
in = conn.getInputStream();
out = new FileOutputStream(rsrc.getLocal());
out = new FileOutputStream(rsrc.getLocalNew());
int read;
// TODO: look to see if we have a download info file
@@ -60,6 +60,7 @@ public class FileUtil extends com.samskivert.util.FileUtil
fin = new FileInputStream(source);
fout = new FileOutputStream(dest);
StreamUtil.copy(fin, fout);
fin.close(); // needed otherwise cannot delete source
if (!source.delete()) {
log.warning("Failed to delete " + source +
" after brute force copy to " + dest + ".");