From d146ef7e09618c4072ee86b092018c85c99eba9d Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Tue, 5 Feb 2008 17:32:27 -0700
Subject: [PATCH] webish: add extra introducer data (version, timestamps) to
 Welcome page

---
 src/allmydata/interfaces.py       |  1 +
 src/allmydata/introducer.py       | 12 +++---
 src/allmydata/test/test_system.py |  6 +--
 src/allmydata/test/test_web.py    | 11 +++++-
 src/allmydata/web/welcome.xhtml   | 17 ++++++--
 src/allmydata/webish.py           | 65 ++++++++++++++++++++++---------
 6 files changed, 79 insertions(+), 33 deletions(-)

diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index b9e50abc..1c7276ce 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -123,6 +123,7 @@ class IIntroducerClient(Interface):
         trying to connect to. Each RemoteServiceConnector has the following
         public attributes::
 
+          service_name: the type of service provided, like 'storage'
           announcement_time: when we first heard about this service
           last_connect_time: when we last established a connection
           last_loss_time: when we last lost a connection
diff --git a/src/allmydata/introducer.py b/src/allmydata/introducer.py
index c8f70720..7519ec4a 100644
--- a/src/allmydata/introducer.py
+++ b/src/allmydata/introducer.py
@@ -113,7 +113,7 @@ class RemoteServiceConnector:
         self._nodeid_s = idlib.shortnodeid_b2a(self._nodeid)
 
         self._index = (self._nodeid, service_name)
-        self._service_name = service_name
+        self.service_name = service_name
 
         self.log("attempting to connect to %s" % self._nodeid_s)
         self.announcement_time = time.time()
@@ -121,8 +121,8 @@ class RemoteServiceConnector:
         self.rref = None
         self.remote_host = None
         self.last_connect_time = None
-        self.version = None
-        self.oldest_supported = None
+        self.version = ver
+        self.oldest_supported = oldest
 
     def log(self, *args, **kwargs):
         return self._ic.log(*args, **kwargs)
@@ -138,12 +138,12 @@ class RemoteServiceConnector:
 
     def _got_service(self, rref):
         self.last_connect_time = time.time()
-        self.remote_host = str(rref.tracker.broker.transport.getPeer())
+        self.remote_host = rref.tracker.broker.transport.getPeer()
 
         self.rref = rref
         self.log("connected to %s" % self._nodeid_s)
 
-        self._ic.add_connection(self._nodeid, self._service_name, rref)
+        self._ic.add_connection(self._nodeid, self.service_name, rref)
 
         rref.notifyOnDisconnect(self._lost, rref)
 
@@ -152,7 +152,7 @@ class RemoteServiceConnector:
         self.last_loss_time = time.time()
         self.rref = None
         self.remote_host = None
-        self._ic.remove_connection(self._nodeid, self._service_name, rref)
+        self._ic.remove_connection(self._nodeid, self.service_name, rref)
 
 
 
diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
index a9c90d68..15a7c62c 100644
--- a/src/allmydata/test/test_system.py
+++ b/src/allmydata/test/test_system.py
@@ -1023,10 +1023,10 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase):
         public = "uri/" + self._root_directory_uri
         d = getPage(base)
         def _got_welcome(page):
-            expected = "Connected Peers: <span>%d</span>" % (self.numclients)
+            expected = "Connected Storage Servers: <span>%d</span>" % (self.numclients)
             self.failUnless(expected in page,
-                            "I didn't see the right 'connected peers' message "
-                            "in: %s" % page
+                            "I didn't see the right 'connected storage servers'"
+                            " message in: %s" % page
                             )
             expected = "My nodeid: <span>%s</span>" % (b32encode(self.clients[0].nodeid).lower(),)
             self.failUnless(expected in page,
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 6d241e90..374d336a 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -13,6 +13,14 @@ from allmydata.interfaces import IURI, INewDirectoryURI, IReadonlyNewDirectoryUR
 # create a fake uploader/downloader, and a couple of fake dirnodes, then
 # create a webserver that works against them
 
+class FakeIntroducerClient:
+    def get_all_connectors(self):
+        return {}
+    def get_all_connections_for(self, service_name):
+        return frozenset()
+    def get_all_peerids(self):
+        return frozenset()
+
 class FakeClient(service.MultiService):
     nodeid = "fake_nodeid"
     basedir = "fake_basedir"
@@ -23,10 +31,9 @@ class FakeClient(service.MultiService):
                 'zfec': "fake",
                 }
     introducer_furl = "None"
+    introducer_client = FakeIntroducerClient()
     def connected_to_introducer(self):
         return False
-    def get_all_peerids(self):
-        return []
 
     def create_node_from_uri(self, uri):
         u = IURI(uri)
diff --git a/src/allmydata/web/welcome.xhtml b/src/allmydata/web/welcome.xhtml
index 73ad3c9d..cf32acb8 100644
--- a/src/allmydata/web/welcome.xhtml
+++ b/src/allmydata/web/welcome.xhtml
@@ -25,15 +25,26 @@ tool</a> may also be useful.</div>
 <div>Helper: <span n:render="string" n:data="helper_furl" /></div>
 <div>Connected to helper?: <span n:render="string" n:data="connected_to_helper" /></div>
 
