From e18d279b3bb5f97c21ddae27958ab67923ab479e Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 30 Jul 2004 21:45:28 +0000 Subject: [PATCH] Further progress on proxy handling. The first time we run, we attempt to detect the need for a proxy and if there is a need, the actual settings. If we detect a need, but can't detect the proxy, we pop up a UI asking the user if they know what it might be. --- .../threerings/getdown/data/Application.java | 6 +- .../threerings/getdown/launcher/Getdown.java | 207 ++++++++++++++++-- .../getdown/launcher/ProxyPanel.java | 139 ++++++++++++ .../threerings/getdown/messages.properties | 23 +- 4 files changed, 348 insertions(+), 27 deletions(-) create mode 100644 src/java/com/threerings/getdown/launcher/ProxyPanel.java 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}