From 9f4439583dc084de7876c79291fbc332f762bcc9 Mon Sep 17 00:00:00 2001
From: jrandom <jrandom>
Date: Fri, 23 Jul 2004 17:36:29 +0000
Subject: [PATCH] expose some data points for the new console, and cleaned up
 some html new piece of data exposed and maintained is a list of router
 contexts - shown as a singleton off RouterContext - allowing an app in the
 same JVM to find the routers (and chose between which one they want)

---
 router/java/src/net/i2p/router/Router.java    |  1 +
 .../src/net/i2p/router/RouterContext.java     | 14 ++++
 router/java/src/net/i2p/router/Shitlist.java  |  6 ++
 .../net/i2p/router/TunnelManagerFacade.java   |  4 +
 .../KademliaNetworkDatabaseFacade.java        | 76 ++++++++++++-------
 .../router/peermanager/ProfileOrganizer.java  | 44 ++++++++---
 .../PoolingTunnelManagerFacade.java           |  6 ++
 7 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index f2724759f3..56f3c3b19d 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -491,6 +491,7 @@ public class Router {
         try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
         try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
         try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
+        _context.listContexts().remove(_context);
         dumpStats();
         _log.log(Log.CRIT, "Shutdown complete", new Exception("Shutdown"));
         try { _context.logManager().shutdown(); } catch (Throwable t) { }
diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java
index c0152a7951..62e739fffb 100644
--- a/router/java/src/net/i2p/router/RouterContext.java
+++ b/router/java/src/net/i2p/router/RouterContext.java
@@ -1,5 +1,7 @@
 package net.i2p.router;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 
 import net.i2p.I2PAppContext;
@@ -57,11 +59,14 @@ public class RouterContext extends I2PAppContext {
     private Calculator _reliabilityCalc;
     private Calculator _capacityCalc;
     
+    private static List _contexts = new ArrayList(1);
+    
     public RouterContext(Router router) { this(router, null); }
     public RouterContext(Router router, Properties envProps) { 
         super(envProps);
         _router = router;
         initAll();
+        _contexts.add(this);
     }
     private void initAll() {
         _clientManagerFacade = new ClientManagerFacadeImpl(this);
@@ -94,6 +99,15 @@ public class RouterContext extends I2PAppContext {
         _capacityCalc = new CapacityCalculator(this);
     }
     
+    /**
+     * Retrieve the list of router contexts currently instantiated in this JVM.  
+     * This will always contain only one item (except when a simulation per the
+     * MultiRouter is going on), and the list should only be modified when a new
+     * context is created or a router is shut down.
+     *
+     */
+    public static List listContexts() { return _contexts; }
+    
     /** what router is this context working for? */
     public Router router() { return _router; }
     /** convenience method for querying the router's ident */
diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java
index 64922a82ec..7730b1ef7d 100644
--- a/router/java/src/net/i2p/router/Shitlist.java
+++ b/router/java/src/net/i2p/router/Shitlist.java
@@ -38,6 +38,12 @@ public class Shitlist {
         _shitlist = new HashMap(100);
     }
     
+    public int getRouterCount() {
+        synchronized (_shitlist) {
+            return _shitlist.size();
+        }
+    }
+    
     public boolean shitlistRouter(Hash peer) {
         if (peer == null) return false;
         if (_context.routerHash().equals(peer)) {
diff --git a/router/java/src/net/i2p/router/TunnelManagerFacade.java b/router/java/src/net/i2p/router/TunnelManagerFacade.java
index bd91bdeaab..5448b83385 100644
--- a/router/java/src/net/i2p/router/TunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/TunnelManagerFacade.java
@@ -63,4 +63,8 @@ public interface TunnelManagerFacade extends Service {
     
     /** how many tunnels are we participating in? */
     public int getParticipatingCount();
+    /** how many free inbound tunnels do we have available? */
+    public int getFreeTunnelCount();
+    /** how many outbound tunnels do we have available? */
+    public int getOutboundTunnelCount();
 }
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
index 6ce250a6d1..ca2b02c58c 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -21,10 +21,12 @@ import java.util.Map;
 import java.util.Set;
 
 import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
 import net.i2p.data.DataStructure;
 import net.i2p.data.Hash;
 import net.i2p.data.Lease;
 import net.i2p.data.LeaseSet;
+import net.i2p.data.RouterAddress;
 import net.i2p.data.RouterInfo;
 import net.i2p.data.i2np.DatabaseLookupMessage;
 import net.i2p.data.i2np.DatabaseSearchReplyMessage;
@@ -616,51 +618,73 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
         }
         Set leases = getLeases();
         buf.append("<h3>Leases</h3>\n");
-        buf.append("<table border=\"1\">\n");
         out.write(buf.toString().getBytes());
         buf.setLength(0);
+        long now = _context.clock().now();
         for (Iterator iter = leases.iterator(); iter.hasNext(); ) {
             LeaseSet ls = (LeaseSet)iter.next();
             Hash key = ls.getDestination().calculateHash();
-            buf.append("<tr><td valign=\"top\" align=\"left\"><b>").append(key.toBase64()).append("</b></td>");
-            
-            if (getLastSent(key).longValue() > 0)
-                buf.append("<td valign=\"top\" align=\"left\"><b>Last sent successfully:</b> ").append(new Date(getLastSent(key).longValue())).append("</td></tr>");
-            else
-                buf.append("<td valign=\"top\" align=\"left\"><b>Last sent successfully:</b> never</td></tr>");
-            buf.append("<tr><td valign=\"top\" align=\"left\" colspan=\"2\"><pre>\n").append(ls.toString()).append("</pre></td></tr>\n");
+            buf.append("<b>LeaseSet: ").append(key.toBase64()).append("</b><br />\n");
+            long exp = ls.getEarliestLeaseDate()-now;
+            buf.append("Earliest expiration date in: <i>").append(DataHelper.formatDuration(exp)).append("</i><br />\n");
+            for (int i = 0; i < ls.getLeaseCount(); i++) {
+                buf.append("Lease ").append(i).append(": gateway <i>");
+                buf.append(ls.getLease(i).getRouterIdentity().getHash().toBase64().substring(0,6));
+                buf.append("</i> tunnelId <i>").append(ls.getLease(i).getTunnelId().getTunnelId()).append("</i><br />\n");
+            }
+            buf.append("<hr />\n");
             out.write(buf.toString().getBytes());
             buf.setLength(0);
         }
-        buf.append("</table>\n");
         
         Hash us = _context.routerHash();
         Set routers = getRouters();
-        buf.append("<h3>Routers</h3>\n");
-        buf.append("<table border=\"1\">\n");
+        out.write("<h3>Routers</h3>\n".getBytes());
+        
+        RouterInfo ourInfo = _context.router().getRouterInfo();
+        renderRouterInfo(buf, ourInfo, true);
         out.write(buf.toString().getBytes());
         buf.setLength(0);
-        
         for (Iterator iter = routers.iterator(); iter.hasNext(); ) {
             RouterInfo ri = (RouterInfo)iter.next();
             Hash key = ri.getIdentity().getHash();
             boolean isUs = key.equals(us);
-            if (isUs) {
-                buf.append("<tr><td valign=\"top\" align=\"left\"><font color=\"red\"><b>").append(key.toBase64()).append("</b></font></td>");
-                buf.append("<td valign=\"top\" align=\"left\" colspan=\"2\"><b>Last sent successfully:</b> ").append(new Date(getLastSent(key).longValue())).append("</td></tr>");
-            } else {
-                buf.append("<tr><td valign=\"top\" align=\"left\"><a name=\"").append(key.toBase64().substring(0,32)).append("\"><b>").append(key.toBase64()).append("</b></a></td>");
-                if (getLastSent(key).longValue() > 0)
-                    buf.append("<td valign=\"top\" align=\"left\"><b>Last sent successfully:</b> ").append(new Date(getLastSent(key).longValue())).append("</td>");
-                else
-                    buf.append("<td valign=\"top\" align=\"left\"><b>Last sent successfully:</b> never</td>");
-                buf.append("<td valign=\"top\" align=\"left\"><a href=\"/profile/").append(key.toBase64().substring(0, 32)).append("\">Profile</a></td></tr>");
+            if (!isUs) {
+                renderRouterInfo(buf, ri, false);
+                out.write(buf.toString().getBytes());
+                buf.setLength(0);
             }
-            buf.append("<tr><td valign=\"top\" align=\"left\" colspan=\"3\"><pre>\n").append(ri.toString()).append("</pre></td></tr>\n");
-            out.write(buf.toString().getBytes());
-            buf.setLength(0);
         }
-        out.write("</table>\n".getBytes());
+    }
+    private void renderRouterInfo(StringBuffer buf, RouterInfo info, boolean isUs) {
+        if (isUs) {
+            buf.append("<b>Our info: </b><br />\n");
+        } else {
+            String hash = info.getIdentity().getHash().toBase64();
+            buf.append("<a name=\"").append(hash.substring(0, 6)).append("\" />");
+            buf.append("<b>Peer info for:</b> ").append(hash).append("<br />\n");
+        }
+        
+        long age = _context.clock().now() - info.getPublished();
+        buf.append("Published: <i>").append(DataHelper.formatDuration(age)).append(" ago</i><br />\n");
+        buf.append("Address(es): <i>");
+        for (Iterator iter = info.getAddresses().iterator(); iter.hasNext(); ) {
+            RouterAddress addr = (RouterAddress)iter.next();
+            buf.append(addr.getTransportStyle()).append(": ");
+            for (Iterator optIter = addr.getOptions().keySet().iterator(); optIter.hasNext(); ) {
+                String name = (String)optIter.next();
+                String val = addr.getOptions().getProperty(name);
+                buf.append('[').append(name).append('=').append(val).append("] ");
+            }
+        }
+        buf.append("</i><br />\n");
+        buf.append("Stats: <br /><i><code>\n");
+        for (Iterator iter = info.getOptions().keySet().iterator(); iter.hasNext(); ) {
+            String key = (String)iter.next();
+            String val = info.getOptions().getProperty(key);
+            buf.append(key).append(" = ").append(val).append("<br />\n");
+        }
+        buf.append("</code></i><hr />\n");
     }
     
 }
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index ab81c600da..f27f052f1f 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -167,6 +167,31 @@ public class ProfileOrganizer {
     public int countNotFailingPeers() { synchronized (_reorganizeLock) { return _notFailingPeers.size(); } }
     public int countFailingPeers() { synchronized (_reorganizeLock) { return _failingPeers.size(); } }
     
+    public int countActivePeers() {
+        synchronized (_reorganizeLock) {
+            int activePeers = 0;
+            
+            long hideBefore = _context.clock().now() - 6*60*60*1000;
+            
+            for (Iterator iter = _failingPeers.values().iterator(); iter.hasNext(); ) {
+                PeerProfile profile = (PeerProfile)iter.next();
+                if (profile.getLastSendSuccessful() >= hideBefore)
+                    activePeers++;
+                else if (profile.getLastHeardFrom() >= hideBefore)
+                    activePeers++;
+            }
+            for (Iterator iter = _notFailingPeers.values().iterator(); iter.hasNext(); ) {
+                PeerProfile profile = (PeerProfile)iter.next();
+                if (profile.getLastSendSuccessful() >= hideBefore)
+                    activePeers++;
+                else if (profile.getLastHeardFrom() >= hideBefore)
+                    activePeers++;
+            }
+            
+            return activePeers;
+        }
+    }
+    
     public boolean isFast(Hash peer) { synchronized (_reorganizeLock) { return _fastPeers.containsKey(peer); } }
     public boolean isHighCapacity(Hash peer) { synchronized (_reorganizeLock) { return _highCapacityPeers.containsKey(peer); } }
     public boolean isWellIntegrated(Hash peer) { synchronized (_reorganizeLock) { return _wellIntegratedPeers.containsKey(peer); } }
@@ -628,14 +653,13 @@ public class ProfileOrganizer {
         buf.append("<h2>Peer Profiles</h2>\n");
         buf.append("<table border=\"1\">");
         buf.append("<tr>");
-        buf.append("<td><b>Peer</b> (").append(order.size()).append(", hiding ").append(peers.size()-order.size()).append(" inactive ones)</td>");
+        buf.append("<td><b>Peer</b> (").append(order.size()).append(", hiding ").append(peers.size()-order.size()).append(")</td>");
         buf.append("<td><b>Groups</b></td>");
         buf.append("<td><b>Speed</b></td>");
         buf.append("<td><b>Capacity</b></td>");
         buf.append("<td><b>Integration</b></td>");
         buf.append("<td><b>Failing?</b></td>");
-        buf.append("<td><b>Reliability (deprecated)</b></td>");
-        buf.append("<td><b>Profile data</b></td>");
+        //buf.append("<td><b>Profile data</b></td>");
         buf.append("</tr>");
         for (Iterator iter = order.keySet().iterator(); iter.hasNext();) {
             String name = (String)iter.next();
@@ -645,10 +669,10 @@ public class ProfileOrganizer {
             buf.append("<tr>");
             buf.append("<td><code>");
             if (prof.getIsFailing()) {
-                buf.append("<font color=\"red\">--").append(peer.toBase64()).append("</font>");
+                buf.append("<font color=\"red\">--").append(peer.toBase64().substring(0,6)).append("</font>");
             } else {
                 if (prof.getIsActive()) {
-                    buf.append("<font color=\"blue\">++").append(peer.toBase64()).append("</font>");
+                    buf.append("<font color=\"blue\">++").append(peer.toBase64().substring(0,6)).append("</font>");
                 } else {
                     buf.append("__").append(peer.toBase64());
                 }
@@ -678,20 +702,19 @@ public class ProfileOrganizer {
             }
             
             switch (tier) {
-                case 1: buf.append("Fast+High Capacity"); break;
+                case 1: buf.append("Fast"); break;
                 case 2: buf.append("High Capacity"); break;
                 case 3: buf.append("Not Failing"); break;
                 default: buf.append("Failing"); break;
             }
-            if (isIntegrated) buf.append(", Well integrated");
+            if (isIntegrated) buf.append(", Integrated");
             
             buf.append("<td align=\"right\">").append(num(prof.getSpeedValue())).append("</td>");
             buf.append("<td align=\"right\">").append(num(prof.getCapacityValue())).append("</td>");
             buf.append("<td align=\"right\">").append(num(prof.getIntegrationValue())).append("</td>");
             buf.append("<td align=\"right\">").append(prof.getIsFailing()).append("</td>");
-            buf.append("<td align=\"right\">").append(num(prof.getReliabilityValue())).append("</td>");
-            buf.append("<td><a href=\"/profile/").append(prof.getPeer().toBase64().substring(0, 32)).append("\">profile.txt</a> ");
-            buf.append("    <a href=\"#").append(prof.getPeer().toBase64().substring(0, 32)).append("\">netDb</a></td>");
+            //buf.append("<td><a href=\"/profile/").append(prof.getPeer().toBase64().substring(0, 32)).append("\">profile.txt</a> ");
+            //buf.append("    <a href=\"#").append(prof.getPeer().toBase64().substring(0, 32)).append("\">netDb</a></td>");
             buf.append("</tr>");
         }
         buf.append("</table>");
@@ -700,7 +723,6 @@ public class ProfileOrganizer {
         buf.append("<li><b>capacity</b>: how many tunnels can we ask them to join in an hour?</li>");
         buf.append("<li><b>integration</b>: how many new peers have they told us about lately?</li>");
         buf.append("<li><b>failing?</b>: is the peer currently swamped (and if possible we should avoid nagging them)?</li>");
-        buf.append("<li><b>reliability</b>: no sound semantics... just a random kludge of a value.</li>");
         buf.append("</ul></i>");
         buf.append("Red peers prefixed with '--' means the peer is failing, and blue peers prefixed ");
         buf.append("with '++' means we've sent or received a message from them ");
diff --git a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
index 851a19656a..f4539b7400 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
@@ -212,6 +212,12 @@ public class PoolingTunnelManagerFacade implements TunnelManagerFacade {
     public int getParticipatingCount() {
         return _pool.getParticipatingTunnelCount();
     }
+    public int getFreeTunnelCount() {
+        return _pool.getFreeTunnelCount();
+    }
+    public int getOutboundTunnelCount() {
+        return _pool.getOutboundTunnelCount();
+    }
     
     /**
      * Aint she pretty?
-- 
GitLab