diff --git a/core/src/main/java/com/threerings/getdown/data/Application.java b/core/src/main/java/com/threerings/getdown/data/Application.java index 1a4729c..14f0ead 100644 --- a/core/src/main/java/com/threerings/getdown/data/Application.java +++ b/core/src/main/java/com/threerings/getdown/data/Application.java @@ -510,12 +510,12 @@ public class Application * discovered later, the caller can use the application base to download a new {@code * getdown.txt} file and try again. * - * @return a configured UpdateInterface instance that will be used to configure the update UI. + * @return a configured Config instance that contains information from the config file. * * @exception IOException thrown if there is an error reading the file or an error encountered * during its parsing. */ - public UpdateInterface init (boolean checkPlatform) + public Config init (boolean checkPlatform) throws IOException { Config config = null; @@ -672,6 +672,7 @@ public class Application parseResources(config, "resource", Resource.NORMAL, _resources); parseResources(config, "uresource", Resource.UNPACK, _resources); parseResources(config, "xresource", Resource.EXEC, _resources); + parseResources(config, "presource", Resource.PREDOWNLOAD, _resources); // parse our auxiliary resource groups for (String auxgroup : config.getList("auxgroups")) { @@ -719,6 +720,15 @@ public class Application // maximum simultaneous downloads _maxConcDownloads = Math.max(1, config.getInt("max_concurrent_downloads", 2)); + return config; + } + + /** + * Sets various properties using an UpdateInterface based on {@code config} + * @param config Information to base the UpdateInterface off + * @return a configured UpdateInterface instance that will be used to configure the update UI + */ + public UpdateInterface initUpdateInterface(Config config) { // parse and return our application config UpdateInterface ui = new UpdateInterface(config); _name = ui.name; @@ -1168,7 +1178,7 @@ public class Application clearValidationMarkers(); // if the new copy validates, reinitialize ourselves; otherwise report baffling hoseage if (_digest.validateResource(crsrc, null)) { - init(true); + initUpdateInterface(init(true)); } else { log.warning(CONFIG_FILE + " failed to validate even after redownloading. " + "Blindly forging onward."); diff --git a/core/src/main/java/com/threerings/getdown/data/Resource.java b/core/src/main/java/com/threerings/getdown/data/Resource.java index 6d222e7..5d75960 100644 --- a/core/src/main/java/com/threerings/getdown/data/Resource.java +++ b/core/src/main/java/com/threerings/getdown/data/Resource.java @@ -32,12 +32,15 @@ public class Resource implements Comparable /** Indicates that the resource should be unpacked. */ UNPACK, /** Indicates that the resource should be marked executable. */ - EXEC + EXEC, + /** Indicates that the resource should be downloaded before a UI is displayed. */ + PREDOWNLOAD }; public static final EnumSet NORMAL = EnumSet.noneOf(Attr.class); public static final EnumSet UNPACK = EnumSet.of(Attr.UNPACK); public static final EnumSet EXEC = EnumSet.of(Attr.EXEC); + public static final EnumSet PREDOWNLOAD = EnumSet.of(Attr.PREDOWNLOAD); /** * Computes the MD5 hash of the supplied file. @@ -198,6 +201,14 @@ public class Resource implements Comparable return _attrs.contains(Attr.UNPACK) && !SysProps.noUnpack(); } + /** + * Returns true if this resource should be predownloaded. + */ + public boolean shouldPredownload () + { + return _attrs.contains(Attr.PREDOWNLOAD); + } + /** * Computes the MD5 hash of this resource's underlying file. * Note: This is both CPU and I/O intensive. @@ -253,15 +264,26 @@ public class Resource implements Comparable /** * Installs the {@code getLocalNew} version of this resource to {@code getLocal}. + * @param validate Validate resource after installing? */ - public void install () throws IOException { + public void install (boolean validate) throws IOException { File source = getLocalNew(), dest = getLocal(); log.info("- " + source); if (!FileUtil.renameTo(source, dest)) { throw new IOException("Failed to rename " + source + " to " + dest); } applyAttrs(); - markAsValid(); + + if (validate){ + markAsValid(); + } + } + + /** + * Same as calling {@link #install(boolean)} with {@code true} + */ + public void install () throws IOException { + install(true); } /** diff --git a/core/src/main/java/com/threerings/getdown/tools/Differ.java b/core/src/main/java/com/threerings/getdown/tools/Differ.java index 87784f6..e8f2904 100644 --- a/core/src/main/java/com/threerings/getdown/tools/Differ.java +++ b/core/src/main/java/com/threerings/getdown/tools/Differ.java @@ -60,13 +60,13 @@ public class Differ } Application oapp = new Application(new EnvConfig(ovdir)); - oapp.init(false); + oapp.initUpdateInterface(oapp.init(false)); ArrayList orsrcs = new ArrayList<>(); orsrcs.addAll(oapp.getCodeResources()); orsrcs.addAll(oapp.getResources()); Application napp = new Application(new EnvConfig(nvdir)); - napp.init(false); + napp.initUpdateInterface(napp.init(false)); ArrayList nrsrcs = new ArrayList<>(); nrsrcs.addAll(napp.getCodeResources()); nrsrcs.addAll(napp.getResources()); diff --git a/core/src/main/java/com/threerings/getdown/tools/Digester.java b/core/src/main/java/com/threerings/getdown/tools/Digester.java index 9aad0cb..b36dedc 100644 --- a/core/src/main/java/com/threerings/getdown/tools/Digester.java +++ b/core/src/main/java/com/threerings/getdown/tools/Digester.java @@ -75,7 +75,7 @@ public class Digester // create our application and instruct it to parse its business Application app = new Application(new EnvConfig(appdir)); - app.init(false); + app.initUpdateInterface(app.init(false)); List rsrcs = new ArrayList<>(); rsrcs.add(app.getConfigResource()); diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java index 17368b1..277b7f4 100644 --- a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -33,8 +33,6 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; -import java.security.cert.Certificate; - import java.util.*; import ca.beq.util.win32.registry.RegistryKey; @@ -279,7 +277,9 @@ public abstract class Getdown extends Thread // to get some sort of interface configuration and the appbase URL log.info("Checking whether we need to use a proxy..."); try { - _ifc = _app.init(true); + Config config = _app.init(true); + doPredownloads(_app.getResources()); + _ifc = _app.initUpdateInterface(config); } catch (IOException ioe) { // no worries } @@ -339,6 +339,34 @@ public abstract class Getdown extends Thread } } + /** + * Finds resources from {@code resources} that have a {@code PREDOWNLOAD} attribute, + * then downloads and installs them (without verifying them) + * @param resources resources to predownload + */ + protected void doPredownloads (Collection resources) { + List predownloads = new ArrayList<>(); + + for(Resource rsrc: resources) { + if(rsrc.shouldPredownload() && !rsrc.getLocal().exists()) { + predownloads.add(rsrc); + } + } + + try { + download(predownloads); + + for(Resource rsrc: predownloads) { + // Install but don't validate yet + rsrc.install(false); + } + + } catch (IOException ioe) { + log.warning("Failed to predownload resources. Continuing...", ioe); + } + + } + /** * Does the actual application validation, update and launching business. */ @@ -352,15 +380,23 @@ public abstract class Getdown extends Thread try { // first parses our application deployment file try { - _ifc = _app.init(true); + Config config = _app.init(true); + doPredownloads(_app.getResources()); + _ifc = _app.initUpdateInterface(config); } catch (IOException ioe) { log.warning("Failed to initialize: " + ioe); _app.attemptRecovery(this); // and re-initalize - _ifc = _app.init(true); + Config config = _app.init(true); + doPredownloads(_app.getResources()); + _ifc = _app.initUpdateInterface(config); + // now force our UI to be recreated with the updated info createInterfaceAsync(true); + setIcons(); // Force icons to be displayed + } + if (!_app.lockForUpdates()) { throw new MultipleGetdownRunning(); } @@ -567,6 +603,12 @@ public abstract class Getdown extends Thread } } + /** + * Force app to (re)set icons + */ + protected abstract void setIcons(); + + /** * Downloads and installs an Java VM bundled with the application. This is called if we are not * running with the necessary Java version. @@ -678,7 +720,8 @@ public abstract class Getdown extends Thread // finally update our metadata files... _app.updateMetadata(); // ...and reinitialize the application - _ifc = _app.init(true); + Config config = _app.init(true); + _ifc = _app.initUpdateInterface(config); } /** diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java b/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java index 9c6a9fb..b47c087 100644 --- a/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java +++ b/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java @@ -24,7 +24,6 @@ import javax.swing.JFrame; import javax.swing.WindowConstants; import com.samskivert.swing.util.SwingUtil; -import com.threerings.getdown.data.Digest; import com.threerings.getdown.data.EnvConfig; import com.threerings.getdown.data.SysProps; import com.threerings.getdown.util.LaunchUtil; @@ -125,6 +124,15 @@ public class GetdownApp _frame.getContentPane().removeAll(); } + setIcons(); + + _frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + return _frame.getContentPane(); + } + + protected void setIcons() { + if(_frame == null) return; + if (_ifc.iconImages != null) { ArrayList icons = new ArrayList<>(); for (String path : _ifc.iconImages) { @@ -140,10 +148,9 @@ public class GetdownApp } else { _frame.setIconImages(icons); } + } else { + log.info("No icons found to load..."); } - - _frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - return _frame.getContentPane(); } @Override