I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit ebe7f3b1 authored by zzz's avatar zzz
Browse files

UI adjustments when no metainfo yet

parent 76029992
No related branches found
No related tags found
No related merge requests found
......@@ -531,6 +531,7 @@ public class Snark
// single torrent
acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
}
// TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator?
trackerclient = new TrackerClient(_util, meta, coordinator, this);
}
......@@ -781,8 +782,11 @@ public class Snark
public long getNeeded() {
if (storage != null)
return storage.needed();
// FIXME else return metainfo length if available
return -1;
if (meta != null)
// FIXME subtract chunks we have
return meta.getTotalLength();
// FIXME fake
return 16 * 16 * 1024;
}
/**
......
......@@ -20,6 +20,7 @@ import java.util.Collection;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
......@@ -34,6 +35,8 @@ public class SnarkManager implements Snark.CompleteListener {
/** map of (canonical) filename of the .torrent file to Snark instance (unsynchronized) */
private final Map<String, Snark> _snarks;
/** used to prevent DirMonitor from deleting torrents that don't have a torrent file yet */
private final Set<String> _magnets;
private final Object _addSnarkLock;
private /* FIXME final FIXME */ File _configFile;
private Properties _config;
......@@ -72,6 +75,7 @@ public class SnarkManager implements Snark.CompleteListener {
public static final int DEFAULT_STARTUP_DELAY = 3;
private SnarkManager() {
_snarks = new HashMap();
_magnets = new ConcurrentHashSet();
_addSnarkLock = new Object();
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(SnarkManager.class);
......@@ -90,8 +94,6 @@ public class SnarkManager implements Snark.CompleteListener {
_running = true;
_peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util);
int minutes = getStartupDelayMinutes();
_messages.add(_("Adding torrents in {0} minutes", minutes));
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start();
_context.addShutdownTask(new SnarkManagerShutdown());
......@@ -321,7 +323,7 @@ public class SnarkManager implements Snark.CompleteListener {
_util.setStartupDelay(minutes);
changed = true;
_config.setProperty(PROP_STARTUP_DELAY, "" + minutes);
addMessage(_("Startup delay limit changed to {0} minutes", minutes));
addMessage(_("Startup delay changed to {0}", DataHelper.formatDuration2(minutes * 60 * 1000)));
}
}
......@@ -549,6 +551,7 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage(rejectMessage);
return;
} else {
// TODO load saved closest DHT nodes and pass to the Snark ?
torrent = new Snark(_util, filename, null, -1, null, null, this,
_peerCoordinatorSet, _connectionAcceptor,
false, dataDir.getPath());
......@@ -583,6 +586,7 @@ public class SnarkManager implements Snark.CompleteListener {
*
* @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash
* @throws RuntimeException via Snark.fatal()
* @since 0.8.4
*/
public void addMagnet(String name, byte[] ih) {
......@@ -590,7 +594,8 @@ public class SnarkManager implements Snark.CompleteListener {
_peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath());
// TODO tell the dir monitor not to delete us
// Tell the dir monitor not to delete us
_magnets.add(name);
synchronized (_snarks) {
_snarks.put(name, torrent);
}
......@@ -608,12 +613,17 @@ public class SnarkManager implements Snark.CompleteListener {
}
/**
* Delete a torrent with the info hash alone (magnet / maggot)
* Stop and delete a torrent running in magnet mode
*
* @param ih 20 byte info hash
* @param snark a torrent with a fake file name ("Magnet xxxx")
* @since 0.8.4
*/
public void deleteMagnet(byte[] ih) {
public void deleteMagnet(Snark snark) {
synchronized (_snarks) {
_snarks.remove(snark.getName());
}
snark.stopTorrent();
_magnets.remove(snark.getName());
}
/**
......@@ -748,6 +758,8 @@ public class SnarkManager implements Snark.CompleteListener {
_config.remove(prop);
}
// TODO save closest DHT nodes too
saveConfig();
}
......@@ -828,6 +840,23 @@ public class SnarkManager implements Snark.CompleteListener {
}
return torrent;
}
/**
* Stop the torrent, leaving it on the list of torrents unless told to remove it
* @since 0.8.4
*/
public void stopTorrent(Snark torrent, boolean shouldRemove) {
if (shouldRemove) {
synchronized (_snarks) {
_snarks.remove(torrent.getName());
}
}
boolean wasStopped = torrent.isStopped();
torrent.stopTorrent();
if (!wasStopped)
addMessage(_("Torrent stopped: \"{0}\"", torrent.getBaseName()));
}
/**
* Stop the torrent and delete the torrent file itself, but leaving the data
* behind.
......@@ -846,11 +875,16 @@ public class SnarkManager implements Snark.CompleteListener {
private class DirMonitor implements Runnable {
public void run() {
try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {}
// the first message was a "We are starting up in 1m"
synchronized (_messages) {
if (_messages.size() == 1)
_messages.remove(0);
// don't bother delaying if auto start is false
long delay = 60 * 1000 * getStartupDelayMinutes();
if (delay > 0 && shouldAutoStart()) {
_messages.add(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
// the first message was a "We are starting up in 1m"
synchronized (_messages) {
if (_messages.size() == 1)
_messages.remove(0);
}
}
// here because we need to delay until I2CP is up
......@@ -922,6 +956,8 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
}
// Don't remove magnet torrents that don't have a torrent file yet
existingNames.removeAll(_magnets);
// now lets see which ones have been removed...
for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
......@@ -975,12 +1011,12 @@ public class SnarkManager implements Snark.CompleteListener {
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
private static Map trackerMap = null;
private static Map<String, String> trackerMap = null;
/** sorted map of name to announceURL=baseURL */
public Map getTrackers() {
public Map<String, String> getTrackers() {
if (trackerMap != null) // only do this once, can't be updated while running
return trackerMap;
Map rv = new TreeMap();
Map<String, String> rv = new TreeMap();
String trackers = _config.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) )
trackers = _context.getProperty(PROP_TRACKERS);
......
......@@ -126,10 +126,9 @@ public class TrackerClient extends I2PAppThread
@Override
public void run()
{
String infoHash = urlencode(meta.getInfoHash());
String infoHash = urlencode(snark.getInfoHash());
String peerID = urlencode(snark.getID());
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
// Construct the list of trackers for this torrent,
// starting with the primary one listed in the metainfo,
......@@ -138,12 +137,18 @@ public class TrackerClient extends I2PAppThread
// the primary tracker, that we don't add it twice.
// todo: check for b32 matches as well
trackers = new ArrayList(2);
String primary = meta.getAnnounce();
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(meta.getAnnounce(), true));
String primary;
if (meta != null) {
primary = meta.getAnnounce();
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(meta.getAnnounce(), true));
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
}
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
primary = "";
}
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
List tlist = _util.getOpenTrackers();
if (tlist != null) {
for (int i = 0; i < tlist.size(); i++) {
......
......@@ -462,7 +462,7 @@ public class I2PSnarkServlet extends Default {
} else if (newURL.startsWith(MAGNET) || newURL.startsWith(MAGGOT)) {
addMagnet(newURL);
} else {
_manager.addMessage(_("Invalid URL - must start with http://, {0} or {1}", MAGNET, MAGGOT));
_manager.addMessage(_("Invalid URL: Must start with \"http://\", \"{0}\", or \"{1}\"", MAGNET, MAGGOT));
}
} else {
// no file or URL specified
......@@ -476,7 +476,7 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next();
Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, false);
_manager.stopTorrent(snark, false);
break;
}
}
......@@ -506,13 +506,14 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next();
Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, true);
MetaInfo meta = snark.getMetaInfo();
if (meta == null) {
// magnet
_manager.deleteMagnet(snark.getInfoHash());
// magnet - remove and delete are the same thing
_manager.deleteMagnet(snark);
_manager.addMessage(_("Magnet deleted: {0}", name));
return;
}
_manager.stopTorrent(snark, true);
// should we delete the torrent file?
// yeah, need to, otherwise it'll get autoadded again (at the moment
File f = new File(name);
......@@ -532,13 +533,14 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next();
Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, true);
MetaInfo meta = snark.getMetaInfo();
if (meta == null) {
// magnet
_manager.deleteMagnet(snark.getInfoHash());
// magnet - remove and delete are the same thing
_manager.deleteMagnet(snark);
_manager.addMessage(_("Magnet deleted: {0}", name));
return;
}
_manager.stopTorrent(snark, true);
File f = new File(name);
f.delete();
_manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath()));
......@@ -635,7 +637,7 @@ public class I2PSnarkServlet extends Default {
for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i);
if (!snark.isStopped())
_manager.stopTorrent(snark.getName(), false);
_manager.stopTorrent(snark, false);
}
if (_manager.util().connected()) {
// Give the stopped announces time to get out
......@@ -750,8 +752,9 @@ public class I2PSnarkServlet extends Default {
stats[5] += total;
MetaInfo meta = snark.getMetaInfo();
// isValid means isNotMagnet
boolean isValid = meta != null;
boolean singleFile = (!isValid) || meta.getFiles() == null;
boolean isMultiFile = isValid && meta.getFiles() != null;
String err = snark.getTrackerProblems();
int curPeers = snark.getPeerCount();
......@@ -776,7 +779,7 @@ public class I2PSnarkServlet extends Default {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
"<br>" + err;
}
} else if (remaining <= 0) {
} else if (remaining == 0) { // < 0 means no meta size yet
if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
......@@ -822,9 +825,12 @@ public class I2PSnarkServlet extends Default {
out.write("<td class=\"" + rowClass + "\">");
// temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash
String announce = meta.getAnnounce();
if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/")) {
String announce = null;
if (isValid)
announce = meta.getAnnounce();
if (announce != null && (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") ||
announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/"))) {
Map trackers = _manager.getTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
......@@ -849,13 +855,13 @@ public class I2PSnarkServlet extends Default {
out.write("</td>\n<td class=\"" + rowClass + "\">");
StringBuilder buf = null;
if (remaining == 0 || meta.getFiles() != null) {
if (remaining == 0 || isMultiFile) {
buf = new StringBuilder(128);
buf.append("<a href=\"").append(snark.getBaseName());
if (meta.getFiles() != null)
if (isMultiFile)
buf.append('/');
buf.append("\" title=\"");
if (meta.getFiles() != null)
if (isMultiFile)
buf.append(_("View files"));
else
buf.append(_("Open file"));
......@@ -863,21 +869,24 @@ public class I2PSnarkServlet extends Default {
out.write(buf.toString());
}
String icon;
if (meta.getFiles() != null)
if (isMultiFile)
icon = "folder";
else
else if (isValid)
icon = toIcon(meta.getName());
if (remaining == 0 || meta.getFiles() != null) {
else
// todo get a nice magnet icon?
icon = "page_white";
if (remaining == 0 || isMultiFile) {
out.write(toImg(icon, _("Open")));
out.write("</a>");
} else {
out.write(toImg(icon));
}
out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">");
if (remaining == 0 || meta.getFiles() != null)
if (remaining == 0 || isMultiFile)
out.write(buf.toString());
out.write(filename);
if (remaining == 0 || meta.getFiles() != null)
if (remaining == 0 || isMultiFile)
out.write("</a>");
out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
......@@ -887,19 +896,21 @@ public class I2PSnarkServlet extends Default {
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0)
out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
else
else if (remaining == 0)
out.write(formatSize(total)); // 3GB
else
out.write("??"); // no meta size yet
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">");
if(isRunning)
if(isRunning && isValid)
out.write(formatSize(uploaded));
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if(isRunning && remaining > 0)
if(isRunning && remaining != 0)
out.write(formatSize(downBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if(isRunning)
if(isRunning && isValid)
out.write(formatSize(upBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
......@@ -919,7 +930,6 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("</a>");
} else {
if (isValid) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
......@@ -930,24 +940,25 @@ public class I2PSnarkServlet extends Default {
out.write("\">");
if (isDegraded)
out.write("</a>");
}
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
// Single quotes in translate strings with parameters must be doubled.
// Then the remaining single quite must be escaped
out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
out.write("')) { return false; }\"");
out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
out.write(_("Remove"));
out.write("\">");
if (isDegraded)
out.write("</a>");
if (isValid) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
// Single quotes in translate strings with parameters must be doubled.
// Then the remaining single quite must be escaped
out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
out.write("')) { return false; }\"");
out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
out.write(_("Remove"));
out.write("\">");
if (isDegraded)
out.write("</a>");
}
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
......@@ -1002,14 +1013,21 @@ public class I2PSnarkServlet extends Default {
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
float pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
if (pct == 100.0)
out.write(_("Seed"));
else {
String ps = String.valueOf(pct);
if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write(ps + "%");
float pct;
if (isValid) {
pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
if (pct == 100.0)
out.write(_("Seed"));
else {
String ps = String.valueOf(pct);
if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write(ps + "%");
}
} else {
pct = (float) 101.0;
// until we get the metainfo we don't know how many pieces there are
out.write("??");
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
......@@ -1031,7 +1049,7 @@ public class I2PSnarkServlet extends Default {
}
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
if (pct != 100.0) {
if (isValid && pct < 100.0) {
if (peer.isInterested() && !peer.isChoking()) {
out.write("<span class=\"unchoked\">");
out.write(formatSize(peer.getUploadRate()) + "ps</span>");
......@@ -1363,7 +1381,7 @@ public class I2PSnarkServlet extends Default {
_manager.addMessage(_("Invalid info hash in magnet URL {0}", url));
return;
}
_manager.addMagnet(ihash, ih);
_manager.addMagnet(name, ih);
}
/** copied from ConfigTunnelsHelper */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment