stub of a torrent updater

This commit is contained in:
zzz
2012-10-21 03:13:31 +00:00
parent 983537b0fd
commit 6331cb2374
3 changed files with 228 additions and 4 deletions

View File

@ -889,7 +889,27 @@ public class SnarkManager implements CompleteListener {
* @since 0.8.4
*/
public void addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus) {
Snark torrent = new Snark(_util, name, ih, trackerURL, this,
addMagnet(name, ih, trackerURL, updateStatus, shouldAutoStart(), this);
}
/**
* Add a torrent with the info hash alone (magnet / maggot)
* External use is for UpdateRunner.
*
* @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash
* @param trackerURL may be null
* @param updateStatus should we add this magnet to the config file,
* to save it across restarts, in case we don't get
* the metadata before shutdown?
* @param listener to intercept callbacks, should pass through to this
* @return the new Snark or null on failure
* @throws RuntimeException via Snark.fatal()
* @since 0.9.4
*/
public Snark addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus,
boolean autoStart, CompleteListener listener) {
Snark torrent = new Snark(_util, name, ih, trackerURL, listener,
_peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath());
@ -897,7 +917,7 @@ public class SnarkManager implements CompleteListener {
Snark snark = getTorrentByInfoHash(ih);
if (snark != null) {
addMessage(_("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return;
return null;
}
// Tell the dir monitor not to delete us
_magnets.add(name);
@ -905,7 +925,7 @@ public class SnarkManager implements CompleteListener {
saveMagnetStatus(ih);
_snarks.put(name, torrent);
}
if (shouldAutoStart()) {
if (autoStart) {
torrent.startTorrent();
addMessage(_("Fetching {0}", name));
DHT dht = _util.getDHT();
@ -918,7 +938,8 @@ public class SnarkManager implements CompleteListener {
}
} else {
addMessage(_("Adding {0}", name));
}
}
return torrent;
}
/**

View File

@ -0,0 +1,54 @@
package org.klomp.snark;
import java.net.URI;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.update.*;
/**
* <p>Handles the request to update the router by firing up a magnet.
* {@link net.i2p.util.EepGet} calls to download the latest signed update file
* and displaying the status to anyone who asks.
* </p>
* <p>After the download completes the signed update file is verified with
* {@link net.i2p.crypto.TrustedUpdate}, and if it's authentic the payload
* of the signed update file is unpacked and the router is restarted to complete
* the update process.
* </p>
*
* This does not do any checking, that is handled by the NewsFetcher.
*
* @since 0.9.4
*/
public class UpdateHandler implements Updater {
private final I2PAppContext _context;
private final UpdateManager _umgr;
private final SnarkManager _smgr;
public UpdateHandler(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr) {
_context = ctx;
_umgr = umgr;
_smgr = smgr;
}
/**
* Start a download and return a handle to the download task.
* Should not block.
*
* @param id plugin name or ignored
* @param maxTime how long you have
* @return active task or null if unable to download
*/
public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
String id, String newVersion, long maxTime) {
if (type != UpdateType.ROUTER_SIGNED ||
method != UpdateMethod.TORRENT || updateSources.isEmpty())
return null;
UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, updateSources, newVersion);
// set status before thread to ensure UI feedback
_umgr.notifyProgress(update, "<b>" + _smgr.util().getString("Updating") + "</b>");
update.start();
return update;
}
}

View File

@ -0,0 +1,149 @@
package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.crypto.TrustedUpdate;
import net.i2p.data.DataHelper;
import net.i2p.update.*;
import net.i2p.util.Log;
import net.i2p.util.VersionComparator;
/**
* The downloader for router signed updates.
*
* @since 0.9.4
*/
class UpdateRunner implements UpdateTask, CompleteListener {
private final I2PAppContext _context;
private final Log _log;
private final UpdateManager _umgr;
private final SnarkManager _smgr;
private final List<URI> _urls;
private final String _updateFile;
private volatile boolean _isRunning;
private final String _newVersion;
private ByteArrayOutputStream _baos;
private URI _currentURI;
private Snark _snark;
private static final long CONNECT_TIMEOUT = 55*1000;
private static final long INACTIVITY_TIMEOUT = 5*60*1000;
private static final long NOPROXY_INACTIVITY_TIMEOUT = 60*1000;
public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr,
List<URI> uris, String newVersion) {
_context = ctx;
_log = ctx.logManager().getLog(getClass());
_umgr = umgr;
_smgr = smgr;
_urls = uris;
_newVersion = newVersion;
_updateFile = (new File(ctx.getTempDir(), "update" + ctx.random().nextInt() + ".tmp")).getAbsolutePath();
}
//////// begin UpdateTask methods
public boolean isRunning() { return _isRunning; }
public void shutdown() {
_isRunning = false;
if (_snark != null) {
}
}
public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
public UpdateMethod getMethod() { return UpdateMethod.TORRENT; }
public URI getURI() { return _currentURI; }
public String getID() { return ""; }
//////// end UpdateTask methods
public void start() {
_isRunning = true;
update();
}
/**
* Loop through the entire list of update URLs.
* For each one, first get the version from the first 56 bytes and see if
* it is newer than what we are running now.
* If it is, get the whole thing.
*/
private void update() {
if (_urls.isEmpty()) {
_umgr.notifyTaskFailed(this, "", null);
return;
}
for (URI uri : _urls) {
_currentURI = uri;
String updateURL = uri.toString();
try {
MagnetURI magnet = new MagnetURI(_smgr.util(), updateURL);
String name = magnet.getName();
byte[] ih = magnet.getInfoHash();
String trackerURL = magnet.getTrackerURL();
_snark = _smgr.addMagnet(name, ih, trackerURL, true, true, this);
if (_snark != null) {
updateStatus("<b>" + _smgr.util().getString("Updating from {0}", updateURL) + "</b>");
break;
}
} catch (IllegalArgumentException iae) {}
}
if (_snark == null) {
_umgr.notifyTaskFailed(this, "", null);
_isRunning = false;
}
}
//////// begin CompleteListener methods
//////// all pass through to SnarkManager
public void torrentComplete(Snark snark) {
_smgr.torrentComplete(snark);
}
public void updateStatus(Snark snark) {
_smgr.updateStatus(snark);
}
public String gotMetaInfo(Snark snark) {
return _smgr.gotMetaInfo(snark);
}
public void fatal(Snark snark, String error) {
_smgr.fatal(snark, error);
}
public void addMessage(Snark snark, String message) {
_smgr.addMessage(snark, message);
}
public long getSavedTorrentTime(Snark snark) {
return _smgr.getSavedTorrentTime(snark);
}
public BitField getSavedTorrentBitField(Snark snark) {
return _smgr.getSavedTorrentBitField(snark);
}
//////// end CompleteListener methods
private void updateStatus(String s) {
_umgr.notifyProgress(this, s);
}
}