Changeset 3497337


Ignore:
Timestamp:
Dec 26, 2010 12:37:51 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
824d5a0
Parents:
7ee7cbf
Message:
  • Update:
    • Change the UpdateHandler? to try all sources in a loop, rather than one, so the user need not retry manually
    • For each source, fetch the first 56 bytes and check the version before downloading the whole thing, so we need not wait for every host to have the latest before updating the news.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java

    r7ee7cbf r3497337  
    11package net.i2p.router.web;
    22
     3import java.io.ByteArrayInputStream;
     4import java.io.ByteArrayOutputStream;
    35import java.io.File;
    46import java.text.DecimalFormat;
    57import java.util.ArrayList;
     8import java.util.Collections;
    69import java.util.List;
    710import java.util.StringTokenizer;
     
    1619import net.i2p.util.I2PAppThread;
    1720import net.i2p.util.Log;
     21import net.i2p.util.PartialEepGet;
     22import net.i2p.util.VersionComparator;
    1823
    1924/**
    20  * <p>Handles the request to update the router by firing off an
    21  * {@link net.i2p.util.EepGet} call to download the latest signed update file
     25 * <p>Handles the request to update the router by firing one or more
     26 * {@link net.i2p.util.EepGet} calls to download the latest signed update file
    2227 * and displaying the status to anyone who asks.
    2328 * </p>
     
    126131        protected EepGet _get;
    127132        protected final DecimalFormat _pct = new DecimalFormat("0.0%");
     133        /** tells the listeners what mode we are in */
     134        private boolean _isPartial;
     135        /** set by the listeners on completion */
     136        private boolean _isNewer;
     137        private ByteArrayOutputStream _baos;
    128138
    129139        public UpdateRunner() {
     
    142152            _isRunning = false;
    143153        }
     154
     155        /**
     156         *  Loop through the entire list of update URLs.
     157         *  For each one, first get the version from the first 56 bytes and see if
     158         *  it is newer than what we are running now.
     159         *  If it is, get the whole thing.
     160         */
    144161        protected void update() {
    145             updateStatus("<b>" + _("Updating") + "</b>");
    146162            // TODO:
    147163            // Do a PartialEepGet on the selected URL, check for version we expect,
     
    150166            // Alternative: In bytesTransferred(), Check the data in the output file after
    151167            // we've received at least 56 bytes. Need a cancel() method in EepGet ?
    152             String updateURL = selectUpdateURL();
    153             if (_log.shouldLog(Log.DEBUG))
    154                 _log.debug("Selected update URL: " + updateURL);
     168
    155169            boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
    156170            String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    157171            int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
    158             try {
    159                 if (shouldProxy)
    160                     // 40 retries!!
    161                     _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
    162                 else
    163                     _get = new EepGet(_context, 1, _updateFile, updateURL, false);
    164                 _get.addStatusListener(UpdateRunner.this);
    165                 _get.fetch();
    166             } catch (Throwable t) {
    167                 _log.error("Error updating", t);
     172
     173            List<String> urls = getUpdateURLs();
     174            if (urls.isEmpty()) {
     175                // not likely, don't bother translating
     176                updateStatus("<b>Update source list is empty, cannot download update</b>");
     177                _log.log(Log.CRIT, "Update source list is empty - cannot download update");
     178                return;
     179            }
     180
     181            if (shouldProxy)
     182                _baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
     183            for (String updateURL : urls) {
     184                updateStatus("<b>" + _("Updating from {0}", linkify(updateURL)) + "</b>");
     185                if (_log.shouldLog(Log.DEBUG))
     186                    _log.debug("Selected update URL: " + updateURL);
     187
     188                // Check the first 56 bytes for the version
     189                if (shouldProxy) {
     190                    _isPartial = true;
     191                    _isNewer = false;
     192                    _baos.reset();
     193                    try {
     194                        // no retries
     195                        _get = new PartialEepGet(_context, proxyHost, proxyPort, _baos, updateURL, TrustedUpdate.HEADER_BYTES);
     196                        _get.addStatusListener(UpdateRunner.this);
     197                        _get.fetch();
     198                    } catch (Throwable t) {
     199                        _isNewer = false;
     200                    }
     201                    _isPartial = false;
     202                    if (!_isNewer)
     203                        continue;
     204                }
     205
     206                // Now get the whole thing
     207                try {
     208                    if (shouldProxy)
     209                        // 40 retries!!
     210                        _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
     211                    else
     212                        _get = new EepGet(_context, 1, _updateFile, updateURL, false);
     213                    _get.addStatusListener(UpdateRunner.this);
     214                    _get.fetch();
     215                } catch (Throwable t) {
     216                    _log.error("Error updating", t);
     217                }
     218                if (this.done)
     219                    break;
    168220            }
    169221        }
    170222       
     223        // EepGet Listeners below.
     224        // We use the same for both the partial and the full EepGet,
     225        // with a couple of adjustments depending on which mode.
     226
    171227        public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
     228            _isNewer = false;
    172229            if (_log.shouldLog(Log.DEBUG))
    173230                _log.debug("Attempt failed on " + url, cause);
     
    175232        }
    176233        public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
     234            if (_isPartial)
     235                return;
    177236            StringBuilder buf = new StringBuilder(64);
    178237            buf.append("<b>").append(_("Updating")).append("</b> ");
     
    187246        }
    188247        public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
     248            if (_isPartial) {
     249                // Compare version with what we have now
     250                String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
     251                boolean newer = (new VersionComparator()).compare(newVersion, RouterVersion.VERSION) > 0;
     252                if (!newer) {
     253                    updateStatus("<b>" + _("No new version found at {0}", linkify(url)) + "</b>");
     254                    if (_log.shouldLog(Log.WARN))
     255                        _log.warn("Found old version \"" + newVersion + "\" at " + url);
     256                }
     257                _isNewer = newer;
     258                return;
     259            }
     260            // Process the .sud/.su2 file
    189261            updateStatus("<b>" + _("Update downloaded") + "</b>");
    190262            TrustedUpdate up = new TrustedUpdate(_context);
     
    224296            } else {
    225297                _log.log(Log.CRIT, err + " from " + url);
    226                 updateStatus("<b>" + err + ' ' + _("from {0}", url) + " </b>");
     298                updateStatus("<b>" + err + ' ' + _("from {0}", linkify(url)) + " </b>");
    227299            }
    228300        }
    229301        public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
     302            _isNewer = false;
    230303            // don't display bytesTransferred as it is meaningless
    231             _log.log(Log.CRIT, "Update from " + url + " did not download completely (" +
     304            _log.error("Update from " + url + " did not download completely (" +
    232305                               bytesRemaining + " remaining after " + currentAttempt + " tries)");
    233306
    234             updateStatus("<b>" + _("Transfer failed") + "</b>");
     307            updateStatus("<b>" + _("Transfer failed from {0}", linkify(url)) + "</b>");
    235308        }
    236309        public void headerReceived(String url, int attemptNum, String key, String val) {}
     
    243316    }
    244317
    245     private String selectUpdateURL() {
     318    private List<String> getUpdateURLs() {
    246319        String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
    247320        StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
    248         List URLList = new ArrayList();
     321        List<String> URLList = new ArrayList();
    249322        while (tok.hasMoreTokens())
    250323            URLList.add(tok.nextToken().trim());
    251         int size = URLList.size();
    252         //_log.log(Log.DEBUG, "Picking update source from " + size + " candidates.");
    253         if (size <= 0) {
    254             _log.log(Log.CRIT, "Update source list is empty - cannot download update");
    255             return null;
    256         }
    257         int index = I2PAppContext.getGlobalContext().random().nextInt(size);
    258         _log.log(Log.DEBUG, "Picked update source " + index + ".");
    259         return (String) URLList.get(index);
     324        Collections.shuffle(URLList, _context.random());
     325        return URLList;
    260326    }
    261327   
    262328    protected void updateStatus(String s) {
    263329        _status = s;
     330    }
     331
     332    protected static String linkify(String url) {
     333        return "<a target=\"_blank\" href=\"" + url + "\"/>" + url + "</a>";
    264334    }
    265335
Note: See TracChangeset for help on using the changeset viewer.