-<div>Known+Connected Peers: <span n:render="string" n:data="num_peers" /></div>
+<div>Known Storage Servers: <span n:render="string" n:data="known_storage_servers" /></div>
+<div>Connected Storage Servers: <span n:render="string" n:data="connected_storage_servers" /></div>
 
 <div>
-<table n:render="sequence" n:data="peers" border="1">
+<table n:render="sequence" n:data="services" border="1">
   <tr n:pattern="header">
     <td>PeerID</td>
+    <td>Connected?</td>
+    <td>Since</td>
+    <td>Announced</td>
+    <td>Version</td>
+    <td>Service Name</td>
   </tr>
-  <tr n:pattern="item" n:render="row">
+  <tr n:pattern="item" n:render="service_row">
     <td><tt><n:slot name="peerid"/></tt></td>
+    <td><tt><n:slot name="connected"/></tt></td>
+    <td><tt><n:slot name="since"/></tt></td>
+    <td><tt><n:slot name="announced"/></tt></td>
+    <td><tt><n:slot name="version"/></tt></td>
+    <td><tt><n:slot name="service_name"/></tt></td>
   </tr>
   <tr n:pattern="empty"><td>no peers!</td></tr>
 </table>
diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py
index 71b524c8..f4d426a8 100644
--- a/src/allmydata/webish.py
+++ b/src/allmydata/webish.py
@@ -1,14 +1,13 @@
 
-from base64 import b32encode
-import os.path
+import time, os.path
 from twisted.application import service, strports, internet
 from twisted.web import static, resource, server, html, http
 from twisted.python import log
-from twisted.internet import defer
+from twisted.internet import defer, address
 from twisted.internet.interfaces import IConsumer
 from nevow import inevow, rend, loaders, appserver, url, tags as T
 from nevow.static import File as nevow_File # TODO: merge with static.File?
-from allmydata.util import fileutil
+from allmydata.util import fileutil, idlib
 import simplejson
 from allmydata.interfaces import IDownloadTarget, IDirectoryNode, IFileNode, \
      IMutableFileNode
@@ -1314,7 +1313,7 @@ class Root(rend.Page):
         return get_package_versions_string()
 
     def data_my_nodeid(self, ctx, data):
-        return b32encode(IClient(ctx).nodeid).lower()
+        return idlib.nodeid_b2a(IClient(ctx).nodeid)
     def data_introducer_furl(self, ctx, data):
         return IClient(ctx).introducer_furl
     def data_connected_to_introducer(self, ctx, data):
@@ -1339,22 +1338,50 @@ class Root(rend.Page):
             return "yes"
         return "no"
 
-    def data_num_peers(self, ctx, data):
-        #client = inevow.ISite(ctx)._client
-        client = IClient(ctx)
-        return len(list(client.get_all_peerids()))
+    def data_known_storage_servers(self, ctx, data):
+        ic = IClient(ctx).introducer_client
+        servers = [c
+                   for c in ic.get_all_connectors().values()
+                   if c.service_name == "storage"]
+        return len(servers)
+
+    def data_connected_storage_servers(self, ctx, data):
+        ic = IClient(ctx).introducer_client
+        return len(ic.get_all_connections_for("storage"))
+
+    def data_services(self, ctx, data):
+        ic = IClient(ctx).introducer_client
+        c = [ (service_name, nodeid, rsc)
+              for (nodeid, service_name), rsc
+              in ic.get_all_connectors().items() ]
+        c.sort()
+        return c
+
+    def render_service_row(self, ctx, data):
+        (service_name, nodeid, rsc) = data
+        ctx.fillSlots("peerid", idlib.nodeid_b2a(nodeid))
+        if rsc.rref:
+            rhost = rsc.remote_host
+            if nodeid == IClient(ctx).nodeid:
+                rhost_s = "(loopback)"
+            elif isinstance(rhost, address.IPv4Address):
+                rhost_s = "%s:%d" % (rhost.host, rhost.port)
+            else:
+                rhost_s = str(rhost)
+            connected = "Yes: to " + rhost_s
+            since = rsc.last_connect_time
+        else:
+            connected = "No"
+            since = rsc.last_loss_time
 
-    def data_peers(self, ctx, data):
-        d = []
-        client = IClient(ctx)
-        for nodeid in sorted(client.get_all_peerids()):
-            row = (b32encode(nodeid).lower(),)
-            d.append(row)
-        return d
+        TIME_FORMAT = "%H:%M:%S %d-%b-%Y"
+        ctx.fillSlots("connected", connected)
+        ctx.fillSlots("since", time.strftime(TIME_FORMAT, time.localtime(since)))
+        ctx.fillSlots("announced", time.strftime(TIME_FORMAT,
+                                                 time.localtime(rsc.announcement_time)))
+        ctx.fillSlots("version", rsc.version)
+        ctx.fillSlots("service_name", rsc.service_name)
 
-    def render_row(self, ctx, data):
-        (nodeid_a,) = data
-        ctx.fillSlots("peerid", nodeid_a)
         return ctx.tag
 
     # this is a form where users can download files by URI
-- 
2.45.2