diff --git a/src/java/com/threerings/getdown/data/Application.java b/src/java/com/threerings/getdown/data/Application.java
index d491319..b52b500 100644
--- a/src/java/com/threerings/getdown/data/Application.java
+++ b/src/java/com/threerings/getdown/data/Application.java
@@ -1,5 +1,5 @@
//
-// $Id: Application.java,v 1.24 2004/07/30 02:23:52 mdb Exp $
+// $Id: Application.java,v 1.25 2004/07/30 21:45:28 mdb Exp $
package com.threerings.getdown.data;
@@ -65,7 +65,7 @@ public class Application
public Color progressBar = new Color(0x6699CC);
/** The dimensions of the status display. */
- public Rectangle status = new Rectangle(5, 25, 300, 100);
+ public Rectangle status = new Rectangle(5, 25, 500, 100);
/** The color of the status text. */
public Color statusText = Color.black;
@@ -105,7 +105,7 @@ public class Application
try {
return createResource(CONFIG_FILE);
} catch (Exception e) {
- throw new RuntimeException("Booched appbase '" + _vappbase + "'!?");
+ throw new RuntimeException("Invalid appbase '" + _vappbase + "'.");
}
}
diff --git a/src/java/com/threerings/getdown/launcher/Getdown.java b/src/java/com/threerings/getdown/launcher/Getdown.java
index 6330fe1..16e6029 100644
--- a/src/java/com/threerings/getdown/launcher/Getdown.java
+++ b/src/java/com/threerings/getdown/launcher/Getdown.java
@@ -1,5 +1,5 @@
//
-// $Id: Getdown.java,v 1.27 2004/07/30 18:14:21 mdb Exp $
+// $Id: Getdown.java,v 1.28 2004/07/30 21:45:28 mdb Exp $
package com.threerings.getdown.launcher;
@@ -21,9 +21,12 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.net.HttpURLConnection;
import java.net.URL;
+
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.ResourceBundle;
@@ -37,6 +40,7 @@ import com.threerings.getdown.Log;
import com.threerings.getdown.data.Application;
import com.threerings.getdown.data.Resource;
import com.threerings.getdown.tools.Patcher;
+import com.threerings.getdown.util.ConfigUtil;
import com.threerings.getdown.util.ProgressObserver;
import com.threerings.getdown.util.ProxyUtil;
@@ -78,6 +82,177 @@ public class Getdown extends Thread
return;
}
+ try {
+ _dead = false;
+ if (detectProxy()) {
+ getdown();
+ } else {
+ // create a panel they can use to configure the proxy settings
+ _frame.getContentPane().removeAll();
+ _frame.getContentPane().add(
+ new ProxyPanel(this, _msgs), BorderLayout.CENTER);
+ _frame.pack();
+ SwingUtil.centerWindow(_frame);
+ _frame.show();
+ // allow them to close the window to abort the proxy
+ // configuration
+ _dead = true;
+ }
+
+ } catch (Exception e) {
+ Log.logStackTrace(e);
+ String msg = e.getMessage();
+ if (msg == null) {
+ msg = "m.unknown_error";
+ } else if (!msg.startsWith("m.")) {
+ // try to do something sensible based on the type of error
+ if (e instanceof FileNotFoundException) {
+ msg = MessageUtil.tcompose("m.missing_resource", msg);
+ } else {
+ msg = MessageUtil.tcompose("m.init_error", msg);
+ }
+ }
+ updateStatus(msg);
+ _dead = true;
+ }
+ }
+
+ /**
+ * Configures our proxy settings (called by {@link ProxyPanel}) and
+ * fires up the launcher.
+ */
+ public void configureProxy (String host, String port)
+ {
+ Log.info("User configured proxy [host=" + host +
+ ", port=" + port + "].");
+
+ // if we're provided with valid values, create a proxy.txt file
+ if (!StringUtil.blank(host)) {
+ File pfile = _app.getLocalPath("proxy.txt");
+ try {
+ PrintStream pout = new PrintStream(new FileOutputStream(pfile));
+ pout.println("host = " + host);
+ if (!StringUtil.blank(port)) {
+ pout.println("port = " + port);
+ }
+ pout.close();
+ } catch (IOException ioe) {
+ Log.warning("Error creating proxy file '" + pfile +
+ "': " + ioe);
+ }
+
+ // also configure them in the JVM
+ System.setProperty("http.proxyHost", host);
+ if (!StringUtil.blank(port)) {
+ System.setProperty("http.proxyPort", port);
+ }
+ }
+
+ // clear out our UI
+ _frame.dispose();
+ _status = null;
+ _frame = null;
+
+ // fire up a new thread
+ new Thread(this).start();
+ }
+
+ /**
+ * Reads and/or autodetects our proxy settings.
+ *
+ * @return true if we should proceed with running the launcher, false
+ * if we need to wait for the user to enter proxy settings.
+ */
+ protected boolean detectProxy ()
+ {
+ // we may already have a proxy configured
+ if (System.getProperty("http.proxyHost") != null) {
+ return true;
+ }
+
+ // TODO: look in the Vinders registry
+
+ // otherwise look for and read our proxy.txt file
+ File pfile = _app.getLocalPath("proxy.txt");
+ if (pfile.exists()) {
+ try {
+ HashMap pconf = ConfigUtil.parseConfig(pfile, false);
+ String proxyHost = (String)pconf.get("host");
+ String proxyPort = (String)pconf.get("port");
+ if (!StringUtil.blank(proxyHost)) {
+ System.setProperty("http.proxyHost", proxyHost);
+ if (!StringUtil.blank(proxyPort)) {
+ System.setProperty("http.proxyPort", proxyPort);
+ }
+ Log.info("Using proxy [host=" + proxyHost +
+ ", port=" + proxyPort + "].");
+ }
+
+ // now we can get on with getting down
+ return true;
+
+ } catch (IOException ioe) {
+ Log.warning("Failed to read '" + pfile + "': " + ioe);
+ }
+ }
+
+ // otherwise we'll need to try to detect our proxy settings; first
+ // we have to initialize our application to get some sort of
+ // interface configuration and the appbase URL
+ Log.info("Attempting to detect proxy settings...");
+ try {
+ _ifc = _app.init(true);
+ } catch (IOException ioe) {
+ // no worries
+ }
+ updateStatus("m.detecting_proxy");
+
+ URL rurl = _app.getConfigResource().getRemote();
+ try {
+ // try to make a HEAD request for this URL
+ HttpURLConnection ucon = (HttpURLConnection)
+ rurl.openConnection();
+ ucon.setRequestMethod("HEAD");
+ ucon.connect();
+
+ // make sure we got a satisfactory response code
+ if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.warning("Got a non-200 response but assuming we're OK " +
+ "because we got something... [url=" + rurl +
+ ", rsp=" + ucon.getResponseCode() + "].");
+ }
+
+ // we got through, so we appear not to require a proxy; make a
+ // blank proxy config and get on gettin' down
+ Log.info("No proxy appears to be needed.");
+ try {
+ pfile.createNewFile();
+ } catch (IOException ioe) {
+ Log.warning("Failed to create blank proxy file '" +
+ pfile + "': " + ioe);
+ }
+ return true;
+
+ } catch (IOException ioe) {
+ Log.info("Failed to HEAD " + rurl + ": " + ioe);
+ Log.info("We probably need a proxy. Attempting to auto-detect...");
+ }
+
+ // let the caller know that we need a proxy but can't detect it
+ return false;
+ }
+
+ /**
+ * Does the actual application validation, update and launching
+ * business.
+ */
+ protected void getdown ()
+ {
+ Log.info("---------------- Proxy Info -----------------");
+ Log.info("-- Proxy Host: " + System.getProperty("http.proxyHost"));
+ Log.info("-- Proxy Port: " + System.getProperty("http.proxyPort"));
+ Log.info("---------------------------------------------");
+
try {
// first parses our application deployment file
try {
@@ -371,27 +546,15 @@ public class Getdown extends Thread
}
// pipe our output into a file in the application directory
- File log = new File(appDir, "launcher.log");
- try {
- FileOutputStream fout = new FileOutputStream(log);
- System.setOut(new PrintStream(fout));
- System.setErr(new PrintStream(fout));
- } catch (IOException ioe) {
- Log.warning("Unable to redirect output to '" + log + "': " + ioe);
- }
-
- // attempt to obtain our proxy information; it may be specified
- // via system properties or we can autodetect it
- if (System.getProperty("http.proxyHost") == null) {
+ if (System.getProperty("no_log_redir") == null) {
+ File log = new File(appDir, "launcher.log");
try {
- URL sample = new URL("http://www.threerings.net/");
- if (ProxyUtil.detectProxy(sample)) {
- String host = ProxyUtil.getProxyIP();
- String port = ProxyUtil.getProxyPort();
- ProxyUtil.configureProxy(host, port);
- }
- } catch (Exception e) {
- Log.warning("Failed to detect proxy: " + e);
+ FileOutputStream fout = new FileOutputStream(log);
+ System.setOut(new PrintStream(fout));
+ System.setErr(new PrintStream(fout));
+ } catch (IOException ioe) {
+ Log.warning("Unable to redirect output to '" + log +
+ "': " + ioe);
}
}
@@ -405,8 +568,6 @@ public class Getdown extends Thread
Log.info("-- User Name: " + System.getProperty("user.name"));
Log.info("-- User Home: " + System.getProperty("user.home"));
Log.info("-- Cur dir: " + System.getProperty("user.dir"));
- Log.info("-- Proxy Host: " + System.getProperty("http.proxyHost"));
- Log.info("-- Proxy Port: " + System.getProperty("http.proxyPort"));
Log.info("---------------------------------------------");
try {
diff --git a/src/java/com/threerings/getdown/launcher/ProxyPanel.java b/src/java/com/threerings/getdown/launcher/ProxyPanel.java
new file mode 100644
index 0000000..e0a6a71
--- /dev/null
+++ b/src/java/com/threerings/getdown/launcher/ProxyPanel.java
@@ -0,0 +1,139 @@
+//
+// $Id: ProxyPanel.java,v 1.1 2004/07/30 21:45:28 mdb Exp $
+
+package com.threerings.getdown.launcher;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import com.samskivert.swing.GroupLayout;
+import com.samskivert.swing.Spacer;
+import com.samskivert.swing.VGroupLayout;
+import com.samskivert.text.MessageUtil;
+
+import com.threerings.getdown.Log;
+
+/**
+ * Displays an interface with which the user can configure their proxy
+ * settings.
+ */
+public class ProxyPanel extends JPanel
+ implements ActionListener
+{
+ public ProxyPanel (Getdown getdown, ResourceBundle msgs)
+ {
+ _getdown = getdown;
+ _msgs = msgs;
+
+ setLayout(new VGroupLayout());
+ setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ add(new JLabel(get("m.configure_proxy")));
+ add(new Spacer(5, 5));
+
+ JPanel row = new JPanel(new BorderLayout(5, 5));
+ row.add(new JLabel(get("m.proxy_host")), BorderLayout.WEST);
+ row.add(_host = new SaneTextField());
+ add(row);
+
+ row = new JPanel(new BorderLayout(5, 5));
+ row.add(new JLabel(get("m.proxy_port")), BorderLayout.WEST);
+ row.add(_port = new SaneTextField());
+ add(row);
+
+ add(new Spacer(5, 5));
+ add(new JLabel(get("m.proxy_extra")));
+
+ row = GroupLayout.makeButtonBox(GroupLayout.CENTER);
+ JButton button;
+ row.add(button = new JButton(get("m.proxy_ok")));
+ button.setActionCommand("ok");
+ button.addActionListener(this);
+ row.add(button = new JButton(get("m.proxy_cancel")));
+ button.setActionCommand("cancel");
+ button.addActionListener(this);
+ add(row);
+
+ // set up any existing proxy defaults
+ String host = System.getProperty("http.proxyHost");
+ if (host != null) {
+ _host.setText(host);
+ }
+ String port = System.getProperty("http.proxyPort");
+ if (port != null) {
+ _port.setText(port);
+ }
+ }
+
+ // documentation inherited
+ public void addNotify ()
+ {
+ super.addNotify();
+ _host.requestFocusInWindow();
+ }
+
+ // documentation inherited
+ public Dimension getPreferredSize ()
+ {
+ // this is annoyingly hardcoded, but we can't just force the width
+ // or the JLabel will claim a bogus height thinking it can lay its
+ // text out all on one line which will booch the whole UI's
+ // preferred size
+ return new Dimension(500, 350);
+ }
+
+ // documentation inherited from interface
+ public void actionPerformed (ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("ok")) {
+ // communicate this info back to getdown
+ _getdown.configureProxy(_host.getText(), _port.getText());
+
+ } else {
+ // they canceled, we're outta here
+ System.exit(0);
+ }
+ }
+
+ /** Used to look up localized messages. */
+ protected String get (String key)
+ {
+ // if this string is tainted, we don't translate it, instead we
+ // simply remove the taint character and return it to the caller
+ if (key.startsWith(MessageUtil.TAINT_CHAR)) {
+ return key.substring(1);
+ }
+ try {
+ return _msgs.getString(key);
+ } catch (MissingResourceException mre) {
+ Log.warning("Missing translation message '" + key + "'.");
+ return key;
+ }
+ }
+
+ protected static class SaneTextField extends JTextField
+ {
+ public Dimension getPreferredSize () {
+ Dimension d = super.getPreferredSize();
+ d.width = Math.max(d.width, 150);
+ return d;
+ }
+ }
+
+ protected Getdown _getdown;
+ protected ResourceBundle _msgs;
+
+ protected JTextField _host;
+ protected JTextField _port;
+}
diff --git a/src/java/com/threerings/getdown/messages.properties b/src/java/com/threerings/getdown/messages.properties
index ad7327c..03b8118 100644
--- a/src/java/com/threerings/getdown/messages.properties
+++ b/src/java/com/threerings/getdown/messages.properties
@@ -1,8 +1,29 @@
#
-# $Id: messages.properties,v 1.6 2004/07/26 18:05:55 mdb Exp $
+# $Id: messages.properties,v 1.7 2004/07/30 21:45:28 mdb Exp $
#
# Getdown translation messages
+m.detecting_proxy = Trying to auto-detect proxy settings...
+
+m.configure_proxy = We were unable to connect to our servers to \
+ download the game data. This may be because your computer accesses the \
+ Internet through a proxy and we were unable to automatically detect your \
+ proxy settings. If you know your proxy settings, you can enter them \
+ below.
+
+m.proxy_extra = If you are sure that you don't use a proxy then \
+ perhaps there is a temporary Internet outage that is preventing us from \
+ communicating with the servers. In this case, you can cancel and try \
+ installing again later.
\
+ If you are not sure whether or not you are using a proxy, please visit \
+ the support section of our website to find instructions on how to \
+ determine your proxy settings.
+
+m.proxy_host = Proxy IP
+m.proxy_port = Proxy port
+m.proxy_ok = OK
+m.proxy_cancel = Cancel
+
m.resolving = Resolving downloads...
m.downloading = Downloading data...
m.failure = Download failed: {0}