From 7e61bbdf9080546cd12ecf105d7ac53b82937f31 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 14 Mar 2007 02:05:22 +0000 Subject: [PATCH] Added support for requesting external tracking URLs during the download process. This will replace the flaky Applet -> JavaScript bridge but first needs some testing. --- .../threerings/getdown/data/Application.java | 45 ++++++++++ .../threerings/getdown/launcher/Getdown.java | 87 ++++++++++++++++++- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/src/java/com/threerings/getdown/data/Application.java b/src/java/com/threerings/getdown/data/Application.java index 1673a2c..ca9470b 100644 --- a/src/java/com/threerings/getdown/data/Application.java +++ b/src/java/com/threerings/getdown/data/Application.java @@ -54,6 +54,7 @@ import java.util.regex.Pattern; import com.samskivert.io.StreamUtil; import com.samskivert.text.MessageUtil; +import com.samskivert.util.ArrayIntSet; import com.samskivert.util.RunAnywhere; import com.samskivert.util.StringUtil; @@ -320,6 +321,36 @@ public class Application } } + /** + * Returns the URL to use to report an initial download event. Returns null if no tracking + * start URL was configured for this application. + * + * @param event the event to be reported: start, jvm_start, jvm_complete, complete. + */ + public URL getTrackingURL (String event) + { + try { + return _trackingURL == null ? null : new URL(_trackingURL + event); + } catch (MalformedURLException mue) { + Log.warning("Invalid tracking URL [path=" + _trackingURL + ", event=" + event + + ", error=" + mue + "]."); + return null; + } + } + + /** + * Returns the URL to request to report that we have reached the specified percentage of our + * initial download. Returns null if no tracking request was configured for the specified + * percentage. + */ + public URL getTrackingProgressURL (int percent) + { + if (_trackingPcts == null || !_trackingPcts.contains(percent)) { + return null; + } + return getTrackingURL("pct" + percent); + } + /** * Instructs the application to parse its getdown.txt configuration and prepare * itself for operation. The application base URL will be parsed first so that if there are @@ -410,6 +441,17 @@ public class Application _javaLocation = (String)javaloc; } + // determine whether we have any tracking configuration + _trackingURL = (String)cdata.get("tracking_url"); + + // check for tracking progress percent configuration + String trackPcts = (String)cdata.get("tracking_percents"); + if (!StringUtil.isBlank(trackPcts)) { + _trackingPcts = new ArrayIntSet(StringUtil.parseIntArray(trackPcts)); + } else if (!StringUtil.isBlank(_trackingURL)) { + _trackingPcts = new ArrayIntSet(new int[] { 50 }); + } + // clear our arrays as we may be reinitializing _codes.clear(); _resources.clear(); @@ -1039,6 +1081,9 @@ public class Application protected boolean _windebug; protected boolean _useTorrent = false; + protected String _trackingURL; + protected ArrayIntSet _trackingPcts; + protected int _javaVersion; protected String _javaLocation; diff --git a/src/java/com/threerings/getdown/launcher/Getdown.java b/src/java/com/threerings/getdown/launcher/Getdown.java index c4491c6..b2767c1 100644 --- a/src/java/com/threerings/getdown/launcher/Getdown.java +++ b/src/java/com/threerings/getdown/launcher/Getdown.java @@ -347,7 +347,12 @@ public abstract class Getdown extends Thread // download and install the necessary version of java, then loop back again and // reverify everything; if we can't download java; we'll throw an exception Log.info("Attempting to update Java VM..."); - updateJava(); + _enableTracking = true; // always track JVM downloads + try { + updateJava(); + } finally { + _enableTracking = false; + } continue; } @@ -369,9 +374,20 @@ public abstract class Getdown extends Thread return; } - // redownload any that are corrupt or invalid... - Log.info(failures.size() + " rsrcs require update."); - download(failures); + try { + int rcount = _app.getAllResources().size(); + _enableTracking = (failures.size() == rcount); + reportTrackingEvent("app_start", -1); + + // redownload any that are corrupt or invalid... + Log.info(failures.size() + " of " + rcount + " rsrcs require update."); + download(failures); + + reportTrackingEvent("app_complete", -1); + } finally { + _enableTracking = false; + } + // now we'll loop back and try it all again } @@ -416,11 +432,15 @@ public abstract class Getdown extends Thread throw new IOException("m.java_download_failed"); } + reportTrackingEvent("jvm_start", -1); + updateStatus("m.downloading_java"); ArrayList list = new ArrayList(); list.add(vmjar); download(list); + reportTrackingEvent("jvm_unpack", -1); + updateStatus("m.unpacking_java"); if (!vmjar.unpack()) { throw new IOException("m.java_unpack_failed"); @@ -452,6 +472,8 @@ public abstract class Getdown extends Thread } catch (Exception e) { Log.warning("Failed to regenerate .jsa dum file [error=" + e + "]."); } + + reportTrackingEvent("jvm_complete", -1); } /** @@ -529,6 +551,9 @@ public abstract class Getdown extends Thread public void downloadProgress (int percent, long remaining) { setStatus("m.downloading", percent, remaining, true); + if (percent > 0) { + reportTrackingEvent("progress", percent); + } if (percent == 100) { synchronized (lock) { lock.notify(); @@ -715,6 +740,28 @@ public abstract class Getdown extends Thread }); } + protected void reportTrackingEvent (String event, int progress) + { + if (!_enableTracking) { + return; + + } else if (progress > 0) { + // we need to make sure we do the right thing if we skip over progress levels + for (int ii = _reportedProgress+1; ii <= progress; ii++) { + URL url = _app.getTrackingProgressURL(progress); + if (url != null) { + new ProgressReporter(url).start(); + } + } + + } else { + URL url = _app.getTrackingURL(event); + if (url != null) { + new ProgressReporter(url).start(); + } + } + } + /** * Load the image at the path. Before trying the exact path/file specified * we will look to see if we can find a localized version by sticking a @@ -785,6 +832,35 @@ public abstract class Getdown extends Thread */ protected abstract void exit (int exitCode); + /** Used to fetch a progress report URL. */ + protected static class ProgressReporter extends Thread + { + public ProgressReporter (URL url) { + setDaemon(true); + _url = url; + } + + public void run () { + try { + HttpURLConnection ucon = (HttpURLConnection)_url.openConnection(); + ucon.connect(); + try { + if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK) { + Log.warning("Failed to report tracking event [url=" + _url + + ", rcode=" + ucon.getResponseCode() + "]."); + } + } finally { + ucon.disconnect(); + } + } catch (IOException ioe) { + Log.warning("Failed to report tracking event [url=" + _url + + ", error=" + ioe + "]."); + } + } + + protected URL _url; + } + /** Used to pass progress on to our user interface. */ protected ProgressObserver _progobs = new ProgressObserver() { public void progress (final int percent) { @@ -803,6 +879,9 @@ public abstract class Getdown extends Thread protected boolean _dead; protected long _startup; + protected boolean _enableTracking = true; + protected int _reportedProgress = 0; + /** The maximum number of resources that can be already present for bittorrent to be used. */ protected static final int MAX_TORRENT_VERIFIED_RESOURCES = 1;