diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java index 7d7e9b054..88dee3101 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java @@ -115,10 +115,10 @@ class PeerCheckerTask extends TimerTask + " C: " + peer.isChoked(), Snark.DEBUG); - // Choke a third of them rather than all so it isn't so drastic... + // Choke a percentage of them rather than all so it isn't so drastic... // unless this torrent is over the limit all by itself. boolean overBWLimitChoke = upload > 0 && - ((overBWLimit && random.nextInt(3) == 0) || + ((overBWLimit && random.nextInt(5) < 2) || (coordinator.overUpBWLimit(uploaded))); // If we are at our max uploaders and we have lots of other diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index e25ff1fe3..c2afec346 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -734,7 +734,7 @@ public class Snark //if (debug >= INFO && t != null) // t.printStackTrace(); stopTorrent(); - throw new RuntimeException(s + (t == null ? "" : ": " + t.getMessage())); + throw new RuntimeException(s + (t == null ? "" : ": " + t)); } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index 4eeb21f6d..fba307f52 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -287,7 +287,7 @@ public class Storage } /** - * @param file absolute path (non-directory) + * @param file canonical path (non-directory) * @return number of bytes remaining; -1 if unknown file * @since 0.7.14 */ @@ -295,7 +295,16 @@ public class Storage long bytes = 0; for (int i = 0; i < rafs.length; i++) { File f = RAFfile[i]; - if (f != null && f.getAbsolutePath().equals(file)) { + // use canonical in case snark dir or sub dirs are symlinked + String canonical = null; + if (f != null) { + try { + canonical = f.getCanonicalPath(); + } catch (IOException ioe) { + f = null; + } + } + if (f != null && canonical.equals(file)) { if (complete()) return 0; int psz = metainfo.getPieceLength(0); @@ -305,7 +314,8 @@ public class Storage long rv = 0; if (!bitfield.get(pc)) rv = Math.min(psz - (start % psz), lengths[i]); - for (int j = pc + 1; j * psz < end; j++) { + int pieces = metainfo.getPieces(); + for (int j = pc + 1; j * psz < end && j < pieces; j++) { if (!bitfield.get(j)) { if ((j+1)*psz < end) rv += psz; 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 3a58d65b5..af793721d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -271,7 +271,7 @@ public class I2PSnarkServlet extends Default { out.write(" ("); out.write(_("{0} torrents", snarks.size())); out.write(", "); - out.write(DataHelper.formatSize(stats[5]) + "B, "); + out.write(DataHelper.formatSize2(stats[5]) + "B, "); out.write(_("{0} connected peers", stats[4])); out.write(")\n" + "  \n" + @@ -683,6 +683,12 @@ public class I2PSnarkServlet extends Default { out.write(_("Open file")); out.write("\">"); } + String icon; + if (snark.meta.getFiles() != null) + icon = "folder"; + else + icon = toIcon(fullFilename); + out.write(toImg(icon)); out.write(filename); if (remaining == 0 || snark.meta.getFiles() != null) out.write(""); @@ -1078,7 +1084,7 @@ public class I2PSnarkServlet extends Default { private static final String HOPS = _x("hops"); private static final String TUNNELS = _x("tunnels"); - /** modded from ConfigTunnelsHelper */ + /** modded from ConfigTunnelsHelper @since 0.7.14 */ private String renderOptions(int min, int max, String strNow, String selName, String name) { int now = 2; try { @@ -1130,6 +1136,7 @@ public class I2PSnarkServlet extends Default { return ((bytes + 512*1024*1024)/(1024*1024*1024)) + " GB"; } + /** @since 0.7.14 */ private static String urlify(String s) { StringBuilder buf = new StringBuilder(256); buf.append("").append(s).append(""); @@ -1174,6 +1181,7 @@ public class I2PSnarkServlet extends Default { * @param base The base URL * @param parent True if the parent directory should be included * @return String of HTML + * @since 0.7.14 */ private String getListHTML(Resource r, String base, boolean parent) throws IOException @@ -1247,14 +1255,12 @@ public class I2PSnarkServlet extends Default { long length = item.length(); if (item.isDirectory()) { complete = true; - status = " " + - _("Directory"); + status = toImg("tick") + _("Directory"); } else { if (snark == null) { // Assume complete, perhaps he removed a completed torrent but kept a bookmark complete = true; - status = " " + - _("Torrent not found?"); + status = toImg("cancel") + _("Torrent not found?"); } else { try { File f = item.getFile(); @@ -1262,16 +1268,14 @@ public class I2PSnarkServlet extends Default { long remaining = snark.storage.remaining(f.getCanonicalPath()); if (remaining < 0) { complete = true; - status = " " + - _("File not found in torrent?"); + status = toImg("cancel") + _("File not found in torrent?"); } else if (remaining == 0 || length <= 0) { complete = true; - status = " " + - _("Complete"); + status = toImg("tick") + _("Complete"); } else { - status = " " + - (100 - (100 * remaining / length)) + "% " + _("complete") + - " (" + DataHelper.formatSize(remaining) + " " + _("bytes remaining") + ")"; + status = toImg("clock") + + (100 * (length - remaining) / length) + "% " + _("complete") + + " (" + DataHelper.formatSize2(remaining) + _("bytes remaining") + ")"; } } else { status = "Not a file?"; @@ -1285,71 +1289,31 @@ public class I2PSnarkServlet extends Default { String path=URI.addPaths(base,encoded); if (item.isDirectory() && !path.endsWith("/")) path=URI.addPaths(path,"/"); - String plc = path.toLowerCase(); + String icon = toIcon(item); - // pick an icon; try to catch the common types in an i2p environment - String icon; - if (item.isDirectory()) { - icon = "folder"; - } else { - // Should really just add to the mime.properties file in org.mortbay.jetty.jar - // instead of this mishmash. We can't get to HttpContext.setMimeMapping() - // from here? We could do it from a web.xml perhaps. - // Or could we put our own org/mortbay/http/mime.properties file in the war? - String mime = getServletContext().getMimeType(path); - if (mime == null) - mime = ""; - if (mime.equals("text/html")) - icon = "html"; - else if (mime.equals("text/plain") || plc.endsWith(".nfo")) - icon = "page"; - else if (mime.equals("application/java-archive") || plc.endsWith(".war")) - icon = "package"; - else if (plc.endsWith(".xpi2p")) - icon = "plugin"; - else if (mime.equals("application/pdf")) - icon = "page_white_acrobat"; - else if (mime.startsWith("image/") || plc.endsWith(".ico")) - icon = "photo"; - else if (mime.startsWith("audio/") || mime.equals("application/ogg") || - plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") || - plc.endsWith(".ape")) - icon = "music"; - else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") || - plc.endsWith(".mp4")) - icon = "film"; - else if (mime.equals("application/zip") || mime.equals("application/x-gtar") || - mime.equals("application/compress") || mime.equals("application/gzip") || - mime.equals("application/x-tar") || - plc.endsWith(".rar") || plc.endsWith(".bz2") || plc.endsWith(".7z")) - icon = "compress"; - else if (plc.endsWith(".exe")) - icon = "application"; - else - icon = "bug"; - } if (complete) { - buf.append("\"\""); // thumbnail ? + String plc = item.toString().toLowerCase(); if (plc.endsWith(".jpg") || plc.endsWith(".jpeg") || plc.endsWith(".png") || plc.endsWith(".gif") || plc.endsWith(".ico")) { - buf.append("class=\"thumb\" src=\"") + buf.append("\"\" "); } else { - buf.append("height=\"16\" width=\"16\" src=\"/i2psnark/_icons/").append(icon).append(".png\"> "); + buf.append(toImg(icon)); } buf.append(""); } else { - buf.append(" "); + buf.append(toImg(icon)); } buf.append(ls[i]); if (complete) buf.append(""); buf.append(""); if (!item.isDirectory()) - buf.append(DataHelper.formatSize(length)).append(' ').append(_("Bytes")); + buf.append(DataHelper.formatSize2(length)).append('B'); buf.append(""); //buf.append(dfmt.format(new Date(item.lastModified()))); buf.append(status); @@ -1361,6 +1325,64 @@ public class I2PSnarkServlet extends Default { return buf.toString(); } + /** @since 0.7.14 */ + private String toIcon(Resource item) { + if (item.isDirectory()) + return "folder"; + return toIcon(item.toString()); + } + + /** + * Pick an icon; try to catch the common types in an i2p environment + * @return file name not including ".png" + * @since 0.7.14 + */ + private String toIcon(String path) { + String icon; + // Should really just add to the mime.properties file in org.mortbay.jetty.jar + // instead of this mishmash. We can't get to HttpContext.setMimeMapping() + // from here? We could do it from a web.xml perhaps. + // Or could we put our own org/mortbay/http/mime.properties file in the war? + String plc = path.toLowerCase(); + String mime = getServletContext().getMimeType(path); + if (mime == null) + mime = ""; + if (mime.equals("text/html")) + icon = "html"; + else if (mime.equals("text/plain") || plc.endsWith(".nfo")) + icon = "page"; + else if (mime.equals("application/java-archive") || plc.endsWith(".war")) + icon = "package"; + else if (plc.endsWith(".xpi2p")) + icon = "plugin"; + else if (mime.equals("application/pdf")) + icon = "page_white_acrobat"; + else if (mime.startsWith("image/") || plc.endsWith(".ico")) + icon = "photo"; + else if (mime.startsWith("audio/") || mime.equals("application/ogg") || + plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") || + plc.endsWith(".ape")) + icon = "music"; + else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") || + plc.endsWith(".mp4")) + icon = "film"; + else if (mime.equals("application/zip") || mime.equals("application/x-gtar") || + mime.equals("application/compress") || mime.equals("application/gzip") || + mime.equals("application/x-tar") || + plc.endsWith(".rar") || plc.endsWith(".bz2") || plc.endsWith(".7z")) + icon = "compress"; + else if (plc.endsWith(".exe")) + icon = "application"; + else + icon = "bug"; + return icon; + } + + /** @since 0.7.14 */ + private static String toImg(String icon) { + return "\"\" "; + } + /** inner class, don't bother reindenting */ private static class FetchAndAdd implements Runnable { diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index c39e541b2..07997fd10 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -1029,6 +1029,30 @@ public class DataHelper { } } + /** + * Like formatSize but with a space after the number + * @since 0.7.14 + */ + public static String formatSize2(long bytes) { + double val = bytes; + int scale = 0; + while (val >= 1024) { + scale++; + val /= 1024; + } + + DecimalFormat fmt = new DecimalFormat("##0.00"); + + String str = fmt.format(val); + switch (scale) { + case 1: return str + " K"; + case 2: return str + " M"; + case 3: return str + " G"; + case 4: return str + " T"; + default: return bytes + " "; + } + } + /** * Strip out any HTML (simply removing any less than / greater than symbols) */ diff --git a/history.txt b/history.txt index 28f7324ef..a16a2758c 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,7 @@ +2010-05-26 zzz + * i2psnark: Listing fixes and cleanups; + icons on front page; tweak bw choker again + 2010-05-24 zzz * i2psnark: Listing icons and cleanups @@ -6,7 +10,6 @@ - fixed major security hole in DatagramDissector * I2PTunnelServer: Implemented WEBIRC support in IRC server tunnel - 2010-05-23 zzz * i2psnark: - Choke slower when at bandwidth limit diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 5a58b19bc..e36cd3b14 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 11; + public final static long BUILD = 12; /** for example "-test" */ public final static String EXTRA = "";