diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index 7d066b150c..221c5366cb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -54,6 +54,10 @@ public class Peer implements Comparable private boolean deregister = true; private static long __id; private long _id; + final static long CHECK_PERIOD = 40*1000; // 40 seconds + final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long + private long uploaded_old[] = {-1,-1,-1,-1,-1,-1}; + private long downloaded_old[] = {-1,-1,-1,-1,-1,-1}; /** * Creates a disconnected peer given a PeerID, your own id and the @@ -487,4 +491,67 @@ public class Peer implements Comparable s.retransmitRequests(); } + /** + * Return how much the peer has + * Quite inefficient - a byte lookup table or counter in Bitfield would be much better + */ + public int completed() + { + PeerState s = state; + if (s == null || s.bitfield == null) + return 0; + int count = 0; + for (int i = 0; i < s.bitfield.size(); i++) + if (s.bitfield.get(i)) + count++; + return count; + } + + /** + * Push the total uploaded/downloaded onto a RATE_DEPTH deep stack + */ + public void setRateHistory(long up, long down) + { + setRate(up, uploaded_old); + setRate(down, downloaded_old); + } + + private void setRate(long val, long array[]) + { + synchronized(array) { + for (int i = RATE_DEPTH-1; i > 0; i--) + array[i] = array[i-1]; + array[0] = val; + } + } + + /** + * Returns the 4-minute-average rate in Bps + */ + public long getUploadRate() + { + return getRate(uploaded_old); + } + + public long getDownloadRate() + { + return getRate(downloaded_old); + } + + private long getRate(long array[]) + { + long rate = 0; + int i = 0; + synchronized(array) { + for ( ; i < RATE_DEPTH; i++){ + if (array[i] < 0) + break; + rate += array[i]; + } + } + if (i == 0) + return 0; + return rate / (i * CHECK_PERIOD / 1000); + } + } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java index 860a506045..d944434540 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java @@ -82,6 +82,7 @@ class PeerCheckerTask extends TimerTask uploaded += upload; long download = peer.getDownloaded(); downloaded += download; + peer.setRateHistory(upload, download); peer.resetCounters(); if (Snark.debug >= Snark.DEBUG) diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 51c3172749..42029c7a61 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -105,6 +105,15 @@ public class PeerCoordinator implements PeerListener public Storage getStorage() { return storage; } public CoordinatorListener getListener() { return listener; } + // for web page detailed stats + public List peerList() + { + synchronized(peers) + { + return new ArrayList(peers); + } + } + public byte[] getID() { return id; @@ -157,12 +166,17 @@ public class PeerCoordinator implements PeerListener */ public void setRateHistory(long up, long down) { - for (int i = RATE_DEPTH-1; i > 0; i--){ - uploaded_old[i] = uploaded_old[i-1]; - downloaded_old[i] = downloaded_old[i-1]; + setRate(up, uploaded_old); + setRate(down, downloaded_old); + } + + private void setRate(long val, long array[]) + { + synchronized(array) { + for (int i = RATE_DEPTH-1; i > 0; i--) + array[i] = array[i-1]; + array[0] = val; } - uploaded_old[0] = up; - downloaded_old[0] = down; } /** @@ -170,21 +184,20 @@ public class PeerCoordinator implements PeerListener */ public long getDownloadRate() { - long rate = 0; - for (int i = 0; i < RATE_DEPTH; i++){ - rate += downloaded_old[i]; - } - return rate / (RATE_DEPTH * CHECK_PERIOD / 1000); + return getRate(downloaded_old); } - /** - * Returns the 4-minute-average rate in Bps - */ public long getUploadRate() + { + return getRate(uploaded_old); + } + + private long getRate(long array[]) { long rate = 0; - for (int i = 0; i < RATE_DEPTH; i++){ - rate += uploaded_old[i]; + synchronized(array) { + for (int i = 0; i < RATE_DEPTH; i++) + rate += array[i]; } return rate / (RATE_DEPTH * CHECK_PERIOD / 1000); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index c96724e1c0..85ce9148d4 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -49,17 +49,25 @@ public class I2PSnarkServlet extends HttpServlet { if ( (nonce != null) && (nonce.equals(String.valueOf(_nonce))) ) processRequest(req); + String peerParam = req.getParameter("p"); + String peerString; + if (peerParam == null) { + peerString = ""; + } else { + peerString = "?p=" + peerParam; + } + PrintWriter out = resp.getWriter(); out.write(HEADER_BEGIN); // we want it to go to the base URI so we don't refresh with some funky action= value - out.write("\n"); + out.write("\n"); out.write(HEADER); out.write("\n"); out.write("
"); out.write("I2PSnark
\n"); out.write("\n"); - out.write("\n"); for (int i = 0; i < snarks.size(); i++) { Snark snark = (Snark)snarks.get(i); - displaySnark(out, snark, uri, i, stats); + boolean showPeers = "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam); + displaySnark(out, snark, uri, i, stats, showPeers); } if (snarks.size() <= 0) { out.write(TABLE_EMPTY); @@ -103,6 +119,7 @@ public class I2PSnarkServlet extends HttpServlet { } out.write(TABLE_FOOTER); + writeAddForm(out, req); if (true) // seeding needs to register the torrent first, so we can't start it automatically (boo, hiss) writeSeedForm(out, req); @@ -318,7 +335,7 @@ public class I2PSnarkServlet extends HttpServlet { private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60; private static final int MAX_DISPLAYED_ERROR_LENGTH = 30; - private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[]) throws IOException { + private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers) throws IOException { String filename = snark.torrent; File f = new File(filename); filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name @@ -369,7 +386,11 @@ public class I2PSnarkServlet extends HttpServlet { String statusString = "Unknown"; if (err != null) { - if (isRunning) + if (isRunning && curPeers > 0 && !showPeers) + statusString = "TrackerErr (" + + curPeers + "/" + knownPeers + + " peers)"; + else if (isRunning) statusString = "TrackerErr (" + curPeers + "/" + knownPeers + " peers)"; else { if (err.length() > MAX_DISPLAYED_ERROR_LENGTH) @@ -377,13 +398,25 @@ public class I2PSnarkServlet extends HttpServlet { statusString = "TrackerErr (" + err + ")"; } } else if (remaining <= 0) { - if (isRunning) + if (isRunning && curPeers > 0 && !showPeers) + statusString = "Seeding (" + + curPeers + "/" + knownPeers + + " peers)"; + else if (isRunning) statusString = "Seeding (" + curPeers + "/" + knownPeers + " peers)"; else statusString = "Complete"; } else { - if (isRunning && curPeers > 0 && downBps > 0) + if (isRunning && curPeers > 0 && downBps > 0 && !showPeers) + statusString = "OK (" + + curPeers + "/" + knownPeers + + " peers)"; + else if (isRunning && curPeers > 0 && downBps > 0) statusString = "OK (" + curPeers + "/" + knownPeers + " peers)"; + else if (isRunning && curPeers > 0 && !showPeers) + statusString = "Stalled (" + + curPeers + "/" + knownPeers + + " peers)"; else if (isRunning && curPeers > 0) statusString = "Stalled (" + curPeers + "/" + knownPeers + " peers)"; else if (isRunning) @@ -427,23 +460,84 @@ public class I2PSnarkServlet extends HttpServlet { out.write(formatSize(upBps) + "ps"); out.write("\n\t"); out.write("\n\n"); + if(showPeers && isRunning && curPeers > 0) { + List peers = snark.coordinator.peerList(); + Iterator it = peers.iterator(); + while (it.hasNext()) { + Peer peer = (Peer)it.next(); + if (!peer.isConnected()) + continue; + out.write(""); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + out.write("\n\t"); + } + } } private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException { @@ -565,15 +659,16 @@ public class I2PSnarkServlet extends HttpServlet { out.write("\n"); } + // rounding makes us look faster :) private String formatSize(long bytes) { if (bytes < 5*1024) return bytes + "B"; else if (bytes < 5*1024*1024) - return (bytes/1024) + "KB"; + return ((bytes + 512)/1024) + "KB"; else if (bytes < 5*1024*1024*1024l) - return (bytes/(1024*1024)) + "MB"; + return ((bytes + 512*1024)/(1024*1024)) + "MB"; else - return (bytes/(1024*1024*1024)) + "GB"; + return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "GB"; } private static final String HEADER_BEGIN = "\n" + @@ -649,7 +744,9 @@ public class I2PSnarkServlet extends HttpServlet { private static final String TABLE_HEADER = "
Refresh
\n"); + out.write("
Refresh
\n"); out.write("
Forum
\n"); out.write("
eBook
\n"); out.write("
GayTorrents
\n"); @@ -79,6 +87,13 @@ public class I2PSnarkServlet extends HttpServlet { List snarks = getSortedSnarks(req); String uri = req.getRequestURI(); out.write(TABLE_HEADER); + if (I2PSnarkUtil.instance().connected() && snarks.size() > 0) { + if (peerParam != null) + out.write("(Hide Peers)
\n"); + else + out.write("(Show Peers)
\n"); + } + out.write(TABLE_HEADER2); out.write("
"); if (I2PSnarkUtil.instance().connected()) out.write("
"); + String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash()); + if (showPeers) + parameters = parameters + "&p=1"; if (isRunning) { - out.write("Stop"); } else { if (isValid) - out.write("Start "); - out.write("Remove
"); - out.write("Delete "); } out.write("
"); + out.write(""); + String ch = peer.toString().substring(0, 4); + String client; + if ("AwMD".equals(ch)) + client = "I2PSnark"; + else if ("BFJT".equals(ch)) + client = "I2PRufus"; + else if ("TTMt".equals(ch)) + client = "I2P-BT"; + else if ("LUFa".equals(ch)) + client = "Azureus"; + else + client = "Unknown"; + out.write("" + client + " " + peer.toString().substring(5, 9) + ""); + out.write(""); + out.write(""); + float pct = (float) (100.0 * (float) peer.completed() / snark.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 + "%"); + } + out.write(""); + out.write(""); + if (remaining > 0) { + if (peer.isInteresting() && !peer.isChoked()) + out.write(""); + else + out.write(""); + out.write("" + formatSize(peer.getDownloadRate()) + "ps"); + } + out.write(""); + if (pct != 100.0) { + if (peer.isInterested() && !peer.isChoking()) + out.write(""); + else + out.write(""); + out.write("" + formatSize(peer.getUploadRate()) + "ps"); + } + out.write(""); + out.write("
\n" + "\n" + - "\n" + + "\n" + " \n" + " \n" + " \n" + diff --git a/history.txt b/history.txt index ab05c87be2..24982775f2 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,7 @@ -$Id: history.txt,v 1.550 2007-02-14 16:35:43 jrandom Exp $ +$Id: history.txt,v 1.551 2007-02-15 18:25:04 jrandom Exp $ + +2007-02-28 zzz + * i2psnark: Add peer details to web page * 2007-02-15 0.6.1.27 released diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 7c1f040be0..ed9883309d 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.486 $ $Date: 2007-02-14 16:35:44 $"; + public final static String ID = "$Revision: 1.487 $ $Date: 2007-02-15 18:25:06 $"; public final static String VERSION = "0.6.1.27"; - public final static long BUILD = 0; + public final static long BUILD = 1; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID);
Status
Status \n"; + + private static final String TABLE_HEADER2 = "TorrentETADownloaded