forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head d2198c4bc21a9d06194cdb2dce24945ebc9d1542)
to branch 'i2p.i2p.zzz.dhtsnark' (head 59fc0206608a5d1323a0acfbcb151d862fe95f95)
This commit is contained in:
@ -67,7 +67,7 @@ public class ConnectionAcceptor implements Runnable
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,7 +82,7 @@ public class ConnectionAcceptor implements Runnable
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
}
|
||||
|
||||
public void halt()
|
||||
@ -146,7 +146,7 @@ public class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
} else {
|
||||
if (socket.getPeerDestination().equals(_util.getMyDestination())) {
|
||||
_util.debug("Incoming connection from myself", Snark.ERROR);
|
||||
_log.error("Incoming connection from myself");
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
@ -163,13 +163,13 @@ public class ConnectionAcceptor implements Runnable
|
||||
catch (I2PException ioe)
|
||||
{
|
||||
if (!socketChanged) {
|
||||
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
}
|
||||
// catch oom?
|
||||
|
@ -124,6 +124,9 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
******/
|
||||
|
||||
/** @since 0.9.1 */
|
||||
public I2PAppContext getContext() { return _context; }
|
||||
|
||||
public boolean configured() { return _configured; }
|
||||
|
||||
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
|
||||
@ -314,7 +317,7 @@ public class I2PSnarkUtil {
|
||||
return rv;
|
||||
} catch (I2PException ie) {
|
||||
_shitlist.add(dest);
|
||||
SimpleScheduler.getInstance().addEvent(new Unshitlist(dest), 10*60*1000);
|
||||
_context.simpleScheduler().addEvent(new Unshitlist(dest), 10*60*1000);
|
||||
throw new IOException("Unable to reach the peer " + peer + ": " + ie.getMessage());
|
||||
}
|
||||
}
|
||||
@ -560,40 +563,6 @@ public class I2PSnarkUtil {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** hook between snark's logger and an i2p log */
|
||||
void debug(String msg, int snarkDebugLevel) {
|
||||
debug(msg, snarkDebugLevel, null);
|
||||
}
|
||||
void debug(String msg, int snarkDebugLevel, Throwable t) {
|
||||
if (t instanceof OutOfMemoryError) {
|
||||
try { Thread.sleep(100); } catch (InterruptedException ie) {}
|
||||
try {
|
||||
t.printStackTrace();
|
||||
} catch (Throwable tt) {}
|
||||
try {
|
||||
System.out.println("OOM thread: " + Thread.currentThread().getName());
|
||||
} catch (Throwable tt) {}
|
||||
}
|
||||
switch (snarkDebugLevel) {
|
||||
case 0:
|
||||
case 1:
|
||||
_log.error(msg, t);
|
||||
break;
|
||||
case 2:
|
||||
_log.warn(msg, t);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
_log.info(msg, t);
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
default:
|
||||
_log.debug(msg, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BUNDLE_NAME = "org.klomp.snark.web.messages";
|
||||
|
||||
/** lang in routerconsole.lang property, else current locale */
|
||||
|
@ -5,10 +5,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
import org.klomp.snark.bencode.BDecoder;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
@ -27,7 +27,6 @@ import org.klomp.snark.bencode.BEValue;
|
||||
*/
|
||||
class MagnetState {
|
||||
public static final int CHUNK_SIZE = 16*1024;
|
||||
private static final Random random = I2PAppContext.getGlobalContext().random();
|
||||
|
||||
private final byte[] infohash;
|
||||
private boolean complete;
|
||||
@ -129,7 +128,7 @@ class MagnetState {
|
||||
throw new IllegalArgumentException("not initialized");
|
||||
if (complete)
|
||||
throw new IllegalArgumentException("complete");
|
||||
int rand = random.nextInt(totalChunks);
|
||||
int rand = RandomSource.getInstance().nextInt(totalChunks);
|
||||
for (int i = 0; i < totalChunks; i++) {
|
||||
int chk = (i + rand) % totalChunks;
|
||||
if (!(have.get(chk) || requested.get(chk))) {
|
||||
|
@ -25,6 +25,8 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* TimerTask that checks for good/bad up/downloader. Works together
|
||||
@ -36,16 +38,18 @@ class PeerCheckerTask implements Runnable
|
||||
|
||||
private final PeerCoordinator coordinator;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final Log _log;
|
||||
private final Random random;
|
||||
private int _runCount;
|
||||
|
||||
PeerCheckerTask(I2PSnarkUtil util, PeerCoordinator coordinator)
|
||||
{
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(PeerCheckerTask.class);
|
||||
random = util.getContext().random();
|
||||
this.coordinator = coordinator;
|
||||
}
|
||||
|
||||
private static final Random random = I2PAppContext.getGlobalContext().random();
|
||||
|
||||
public void run()
|
||||
{
|
||||
_runCount++;
|
||||
@ -82,6 +86,14 @@ class PeerCheckerTask implements Runnable
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Disconnecting peer idle " +
|
||||
DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer);
|
||||
peer.disconnect();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!peer.isChoking())
|
||||
uploaders++;
|
||||
|
||||
@ -92,14 +104,15 @@ class PeerCheckerTask implements Runnable
|
||||
peer.setRateHistory(upload, download);
|
||||
peer.resetCounters();
|
||||
|
||||
_util.debug(peer + ":", Snark.DEBUG);
|
||||
_util.debug(" ul: " + upload*1024/KILOPERSECOND
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(peer + ":"
|
||||
+ " ul: " + upload*1024/KILOPERSECOND
|
||||
+ " dl: " + download*1024/KILOPERSECOND
|
||||
+ " i: " + peer.isInterested()
|
||||
+ " I: " + peer.isInteresting()
|
||||
+ " c: " + peer.isChoking()
|
||||
+ " C: " + peer.isChoked(),
|
||||
Snark.DEBUG);
|
||||
+ " C: " + peer.isChoked());
|
||||
}
|
||||
|
||||
// Choke a percentage of them rather than all so it isn't so drastic...
|
||||
// unless this torrent is over the limit all by itself.
|
||||
@ -120,8 +133,8 @@ class PeerCheckerTask implements Runnable
|
||||
// Check if it still wants pieces from us.
|
||||
if (!peer.isInterested())
|
||||
{
|
||||
_util.debug("Choke uninterested peer: " + peer,
|
||||
Snark.INFO);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Choke uninterested peer: " + peer);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@ -131,8 +144,8 @@ class PeerCheckerTask implements Runnable
|
||||
}
|
||||
else if (overBWLimitChoke)
|
||||
{
|
||||
_util.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer,
|
||||
Snark.INFO);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@ -144,7 +157,8 @@ class PeerCheckerTask implements Runnable
|
||||
else if (peer.isInteresting() && peer.isChoked())
|
||||
{
|
||||
// If they are choking us make someone else a downloader
|
||||
_util.debug("Choke choking peer: " + peer, Snark.DEBUG);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Choke choking peer: " + peer);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@ -156,7 +170,8 @@ class PeerCheckerTask implements Runnable
|
||||
else if (!peer.isInteresting() && !coordinator.completed())
|
||||
{
|
||||
// If they aren't interesting make someone else a downloader
|
||||
_util.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Choke uninteresting peer: " + peer);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@ -170,8 +185,8 @@ class PeerCheckerTask implements Runnable
|
||||
&& download == 0)
|
||||
{
|
||||
// We are downloading but didn't receive anything...
|
||||
_util.debug("Choke downloader that doesn't deliver:"
|
||||
+ peer, Snark.DEBUG);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Choke downloader that doesn't deliver: " + peer);
|
||||
peer.setChoking(true);
|
||||
uploaders--;
|
||||
coordinator.uploaders--;
|
||||
@ -198,7 +213,10 @@ class PeerCheckerTask implements Runnable
|
||||
// send PEX
|
||||
if ((_runCount % 17) == 0 && !peer.isCompleted())
|
||||
coordinator.sendPeers(peer);
|
||||
peer.keepAlive();
|
||||
// cheap failsafe for seeds connected to seeds, stop pinging and hopefully
|
||||
// the inactive checker (above) will eventually disconnect it
|
||||
if (coordinator.getNeededLength() > 0 || !peer.isCompleted())
|
||||
peer.keepAlive();
|
||||
// announce them to local tracker (TrackerClient does this too)
|
||||
if (_util.getDHT() != null && (_runCount % 5) == 0) {
|
||||
_util.getDHT().announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
@ -215,8 +233,8 @@ class PeerCheckerTask implements Runnable
|
||||
|| uploaders > uploadLimit)
|
||||
&& worstDownloader != null)
|
||||
{
|
||||
_util.debug("Choke worst downloader: " + worstDownloader,
|
||||
Snark.DEBUG);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Choke worst downloader: " + worstDownloader);
|
||||
|
||||
worstDownloader.setChoking(true);
|
||||
coordinator.uploaders--;
|
||||
|
@ -22,6 +22,7 @@ package org.klomp.snark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@ -68,6 +69,7 @@ class PeerCoordinator implements PeerListener
|
||||
// package local for access by CheckDownLoadersTask
|
||||
final static long CHECK_PERIOD = 40*1000; // 40 seconds
|
||||
final static int MAX_UPLOADERS = 6;
|
||||
public static final long MAX_INACTIVE = 8*60*1000;
|
||||
|
||||
/**
|
||||
* Approximation of the number of current uploaders.
|
||||
@ -130,7 +132,7 @@ class PeerCoordinator implements PeerListener
|
||||
private final MagnetState magnetState;
|
||||
private final CoordinatorListener listener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private static final Random _random = I2PAppContext.getGlobalContext().random();
|
||||
private final Random _random;
|
||||
|
||||
/**
|
||||
* @param metainfo null if in magnet mode
|
||||
@ -140,6 +142,7 @@ class PeerCoordinator implements PeerListener
|
||||
CoordinatorListener listener, Snark torrent)
|
||||
{
|
||||
_util = util;
|
||||
_random = util.getContext().random();
|
||||
this.id = id;
|
||||
this.infohash = infohash;
|
||||
this.metainfo = metainfo;
|
||||
@ -157,7 +160,7 @@ class PeerCoordinator implements PeerListener
|
||||
// Install a timer to check the uploaders.
|
||||
// Randomize the first start time so multiple tasks are spread out,
|
||||
// this will help the behavior with global limits
|
||||
timer = new CheckEvent(new PeerCheckerTask(_util, this));
|
||||
timer = new CheckEvent(_util.getContext(), new PeerCheckerTask(_util, this));
|
||||
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
|
||||
}
|
||||
|
||||
@ -167,8 +170,8 @@ class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
private static class CheckEvent extends SimpleTimer2.TimedEvent {
|
||||
private final PeerCheckerTask _task;
|
||||
public CheckEvent(PeerCheckerTask task) {
|
||||
super(SimpleTimer2.getInstance());
|
||||
public CheckEvent(I2PAppContext ctx, PeerCheckerTask task) {
|
||||
super(ctx.simpleTimer2());
|
||||
_task = task;
|
||||
}
|
||||
public void timeReached() {
|
||||
@ -377,8 +380,10 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce max if huge pieces to keep from ooming when leeching
|
||||
* @return 512K: 16; 1M: 11; 2M: 6
|
||||
* Formerly used to
|
||||
* reduce max if huge pieces to keep from ooming when leeching
|
||||
* but now we don't
|
||||
* @return usually 16
|
||||
*/
|
||||
private int getMaxConnections() {
|
||||
if (metainfo == null)
|
||||
@ -388,7 +393,7 @@ class PeerCoordinator implements PeerListener
|
||||
return 4;
|
||||
if (pieces <= 5)
|
||||
return 6;
|
||||
int size = metainfo.getPieceLength(0);
|
||||
//int size = metainfo.getPieceLength(0);
|
||||
int max = _util.getMaxConnections();
|
||||
// Now that we use temp files, no memory concern
|
||||
//if (size <= 512*1024 || completed())
|
||||
@ -434,6 +439,12 @@ class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
public void restart() {
|
||||
halted = false;
|
||||
synchronized (uploaded_old) {
|
||||
Arrays.fill(uploaded_old, 0);
|
||||
}
|
||||
synchronized (downloaded_old) {
|
||||
Arrays.fill(downloaded_old, 0);
|
||||
}
|
||||
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
|
||||
}
|
||||
|
||||
@ -449,7 +460,7 @@ class PeerCoordinator implements PeerListener
|
||||
synchronized(peers)
|
||||
{
|
||||
Peer old = peerIDInList(peer.getPeerID(), peers);
|
||||
if ( (old != null) && (old.getInactiveTime() > 8*60*1000) ) {
|
||||
if ( (old != null) && (old.getInactiveTime() > MAX_INACTIVE) ) {
|
||||
// idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
|
||||
@ -543,7 +554,7 @@ class PeerCoordinator implements PeerListener
|
||||
need_more = (!peer.isConnected()) && peersize < getMaxConnections();
|
||||
// Check if we already have this peer before we build the connection
|
||||
Peer old = peerIDInList(peer.getPeerID(), peers);
|
||||
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
|
||||
need_more = need_more && ((old == null) || (old.getInactiveTime() > MAX_INACTIVE));
|
||||
}
|
||||
|
||||
if (need_more)
|
||||
@ -974,11 +985,8 @@ class PeerCoordinator implements PeerListener
|
||||
|
||||
// Announce to the world we have it!
|
||||
// Disconnect from other seeders when we get the last piece
|
||||
List<Peer> toDisconnect = new ArrayList();
|
||||
Iterator<Peer> it = peers.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer p = it.next();
|
||||
List<Peer> toDisconnect = done ? new ArrayList() : null;
|
||||
for (Peer p : peers) {
|
||||
if (p.isConnected())
|
||||
{
|
||||
if (done && p.isCompleted())
|
||||
@ -986,15 +994,13 @@ class PeerCoordinator implements PeerListener
|
||||
else
|
||||
p.have(piece);
|
||||
}
|
||||
}
|
||||
it = toDisconnect.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Peer p = it.next();
|
||||
p.disconnect(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (done) {
|
||||
for (Peer p : toDisconnect) {
|
||||
p.disconnect(true);
|
||||
}
|
||||
|
||||
// put msg on the console if partial, since Storage won't do it
|
||||
if (!completed())
|
||||
snark.storageCompleted(storage);
|
||||
|
@ -35,6 +35,7 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Main Snark program startup class.
|
||||
@ -47,29 +48,6 @@ public class Snark
|
||||
private final static int MIN_PORT = 6881;
|
||||
private final static int MAX_PORT = 6889;
|
||||
|
||||
// Error messages (non-fatal)
|
||||
public final static int ERROR = 1;
|
||||
|
||||
// Warning messages
|
||||
public final static int WARNING = 2;
|
||||
|
||||
// Notices (peer level)
|
||||
public final static int NOTICE = 3;
|
||||
|
||||
// Info messages (protocol policy level)
|
||||
public final static int INFO = 4;
|
||||
|
||||
// Debug info (protocol level)
|
||||
public final static int DEBUG = 5;
|
||||
|
||||
// Very low level stuff (network level)
|
||||
public final static int ALL = 6;
|
||||
|
||||
/**
|
||||
* What level of debug info to show.
|
||||
*/
|
||||
//public static int debug = NOTICE;
|
||||
|
||||
// Whether or not to ask the user for commands while sharing
|
||||
//private static boolean command_interpreter = true;
|
||||
|
||||
@ -249,12 +227,13 @@ public class Snark
|
||||
private TrackerClient trackerclient;
|
||||
private String rootDataDir = ".";
|
||||
private final CompleteListener completeListener;
|
||||
private boolean stopped;
|
||||
private boolean starting;
|
||||
private volatile boolean stopped;
|
||||
private volatile boolean starting;
|
||||
private byte[] id;
|
||||
private final byte[] infoHash;
|
||||
private String additionalTrackerURL;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final Log _log;
|
||||
private final PeerCoordinatorSet _peerCoordinatorSet;
|
||||
private String trackerProblems;
|
||||
private int trackerSeenPeers;
|
||||
@ -308,6 +287,7 @@ public class Snark
|
||||
|
||||
completeListener = complistener;
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(Snark.class);
|
||||
_peerCoordinatorSet = peerCoordinatorSet;
|
||||
acceptor = connectionAcceptor;
|
||||
|
||||
@ -318,7 +298,8 @@ public class Snark
|
||||
activity = "Network setup";
|
||||
|
||||
id = generateID();
|
||||
debug("My peer id: " + PeerID.idencode(id), Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("My peer id: " + PeerID.idencode(id));
|
||||
|
||||
/*
|
||||
* Don't start a tunnel if the torrent isn't going to be started.
|
||||
@ -404,8 +385,8 @@ public class Snark
|
||||
try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
infoHash = x_infoHash; // final
|
||||
debug(meta.toString(), INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(meta.toString());
|
||||
|
||||
// When the metainfo torrent was created from an existing file/dir
|
||||
// it already exists.
|
||||
@ -466,6 +447,7 @@ public class Snark
|
||||
{
|
||||
completeListener = complistener;
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(Snark.class);
|
||||
_peerCoordinatorSet = peerCoordinatorSet;
|
||||
acceptor = connectionAcceptor;
|
||||
this.torrent = torrent;
|
||||
@ -533,9 +515,11 @@ public class Snark
|
||||
fatal("Unable to listen for I2P connections");
|
||||
else {
|
||||
Destination d = serversocket.getManager().getSession().getMyDestination();
|
||||
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64());
|
||||
}
|
||||
debug("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient", NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
|
||||
if (_peerCoordinatorSet != null) {
|
||||
@ -575,7 +559,8 @@ public class Snark
|
||||
}
|
||||
trackerclient.start();
|
||||
} else {
|
||||
debug("NOT starting TrackerClient???", NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("NOT starting TrackerClient???");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1019,22 +1004,13 @@ public class Snark
|
||||
private static void usage()
|
||||
{
|
||||
System.out.println
|
||||
("Usage: snark [--debug [level]] [--no-commands] [--port <port>]");
|
||||
("Usage: snark [--no-commands] [--port <port>]");
|
||||
System.out.println
|
||||
(" [--eepproxy hostname portnum]");
|
||||
System.out.println
|
||||
(" [--i2cp routerHost routerPort ['name=val name=val name=val']]");
|
||||
System.out.println
|
||||
(" (<url>|<file>)");
|
||||
System.out.println
|
||||
(" --debug\tShows some extra info and stacktraces");
|
||||
System.out.println
|
||||
(" level\tHow much debug details to show");
|
||||
System.out.println
|
||||
(" \t(defaults to "
|
||||
+ NOTICE + ", with --debug to "
|
||||
+ INFO + ", highest level is "
|
||||
+ ALL + ").");
|
||||
System.out.println
|
||||
(" --no-commands\tDon't read interactive commands or show usage info.");
|
||||
System.out.println
|
||||
@ -1073,7 +1049,7 @@ public class Snark
|
||||
*/
|
||||
private void fatal(String s, Throwable t)
|
||||
{
|
||||
_util.debug(s, ERROR, t);
|
||||
_log.error(s, t);
|
||||
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
|
||||
//if (debug >= INFO && t != null)
|
||||
// t.printStackTrace();
|
||||
@ -1085,14 +1061,6 @@ public class Snark
|
||||
throw new RuntimeException(s, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show debug info if debug is true.
|
||||
*/
|
||||
private void debug(String s, int level)
|
||||
{
|
||||
_util.debug(s, level, null);
|
||||
}
|
||||
|
||||
/** CoordinatorListener - this does nothing */
|
||||
public void peerChange(PeerCoordinator coordinator, Peer peer)
|
||||
{
|
||||
@ -1170,9 +1138,10 @@ public class Snark
|
||||
// + " pieces: ");
|
||||
checking = true;
|
||||
}
|
||||
if (!checking)
|
||||
debug("Got " + (checked ? "" : "BAD ") + "piece: " + num,
|
||||
Snark.INFO);
|
||||
if (!checking) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + (checked ? "" : "BAD ") + "piece: " + num);
|
||||
}
|
||||
}
|
||||
|
||||
public void storageAllChecked(Storage storage)
|
||||
@ -1188,7 +1157,8 @@ public class Snark
|
||||
|
||||
public void storageCompleted(Storage storage)
|
||||
{
|
||||
debug("Completely received " + torrent, Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Completely received " + torrent);
|
||||
//storage.close();
|
||||
//System.out.println("Completely received: " + torrent);
|
||||
if (completeListener != null)
|
||||
@ -1261,7 +1231,8 @@ public class Snark
|
||||
total += c.getCurrentUploadRate();
|
||||
}
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
debug("Total up bw: " + total + " Limit: " + limit, Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Total up bw: " + total + " Limit: " + limit);
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
|
@ -1726,7 +1726,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
if (count > 0) {
|
||||
// Schedule this even for final shutdown, as there's a chance
|
||||
// that it's just this webapp that is stopping.
|
||||
SimpleScheduler.getInstance().addEvent(new Disconnector(), 60*1000);
|
||||
_context.simpleScheduler().addEvent(new Disconnector(), 60*1000);
|
||||
addMessage(_("Closing I2P tunnel after notifying trackers."));
|
||||
if (finalShutdown) {
|
||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
||||
|
@ -34,6 +34,7 @@ import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.crypto.SHA1;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureFile;
|
||||
|
||||
/**
|
||||
@ -55,6 +56,7 @@ public class Storage
|
||||
|
||||
private final StorageListener listener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final Log _log;
|
||||
|
||||
private /* FIXME final FIXME */ BitField bitfield; // BitField to represent the pieces
|
||||
private int needed; // Number of pieces needed
|
||||
@ -87,6 +89,7 @@ public class Storage
|
||||
throws IOException
|
||||
{
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(Storage.class);
|
||||
this.metainfo = metainfo;
|
||||
this.listener = listener;
|
||||
needed = metainfo.getPieces();
|
||||
@ -110,6 +113,7 @@ public class Storage
|
||||
throws IOException
|
||||
{
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(Storage.class);
|
||||
this.listener = listener;
|
||||
// Create names, rafs and lengths arrays.
|
||||
getFiles(baseFile);
|
||||
@ -232,8 +236,9 @@ public class Storage
|
||||
File[] files = f.listFiles();
|
||||
if (files == null)
|
||||
{
|
||||
_util.debug("WARNING: Skipping '" + f
|
||||
+ "' not a normal file.", Snark.WARNING);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("WARNING: Skipping '" + f
|
||||
+ "' not a normal file.");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < files.length; i++)
|
||||
@ -457,7 +462,8 @@ public class Storage
|
||||
if (files == null)
|
||||
{
|
||||
// Create base as file.
|
||||
_util.debug("Creating/Checking file: " + base, Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Creating/Checking file: " + base);
|
||||
if (!base.createNewFile() && !base.exists())
|
||||
throw new IOException("Could not create file " + base);
|
||||
|
||||
@ -481,7 +487,8 @@ public class Storage
|
||||
else
|
||||
{
|
||||
// Create base as dir.
|
||||
_util.debug("Creating/Checking directory: " + base, Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Creating/Checking directory: " + base);
|
||||
if (!base.mkdir() && !base.isDirectory())
|
||||
throw new IOException("Could not create directory " + base);
|
||||
|
||||
@ -540,19 +547,22 @@ public class Storage
|
||||
bitfield = savedBitField;
|
||||
needed = metainfo.getPieces() - bitfield.count();
|
||||
_probablyComplete = complete();
|
||||
_util.debug("Found saved state and files unchanged, skipping check", Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Found saved state and files unchanged, skipping check");
|
||||
} else {
|
||||
// the following sets the needed variable
|
||||
changed = true;
|
||||
checkCreateFiles(false);
|
||||
}
|
||||
if (complete()) {
|
||||
_util.debug("Torrent is complete", Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Torrent is complete");
|
||||
} else {
|
||||
// fixme saved priorities
|
||||
if (files != null)
|
||||
priorities = new int[files.size()];
|
||||
_util.debug("Still need " + needed + " out of " + metainfo.getPieces() + " pieces", Snark.NOTICE);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Still need " + needed + " out of " + metainfo.getPieces() + " pieces");
|
||||
}
|
||||
}
|
||||
|
||||
@ -731,7 +741,7 @@ public class Storage
|
||||
String msg = "File '" + names[i] + "' exists, but has wrong length (expected " +
|
||||
lengths[i] + " but found " + length + ") - repairing corruption";
|
||||
SnarkManager.instance().addMessage(msg);
|
||||
_util.debug(msg, Snark.ERROR);
|
||||
_log.error(msg);
|
||||
changed = true;
|
||||
resume = true;
|
||||
_probablyComplete = false; // to force RW
|
||||
@ -844,7 +854,8 @@ public class Storage
|
||||
*/
|
||||
private void balloonFile(int nr) throws IOException
|
||||
{
|
||||
_util.debug("Ballooning " + nr + ": " + RAFfile[nr], Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Ballooning " + nr + ": " + RAFfile[nr]);
|
||||
long remaining = lengths[nr];
|
||||
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
|
||||
byte[] zeros = new byte[ZEROBLOCKSIZE];
|
||||
@ -875,7 +886,7 @@ public class Storage
|
||||
closeRAF(i);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_util.debug("Error closing " + RAFfile[i], Snark.ERROR, ioe);
|
||||
_log.error("Error closing " + RAFfile[i], ioe);
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
@ -896,7 +907,8 @@ public class Storage
|
||||
try {
|
||||
bs = new byte[len];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_util.debug("Out of memory, can't honor request for piece " + piece, Snark.WARNING, oom);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Out of memory, can't honor request for piece " + piece, oom);
|
||||
return null;
|
||||
}
|
||||
getUncheckedPiece(piece, bs, off, len);
|
||||
@ -1000,8 +1012,9 @@ public class Storage
|
||||
if (needed > 0) {
|
||||
if (listener != null)
|
||||
listener.setWantedPieces(this);
|
||||
_util.debug("WARNING: Not really done, missing " + needed
|
||||
+ " pieces", Snark.WARNING);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("WARNING: Not really done, missing " + needed
|
||||
+ " pieces");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ import net.i2p.util.SimpleTimer2;
|
||||
* @author Mark Wielaard (mark@klomp.org)
|
||||
*/
|
||||
public class TrackerClient implements Runnable {
|
||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(TrackerClient.class);
|
||||
private final Log _log;
|
||||
private static final String NO_EVENT = "";
|
||||
private static final String STARTED_EVENT = "started";
|
||||
private static final String COMPLETED_EVENT = "completed";
|
||||
@ -116,6 +116,7 @@ public class TrackerClient implements Runnable {
|
||||
String id = urlencode(snark.getID());
|
||||
_threadName = "TrackerClient " + id.substring(id.length() - 12);
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(TrackerClient.class);
|
||||
this.meta = meta;
|
||||
this.additionalTrackerURL = additionalTrackerURL;
|
||||
this.coordinator = coordinator;
|
||||
@ -183,7 +184,7 @@ public class TrackerClient implements Runnable {
|
||||
|
||||
private class Runner extends SimpleTimer2.TimedEvent {
|
||||
public Runner(long delay) {
|
||||
super(SimpleTimer2.getInstance(), delay);
|
||||
super(_util.getContext().simpleTimer2(), delay);
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
@ -397,9 +398,10 @@ public class TrackerClient implements Runnable {
|
||||
catch (IOException ioe)
|
||||
{
|
||||
// Probably not fatal (if it doesn't last to long...)
|
||||
_util.debug
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn
|
||||
("WARNING: Could not contact tracker at '"
|
||||
+ tr.announce + "': " + ioe, Snark.WARNING);
|
||||
+ tr.announce + "': " + ioe);
|
||||
tr.trackerProblems = ioe.getMessage();
|
||||
// don't show secondary tracker problems to the user
|
||||
if (tr.isPrimary)
|
||||
@ -421,8 +423,9 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_util.debug("Not announcing to " + tr.announce + " last announce was " +
|
||||
new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval), Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not announcing to " + tr.announce + " last announce was " +
|
||||
new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval));
|
||||
}
|
||||
if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
|
||||
maxSeenPeers = tr.seenPeers;
|
||||
@ -432,7 +435,8 @@ public class TrackerClient implements Runnable {
|
||||
if (coordinator.needOutboundPeers() && (meta == null || !meta.isPrivate()) && !stop) {
|
||||
Set<PeerID> pids = coordinator.getPEXPeers();
|
||||
if (!pids.isEmpty()) {
|
||||
_util.debug("Got " + pids.size() + " from PEX", Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + pids.size() + " from PEX");
|
||||
List<Peer> peers = new ArrayList(pids.size());
|
||||
for (PeerID pID : pids) {
|
||||
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
|
||||
@ -448,7 +452,8 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_util.debug("Not getting PEX peers", Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not getting PEX peers");
|
||||
}
|
||||
|
||||
// Get peers from DHT
|
||||
@ -460,13 +465,15 @@ public class TrackerClient implements Runnable {
|
||||
else
|
||||
numwant = _util.getMaxConnections();
|
||||
List<Hash> hashes = _util.getDHT().getPeers(snark.getInfoHash(), numwant, 2*60*1000);
|
||||
_util.debug("Got " + hashes + " from DHT", Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + hashes + " from DHT");
|
||||
// announce ourselves while the token is still good
|
||||
// FIXME this needs to be in its own thread
|
||||
if (!stop) {
|
||||
// announce only to the 1 closest
|
||||
int good = _util.getDHT().announce(snark.getInfoHash(), 1, 5*60*1000);
|
||||
_util.debug("Sent " + good + " good announces to DHT", Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sent " + good + " good announces to DHT");
|
||||
}
|
||||
|
||||
// now try these peers
|
||||
@ -487,7 +494,8 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_util.debug("Not getting DHT peers", Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not getting DHT peers");
|
||||
}
|
||||
|
||||
|
||||
@ -498,7 +506,8 @@ public class TrackerClient implements Runnable {
|
||||
return;
|
||||
|
||||
if (!runStarted)
|
||||
_util.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(" Retrying in one minute...");
|
||||
|
||||
try {
|
||||
// Sleep some minutes...
|
||||
@ -527,7 +536,7 @@ public class TrackerClient implements Runnable {
|
||||
} // try
|
||||
catch (Throwable t)
|
||||
{
|
||||
_util.debug("TrackerClient: " + t, Snark.ERROR, t);
|
||||
_log.error("TrackerClient: " + t, t);
|
||||
if (t instanceof OutOfMemoryError)
|
||||
throw (OutOfMemoryError)t;
|
||||
}
|
||||
@ -620,7 +629,8 @@ public class TrackerClient implements Runnable {
|
||||
else
|
||||
buf.append(_util.getMaxConnections());
|
||||
String s = buf.toString();
|
||||
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending TrackerClient request: " + s);
|
||||
|
||||
tr.lastRequestTime = System.currentTimeMillis();
|
||||
// Don't wait for a response to stopped when shutting down
|
||||
@ -636,7 +646,8 @@ public class TrackerClient implements Runnable {
|
||||
|
||||
TrackerInfo info = new TrackerInfo(in, snark.getID(),
|
||||
snark.getInfoHash(), snark.getMetaInfo());
|
||||
_util.debug("TrackerClient response: " + info, Snark.INFO);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("TrackerClient response: " + info);
|
||||
|
||||
String failure = info.getFailureReason();
|
||||
if (failure != null)
|
||||
|
@ -243,11 +243,12 @@ public class FetchAndAdd extends Snark implements EepGet.StatusListener, Runnabl
|
||||
}
|
||||
|
||||
/**
|
||||
* @return torrent file bytes remaining or -1
|
||||
* @return -1 when done so the web will list us as "complete" instead of "seeding"
|
||||
*/
|
||||
@Override
|
||||
public long getRemainingLength() {
|
||||
return _remaining;
|
||||
long rv = _remaining;
|
||||
return rv > 0 ? rv : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,9 +232,9 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
//out.write("<meta http-equiv=\"refresh\" content=\"" + delay + ";/i2psnark/" + peerString + "\">\n");
|
||||
out.write("<script src=\"/js/ajax.js\" type=\"text/javascript\"></script>\n" +
|
||||
"<script type=\"text/javascript\">\n" +
|
||||
"var failMessage = \"<b>" + _("Router is down") + "<\\/b>\";\n" +
|
||||
"var failMessage = \"<div class=\\\"routerdown\\\"><b>" + _("Router is down") + "<\\/b><\\/div>\";\n" +
|
||||
"function requestAjax1() { ajax(\"/i2psnark/.ajax/xhr1.html" + peerString + "\", \"mainsection\", " + (delay*1000) + "); }\n" +
|
||||
"function initAjax(delayMs) { setTimeout(requestAjax1, " + (delay*1000) +"); }\n" +
|
||||
"function initAjax() { setTimeout(requestAjax1, " + (delay*1000) +"); }\n" +
|
||||
"</script>\n");
|
||||
}
|
||||
}
|
||||
@ -333,8 +333,11 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n");
|
||||
}
|
||||
out.write(TABLE_HEADER);
|
||||
out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" > ");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "status.png\" title=\"");
|
||||
out.write(_("Status"));
|
||||
out.write("\" alt=\"");
|
||||
out.write(_("Status"));
|
||||
out.write("\"></th>\n<th>");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
out.write(" <a href=\"/i2psnark/");
|
||||
if (peerParam != null) {
|
||||
@ -355,48 +358,53 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
out.write("</a><br>\n");
|
||||
}
|
||||
out.write("</th>\n<th colspan=\"3\" align=\"left\">");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "torrent.png\" alt=\"\">");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "torrent.png\" title=\"");
|
||||
out.write(_("Torrent"));
|
||||
out.write("\" alt=\"");
|
||||
out.write(_("Torrent"));
|
||||
out.write("\">");
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "eta.png\" alt=\"\" title=\"");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "eta.png\" title=\"");
|
||||
out.write(_("Estimated time remaining"));
|
||||
out.write("\">");
|
||||
out.write("\" alt=\"");
|
||||
// Translators: Please keep short or translate as " "
|
||||
out.write(_("ETA"));
|
||||
out.write("\">");
|
||||
}
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_rx.png\" alt=\"\" title=\"");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_rx.png\" title=\"");
|
||||
out.write(_("Downloaded"));
|
||||
out.write("\">");
|
||||
out.write("\" alt=\"");
|
||||
// Translators: Please keep short or translate as " "
|
||||
out.write(_("RX"));
|
||||
out.write("\">");
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" alt=\"\" title=\"");
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" title=\"");
|
||||
out.write(_("Uploaded"));
|
||||
out.write("\">");
|
||||
out.write("\" alt=\"");
|
||||
// Translators: Please keep short or translate as " "
|
||||
out.write(_("TX"));
|
||||
out.write("\">");
|
||||
}
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_rxspeed.png\" title=\"");
|
||||
out.write(_("Down Rate"));
|
||||
out.write("\" alt=\"");
|
||||
out.write(_("RX"));
|
||||
out.write(" \">");
|
||||
// Translators: Please keep short or translate as " "
|
||||
out.write(_("Rate"));
|
||||
out.write(_("RX Rate"));
|
||||
out.write(" \">");
|
||||
}
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_txspeed.png\" title=\"");
|
||||
out.write(_("Up Rate"));
|
||||
out.write("\" alt=\"");
|
||||
out.write(_("TX"));
|
||||
// Translators: Please keep short or translate as " "
|
||||
out.write(_("TX Rate"));
|
||||
out.write(" \">");
|
||||
out.write(_("Rate"));
|
||||
}
|
||||
out.write("</th>\n<th align=\"center\">");
|
||||
|
||||
@ -965,22 +973,25 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
String statusString;
|
||||
if (err != null) {
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else {
|
||||
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
||||
err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "…";
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
"<br>" + err;
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error");
|
||||
}
|
||||
} else if (snark.isStarting()) {
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Starting");
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Starting") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Starting");
|
||||
} else if (remaining == 0 || needed == 0) { // < 0 means no meta size yet
|
||||
// partial complete or seeding
|
||||
if (isRunning) {
|
||||
@ -995,43 +1006,53 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
txt = _("Complete");
|
||||
}
|
||||
if (curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + img + ".png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + txt +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + img + ".png\" title=\"" + txt + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + txt +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + img + ".png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + txt +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + img + ".png\" title=\"" + txt + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + txt +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
} else {
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete");
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" title=\"" + _("Complete") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete");
|
||||
}
|
||||
} else {
|
||||
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" title=\"" + _("OK") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning && curPeers > 0 && downBps > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" title=\"" + _("OK") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Stalled") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning && curPeers > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Stalled") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else if (isRunning && knownPeers > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") +
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" title=\"" + _("No Peers") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") +
|
||||
": 0" + thinsp(noThinsp) + knownPeers ;
|
||||
else if (isRunning)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" title=\"" + _("No Peers") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
|
||||
else
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stopped.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stopped");
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stopped.png\" title=\"" + _("Stopped") + "\"></td>" +
|
||||
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stopped");
|
||||
}
|
||||
|
||||
out.write("<tr class=\"" + rowClass + "\">");
|
||||
@ -1074,11 +1095,11 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
else if (isValid)
|
||||
icon = toIcon(meta.getName());
|
||||
else if (snark instanceof FetchAndAdd)
|
||||
icon = "arrow_down";
|
||||
icon = "basket_put";
|
||||
else
|
||||
icon = "magnet";
|
||||
if (isValid) {
|
||||
out.write(toImg(icon, _("Info")));
|
||||
out.write(toImg(icon));
|
||||
out.write("</a>");
|
||||
} else {
|
||||
out.write(toImg(icon));
|
||||
@ -1105,7 +1126,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
|
||||
if(isRunning && remainingSeconds > 0)
|
||||
out.write(DataHelper.formatDuration2(remainingSeconds*1000)); // (eta 6h)
|
||||
out.write(DataHelper.formatDuration2(Math.max(remainingSeconds, 10) * 1000)); // (eta 6h)
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
|
||||
if (remaining > 0)
|
||||
@ -1326,7 +1347,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
* @return string or null
|
||||
* @since 0.8.4
|
||||
*/
|
||||
private String getTrackerLink(String announce, byte[] infohash) {
|
||||
private String getTrackerLinkUrl(String announce, byte[] infohash) {
|
||||
// temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash
|
||||
if (announce != null && (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
|
||||
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") ||
|
||||
@ -1342,15 +1363,29 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
buf.append("<a href=\"").append(baseURL).append("details.php?dllist=1&filelist=1&info_hash=")
|
||||
.append(TrackerClient.urlencode(infohash))
|
||||
.append("\" title=\"").append(_("Details at {0} tracker", name)).append("\" target=\"_blank\">" +
|
||||
"<img alt=\"").append(_("Info")).append("\" border=\"0\" src=\"")
|
||||
.append(_imgPath).append("details.png\"></a>");
|
||||
.append("\" title=\"").append(_("Details at {0} tracker", name)).append("\" target=\"_blank\">");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string or null
|
||||
* @since 0.8.4
|
||||
*/
|
||||
private String getTrackerLink(String announce, byte[] infohash) {
|
||||
String linkUrl = getTrackerLinkUrl(announce, infohash);
|
||||
if (linkUrl != null) {
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
buf.append(linkUrl)
|
||||
.append("<img alt=\"").append(_("Info")).append("\" border=\"0\" src=\"")
|
||||
.append(_imgPath).append("details.png\"></a>");
|
||||
return buf.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException {
|
||||
// display incoming parameter if a GET so links will work
|
||||
String newURL = req.getParameter("newURL");
|
||||
@ -1562,9 +1597,9 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
out.write(": <td><input type=\"text\" name=\"upBW\" class=\"r\" value=\""
|
||||
+ _manager.util().getMaxUpBW() + "\" size=\"4\" maxlength=\"4\" > KBps <i>");
|
||||
out.write(_("Half available bandwidth recommended."));
|
||||
out.write("<br><a href=\"/config.jsp\" target=\"blank\">");
|
||||
out.write(" [<a href=\"/config.jsp\" target=\"blank\">");
|
||||
out.write(_("View or change router bandwidth"));
|
||||
out.write("</a></i><br>\n" +
|
||||
out.write("</a>]</i><br>\n" +
|
||||
|
||||
"<tr><td>");
|
||||
out.write(_("Use open trackers also"));
|
||||
@ -1650,7 +1685,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
"<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> ");
|
||||
buf.append(_("Trackers"));
|
||||
buf.append("</span><hr>\n" +
|
||||
"<table><tr><th>")
|
||||
"<table class=\"trackerconfig\"><tr><th>")
|
||||
//.append(_("Remove"))
|
||||
.append("</th><th>")
|
||||
.append(_("Name"))
|
||||
@ -1669,16 +1704,16 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
String name = t.name;
|
||||
String homeURL = t.baseURL;
|
||||
String announceURL = t.announceURL.replace("=", "=");
|
||||
buf.append("<tr><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"delete_")
|
||||
buf.append("<tr><td><input type=\"checkbox\" class=\"optbox\" name=\"delete_")
|
||||
.append(name).append("\" title=\"").append(_("Delete")).append("\">" +
|
||||
"</td><td align=\"left\">").append(name)
|
||||
.append("</td><td align=\"left\">").append(urlify(homeURL, 35))
|
||||
.append("</td><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"open_")
|
||||
"</td><td>").append(name)
|
||||
.append("</td><td>").append(urlify(homeURL, 35))
|
||||
.append("</td><td><input type=\"checkbox\" class=\"optbox\" name=\"open_")
|
||||
.append(announceURL).append("\"");
|
||||
if (openTrackers.contains(t.announceURL))
|
||||
buf.append(" checked=\"checked\"");
|
||||
buf.append(">" +
|
||||
"</td><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"private_")
|
||||
"</td><td><input type=\"checkbox\" class=\"optbox\" name=\"private_")
|
||||
.append(announceURL).append("\"");
|
||||
if (privateTrackers.contains(t.announceURL)) {
|
||||
buf.append(" checked=\"checked\"");
|
||||
@ -1691,17 +1726,17 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
}
|
||||
}
|
||||
buf.append(">" +
|
||||
"</td><td align=\"left\">").append(urlify(announceURL, 35))
|
||||
"</td><td>").append(urlify(announceURL, 35))
|
||||
.append("</td></tr>\n");
|
||||
}
|
||||
buf.append("<tr><td align=\"center\"><b>")
|
||||
buf.append("<tr><td><b>")
|
||||
.append(_("Add")).append(":</b></td>" +
|
||||
"<td align=\"left\"><input type=\"text\" size=\"16\" name=\"tname\"></td>" +
|
||||
"<td align=\"left\"><input type=\"text\" size=\"40\" name=\"thurl\"></td>" +
|
||||
"<td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"_add_open_\"></td>" +
|
||||
"<td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"_add_private_\"></td>" +
|
||||
"<td align=\"left\"><input type=\"text\" size=\"40\" name=\"taurl\"></td></tr>\n" +
|
||||
"<tr><td colspan=\"2\"></td><td colspan=\"4\" align=\"left\">\n" +
|
||||
"<td><input type=\"text\" class=\"trackername\" name=\"tname\"></td>" +
|
||||
"<td><input type=\"text\" class=\"trackerhome\" name=\"thurl\"></td>" +
|
||||
"<td><input type=\"checkbox\" class=\"optbox\" name=\"_add_open_\"></td>" +
|
||||
"<td><input type=\"checkbox\" class=\"optbox\" name=\"_add_private_\"></td>" +
|
||||
"<td><input type=\"text\" class=\"trackerannounce\" name=\"taurl\"></td></tr>\n" +
|
||||
"<tr><td colspan=\"2\"></td><td colspan=\"4\">\n" +
|
||||
"<input type=\"submit\" name=\"taction\" class=\"default\" value=\"").append(_("Add tracker")).append("\">\n" +
|
||||
"<input type=\"submit\" name=\"taction\" class=\"delete\" value=\"").append(_("Delete selected")).append("\">\n" +
|
||||
"<input type=\"submit\" name=\"taction\" class=\"accept\" value=\"").append(_("Save tracker configuration")).append("\">\n" +
|
||||
@ -1984,7 +2019,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
|
||||
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" >\n" +
|
||||
"<thead>\n" +
|
||||
"<tr><th colspan=\"2\">";
|
||||
"<tr><th>";
|
||||
|
||||
private static final String FOOTER = "</div></center></body></html>";
|
||||
|
||||
@ -2059,40 +2094,34 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
boolean showPriority = ls != null && snark != null && snark.getStorage() != null && !snark.getStorage().complete();
|
||||
if (showPriority)
|
||||
buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
|
||||
buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" ><thead>");
|
||||
if (snark != null) {
|
||||
// first row - torrent info
|
||||
// FIXME center
|
||||
buf.append("<tr><th colspan=\"" + (showPriority ? '4' : '3') + "\"><div>")
|
||||
.append(_("Torrent")).append(": ").append(snark.getBaseName());
|
||||
int pieces = snark.getPieces();
|
||||
double completion = (pieces - snark.getNeeded()) / (double) pieces;
|
||||
if (completion < 1.0)
|
||||
buf.append("<br>").append(_("Completion")).append(": ").append((new DecimalFormat("0.00%")).format(completion));
|
||||
else
|
||||
buf.append("<br>").append(_("Complete"));
|
||||
// else unknown
|
||||
long needed = snark.getNeededLength();
|
||||
if (needed > 0)
|
||||
buf.append("<br>").append(_("Remaining")).append(": ").append(formatSize(needed));
|
||||
buf.append("<br>").append(_("Size")).append(": ").append(formatSize(snark.getTotalLength()));
|
||||
MetaInfo meta = snark.getMetaInfo();
|
||||
if (meta != null) {
|
||||
List files = meta.getFiles();
|
||||
int fileCount = files != null ? files.size() : 1;
|
||||
buf.append("<br>").append(_("Files")).append(": ").append(fileCount);
|
||||
}
|
||||
buf.append("<br>").append(_("Pieces")).append(": ").append(pieces);
|
||||
buf.append("<br>").append(_("Piece size")).append(": ").append(formatSize(snark.getPieceLength(0)));
|
||||
// first table - torrent info
|
||||
buf.append("<table class=\"snarkTorrentInfo\">\n");
|
||||
buf.append("<tr><th><b>")
|
||||
.append(_("Torrent"))
|
||||
.append(":</b> ")
|
||||
.append(snark.getBaseName())
|
||||
.append("</th></tr>\n");
|
||||
|
||||
buf.append("<tr><td>")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > <b>")
|
||||
.append(_("Torrent file"))
|
||||
.append(":</b> ")
|
||||
.append(snark.getName())
|
||||
.append("</td></tr>\n");
|
||||
|
||||
MetaInfo meta = snark.getMetaInfo();
|
||||
if (meta != null) {
|
||||
String announce = meta.getAnnounce();
|
||||
if (announce != null) {
|
||||
buf.append("<br>");
|
||||
buf.append("<tr><td>");
|
||||
String trackerLink = getTrackerLink(announce, snark.getInfoHash());
|
||||
if (trackerLink != null)
|
||||
buf.append(trackerLink).append(' ');
|
||||
buf.append(_("Tracker")).append(": ");
|
||||
buf.append("<b>").append(_("Tracker")).append(":</b> ");
|
||||
String trackerLinkUrl = getTrackerLinkUrl(announce, snark.getInfoHash());
|
||||
if (trackerLinkUrl != null)
|
||||
buf.append(trackerLinkUrl);
|
||||
if (announce.startsWith("http://"))
|
||||
announce = announce.substring(7);
|
||||
int slsh = announce.indexOf('/');
|
||||
@ -2101,53 +2130,119 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
if (announce.length() > 67)
|
||||
announce = announce.substring(0, 40) + "…" + announce.substring(announce.length() - 8);
|
||||
buf.append(announce);
|
||||
if (trackerLinkUrl != null)
|
||||
buf.append("</a>");
|
||||
buf.append("</td></tr>");
|
||||
}
|
||||
}
|
||||
|
||||
String hex = I2PSnarkUtil.toHex(snark.getInfoHash());
|
||||
if (meta == null || !meta.isPrivate()) {
|
||||
buf.append("<br>").append(toImg("magnet", _("Magnet link"))).append(" <a href=\"")
|
||||
buf.append("<tr><td><a href=\"")
|
||||
.append(MAGNET_FULL).append(hex).append("\">")
|
||||
.append(MAGNET_FULL).append(hex).append("</a>");
|
||||
.append(toImg("magnet", _("Magnet link")))
|
||||
.append("</a> <b>Magnet:</b> <a href=\"")
|
||||
.append(MAGNET_FULL).append(hex).append("\">")
|
||||
.append(MAGNET_FULL).append(hex).append("</a>")
|
||||
.append("</td></tr>\n");
|
||||
} else {
|
||||
buf.append("<br>").append(_("Private torrent"));
|
||||
buf.append("<tr><td>")
|
||||
.append(_("Private torrent"))
|
||||
.append("</td></tr>\n");
|
||||
}
|
||||
// We don't have the hash of the torrent file
|
||||
//buf.append("<br>").append(_("Maggot link")).append(": <a href=\"").append(MAGGOT).append(hex).append(':').append(hex).append("\">")
|
||||
// .append(MAGGOT).append(hex).append(':').append(hex).append("</a>");
|
||||
buf.append("<br>").append(_("Torrent file")).append(": ").append(snark.getName());
|
||||
buf.append("</div></th></tr>");
|
||||
//buf.append("<tr><td>").append(_("Maggot link")).append(": <a href=\"").append(MAGGOT).append(hex).append(':').append(hex).append("\">")
|
||||
// .append(MAGGOT).append(hex).append(':').append(hex).append("</a></td></tr>");
|
||||
|
||||
buf.append("<tr><td>")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "size.png\" > <b>")
|
||||
.append(_("Size"))
|
||||
.append(":</b> ")
|
||||
.append(formatSize(snark.getTotalLength()));
|
||||
int pieces = snark.getPieces();
|
||||
double completion = (pieces - snark.getNeeded()) / (double) pieces;
|
||||
if (completion < 1.0)
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "head_rx.png\" > <b>")
|
||||
.append(_("Completion"))
|
||||
.append(":</b> ")
|
||||
.append((new DecimalFormat("0.00%")).format(completion));
|
||||
else
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "head_rx.png\" > ")
|
||||
.append(_("Complete"));
|
||||
// else unknown
|
||||
long needed = snark.getNeededLength();
|
||||
if (needed > 0)
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "head_rx.png\" > <b>")
|
||||
.append(_("Remaining"))
|
||||
.append(":</b> ")
|
||||
.append(formatSize(needed));
|
||||
if (meta != null) {
|
||||
List files = meta.getFiles();
|
||||
int fileCount = files != null ? files.size() : 1;
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > <b>")
|
||||
.append(_("Files"))
|
||||
.append(":</b> ")
|
||||
.append(fileCount);
|
||||
}
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > <b>")
|
||||
.append(_("Pieces"))
|
||||
.append(":</b> ")
|
||||
.append(pieces);
|
||||
buf.append(" <img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > <b>")
|
||||
.append(_("Piece size"))
|
||||
.append(":</b> ")
|
||||
.append(formatSize(snark.getPieceLength(0)))
|
||||
.append("</td></tr>\n");
|
||||
} else {
|
||||
// shouldn't happen
|
||||
buf.append("<tr><th>Not found<br>resource=\"").append(r.toString())
|
||||
.append("\"<br>base=\"").append(base)
|
||||
.append("\"<br>torrent=\"").append(torrentName)
|
||||
.append("\"</th></tr>");
|
||||
.append("\"</th></tr>\n");
|
||||
}
|
||||
buf.append("</table>\n");
|
||||
if (ls == null) {
|
||||
// We are only showing the torrent info section
|
||||
buf.append("</thead></table></div></div></BODY></HTML>");
|
||||
buf.append("</div></div></BODY></HTML>");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// second row - dir info
|
||||
buf.append("<tr><th>")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > ")
|
||||
.append(_("Directory")).append(": ").append(directory).append("</th><th align=\"right\">")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "size.png\" > ")
|
||||
.append(_("Size"));
|
||||
buf.append("</th><th class=\"headerstatus\">")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" > ")
|
||||
.append(_("Status")).append("</th>");
|
||||
// second table - dir info
|
||||
buf.append("<table class=\"snarkDirInfo\"><thead>\n");
|
||||
buf.append("<tr>\n")
|
||||
.append("<th colspan=2>")
|
||||
.append("<img border=\"0\" src=\"" + _imgPath + "file.png\" title=\"")
|
||||
.append(_("Directory"))
|
||||
.append(": ")
|
||||
.append(directory)
|
||||
.append("\" alt=\"")
|
||||
.append(_("Directory"))
|
||||
.append("\"></th>\n");
|
||||
buf.append("<th align=\"right\">")
|
||||
.append("<img border=\"0\" src=\"" + _imgPath + "size.png\" title=\"")
|
||||
.append(_("Size"))
|
||||
.append("\" alt=\"")
|
||||
.append(_("Size"))
|
||||
.append("\"></th>\n");
|
||||
buf.append("<th class=\"headerstatus\">")
|
||||
.append("<img border=\"0\" src=\"" + _imgPath + "status.png\" title=\"")
|
||||
.append(_("Status"))
|
||||
.append("\" alt=\"")
|
||||
.append(_("Status"))
|
||||
.append("\"></th>\n");
|
||||
if (showPriority)
|
||||
buf.append("<th class=\"headerpriority\">")
|
||||
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "priority.png\" > ")
|
||||
.append(_("Priority")).append("</th>");
|
||||
buf.append("</tr></thead>\n");
|
||||
buf.append("<tr><td colspan=\"" + (showPriority ? '4' : '3') + "\" class=\"ParentDir\"><A HREF=\"");
|
||||
.append("<img border=\"0\" src=\"" + _imgPath + "priority.png\" title=\"")
|
||||
.append(_("Priority"))
|
||||
.append("\" alt=\"")
|
||||
.append(_("Priority"))
|
||||
.append("\"></th>\n");
|
||||
buf.append("</tr>\n</thead>\n");
|
||||
buf.append("<tr><td colspan=\"" + (showPriority ? '5' : '4') + "\" class=\"ParentDir\"><A HREF=\"");
|
||||
buf.append(URIUtil.addPaths(base,"../"));
|
||||
buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ")
|
||||
.append(_("Up to higher level directory")).append("</A></td></tr>\n");
|
||||
.append(_("Up to higher level directory"))
|
||||
.append("</A></td></tr>\n");
|
||||
|
||||
|
||||
//DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
|
||||
@ -2163,8 +2258,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
Resource item = r.addPath(ls[i]);
|
||||
|
||||
String rowClass = (i % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
|
||||
buf.append("<TR class=\"").append(rowClass).append("\"><TD class=\"snarkFileName ")
|
||||
.append(rowClass).append("\">");
|
||||
buf.append("<TR class=\"").append(rowClass).append("\">");
|
||||
|
||||
// Get completeness and status string
|
||||
boolean complete = false;
|
||||
@ -2200,7 +2294,7 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
status = toImg("clock_red");
|
||||
status += " " +
|
||||
(100 * (length - remaining) / length) + "% " + _("complete") +
|
||||
" (" + DataHelper.formatSize2(remaining) + _("bytes remaining") + ")";
|
||||
" (" + DataHelper.formatSize2(remaining) + "B " + _("remaining") + ")";
|
||||
}
|
||||
} else {
|
||||
status = "Not a file?";
|
||||
@ -2216,6 +2310,8 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
path=URIUtil.addPaths(path,"/");
|
||||
String icon = toIcon(item);
|
||||
|
||||
buf.append("<TD class=\"snarkFileIcon ")
|
||||
.append(rowClass).append("\">");
|
||||
if (complete) {
|
||||
buf.append("<a href=\"").append(path).append("\">");
|
||||
// thumbnail ?
|
||||
@ -2223,16 +2319,17 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
if (plc.endsWith(".jpg") || plc.endsWith(".jpeg") || plc.endsWith(".png") ||
|
||||
plc.endsWith(".gif") || plc.endsWith(".ico")) {
|
||||
buf.append("<img alt=\"\" border=\"0\" class=\"thumb\" src=\"")
|
||||
.append(path).append("\"></a> ");
|
||||
.append(path).append("\"></a>");
|
||||
} else {
|
||||
buf.append(toImg(icon, _("Open"))).append("</a> ");
|
||||
buf.append(toImg(icon, _("Open"))).append("</a>");
|
||||
}
|
||||
buf.append("<A HREF=\"");
|
||||
buf.append(path);
|
||||
buf.append("\">");
|
||||
} else {
|
||||
buf.append(toImg(icon)).append(' ');
|
||||
buf.append(toImg(icon));
|
||||
}
|
||||
buf.append("</TD><TD class=\"snarkFileName ")
|
||||
.append(rowClass).append("\">");
|
||||
if (complete)
|
||||
buf.append("<a href=\"").append(path).append("\">");
|
||||
buf.append(ls[i]);
|
||||
if (complete)
|
||||
buf.append("</a>");
|
||||
@ -2269,15 +2366,15 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
buf.append("</TR>\n");
|
||||
}
|
||||
if (showSaveButton) {
|
||||
buf.append("<thead><tr><th colspan=\"3\"> </th><th class=\"headerpriority\"><input type=\"submit\" value=\"");
|
||||
buf.append("<thead><tr><th colspan=\"4\"> </th><th class=\"headerpriority\"><input type=\"submit\" value=\"");
|
||||
buf.append(_("Save priorities"));
|
||||
buf.append("\" name=\"foo\" ></th></tr></thead>\n");
|
||||
}
|
||||
buf.append("</TABLE>\n");
|
||||
buf.append("</table>\n");
|
||||
if (showPriority)
|
||||
buf.append("</form>");
|
||||
buf.append("</div></div></BODY></HTML>\n");
|
||||
|
||||
buf.append("</form>");
|
||||
buf.append("</div></div></BODY></HTML>\n");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user