From c073565eccee2491b43d1ac075e790043399df5b Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@lothar.com>
Date: Tue, 12 Jun 2012 14:01:24 -0700
Subject: [PATCH] Display serverids consistently as 8-char pubkey, or 6-char
 tubid.

This makes it easy to distinguish between old V1-Introducer
nodes (identified by their Foolscap TubID) and new V2 nodes (identified
by their ed25519 pubkey).

This fixes a few places where we used to display a tubid even if we had
a pubkey, making it hard to visually correlate servers in two different
displays. It also cleans up the way we pass serverids to the JS-based
download timeline.

The "introweb" subscribed-clients list still shows tubids.
---
 src/allmydata/storage_client.py               |  2 +-
 src/allmydata/test/test_web.py                | 27 ++++++------
 .../web/static/download_status_timeline.js    |  2 +-
 src/allmydata/web/status.py                   | 41 ++++++++++---------
 4 files changed, 35 insertions(+), 37 deletions(-)

diff --git a/src/allmydata/storage_client.py b/src/allmydata/storage_client.py
index d4397d69..68823f01 100644
--- a/src/allmydata/storage_client.py
+++ b/src/allmydata/storage_client.py
@@ -208,7 +208,7 @@ class NativeStorageServer:
                 self._short_description = key_s[:8]
         else:
             self._long_description = tubid_s
-            self._short_description = tubid_s[:8]
+            self._short_description = tubid_s[:6]
 
         self.announcement_time = time.time()
         self.last_connect_time = None
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index b99b9bb5..2483236d 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -15,7 +15,7 @@ from nevow import rend
 
 from allmydata import interfaces, uri, webish, dirnode
 from allmydata.storage.shares import get_share_file
-from allmydata.storage_client import StorageFarmBroker
+from allmydata.storage_client import StorageFarmBroker, StubServer
 from allmydata.immutable import upload
 from allmydata.immutable.downloader.status import DownloadStatus
 from allmydata.dirnode import DirectoryNode
@@ -102,19 +102,12 @@ class FakeUploader(service.Service):
     def get_helper_info(self):
         return (None, False)
 
-class FakeIServer:
-    def __init__(self, binaryserverid):
-        self.binaryserverid = binaryserverid
-    def get_name(self): return "short"
-    def get_longname(self): return "long"
-    def get_serverid(self): return self.binaryserverid
-
 def build_one_ds():
     ds = DownloadStatus("storage_index", 1234)
     now = time.time()
 
-    serverA = FakeIServer(hashutil.tagged_hash("foo", "serverid_a")[:20])
-    serverB = FakeIServer(hashutil.tagged_hash("foo", "serverid_b")[:20])
+    serverA = StubServer(hashutil.tagged_hash("foo", "serverid_a")[:20])
+    serverB = StubServer(hashutil.tagged_hash("foo", "serverid_b")[:20])
     storage_index = hashutil.storage_index_hash("SI")
     e0 = ds.add_segment_request(0, now)
     e0.activate(now+0.5)
@@ -586,11 +579,15 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
             cmpu_id = base32.b2a(hashutil.tagged_hash("foo", "serverid_b")[:20])
             # serverids[] keys are strings, since that's what JSON does, but
             # we'd really like them to be ints
-            self.failUnlessEqual(data["serverids"]["0"], "phwr")
-            self.failUnless(data["serverids"].has_key("1"), data["serverids"])
-            self.failUnlessEqual(data["serverids"]["1"], "cmpu", data["serverids"])
-            self.failUnlessEqual(data["server_info"][phwr_id]["short"], "phwr")
-            self.failUnlessEqual(data["server_info"][cmpu_id]["short"], "cmpu")
+            self.failUnlessEqual(data["serverids"]["0"], "phwrsjte")
+            self.failUnless(data["serverids"].has_key("1"),
+                            str(data["serverids"]))
+            self.failUnlessEqual(data["serverids"]["1"], "cmpuvkjm",
+                                 str(data["serverids"]))
+            self.failUnlessEqual(data["server_info"][phwr_id]["short"],
+                                 "phwrsjte")
+            self.failUnlessEqual(data["server_info"][cmpu_id]["short"],
+                                 "cmpuvkjm")
             self.failUnlessIn("dyhb", data)
             self.failUnlessIn("misc", data)
         d.addCallback(_check_dl_json)
diff --git a/src/allmydata/web/static/download_status_timeline.js b/src/allmydata/web/static/download_status_timeline.js
index fb5d691a..efd3ee37 100644
--- a/src/allmydata/web/static/download_status_timeline.js
+++ b/src/allmydata/web/static/download_status_timeline.js
@@ -389,7 +389,7 @@ function onDataReceived(data) {
              .attr("stroke", function(d){return shnum_colors(d.shnum);})
              .attr("stroke-width", 1)
              .attr("title", function(d){
-                       return "sh"+d.shnum+"-on-"+d.serverid.slice(0,4)
+                       return "sh"+d.shnum+"-on-"+servername(d)
                            +" ["+d.start+":+"+d.length+"] -> "
                            +d.response_length;})
         ;
diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py
index 7ca8e4a5..89e6b640 100644
--- a/src/allmydata/web/status.py
+++ b/src/allmydata/web/status.py
@@ -365,7 +365,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
         for ev in events:
             ev = ev.copy()
             if ev.has_key('server'):
-                ev["serverid"] = base32.b2a(ev["server"].get_serverid())
+                ev["serverid"] = ev["server"].get_longname()
                 del ev["server"]
             # find an empty slot in the rows
             free_slot = None
@@ -405,7 +405,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
         for ev in events:
             # DownloadStatus promises to give us events in temporal order
             ev = ev.copy()
-            ev["serverid"] = base32.b2a(ev["server"].get_serverid())
+            ev["serverid"] = ev["server"].get_longname()
             del ev["server"]
             if ev["serverid"] not in serverid_to_group:
                 groupnum = len(serverid_to_group)
@@ -453,23 +453,23 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
                                           "start_time", "finish_time")
         data["block"],data["block_rownums"] = self._find_overlap_requests(ds.block_requests)
 
-        servernums = {}
-        serverid_strings = {}
-        for d_ev in data["dyhb"]:
-            if d_ev["serverid"] not in servernums:
-                servernum = len(servernums)
-                servernums[d_ev["serverid"]] = servernum
-                #title= "%s: %s" % ( ",".join([str(shnum) for shnum in shnums]))
-                serverid_strings[servernum] = d_ev["serverid"][:4]
-        data["server_info"] = dict([(serverid, {"num": servernums[serverid],
-                                                "color": self.color(base32.a2b(serverid)),
-                                                "short": serverid_strings[servernums[serverid]],
-                                                })
-                                   for serverid in servernums.keys()])
-        data["num_serverids"] = len(serverid_strings)
+        server_info = {} # maps longname to {num,color,short}
+        server_shortnames = {} # maps servernum to shortname
+        for d_ev in ds.dyhb_requests:
+            s = d_ev["server"]
+            longname = s.get_longname()
+            if longname not in server_info:
+                num = len(server_info)
+                server_info[longname] = {"num": num,
+                                         "color": self.color(s),
+                                         "short": s.get_name() }
+                server_shortnames[str(num)] = s.get_name()
+
+        data["server_info"] = server_info
+        data["num_serverids"] = len(server_info)
         # we'd prefer the keys of serverids[] to be ints, but this is JSON,
         # so they get converted to strings. Stupid javascript.
-        data["serverids"] = serverid_strings
+        data["serverids"] = server_shortnames
         data["bounds"] = {"min": ds.first_timestamp, "max": ds.last_timestamp}
         return simplejson.dumps(data, indent=1) + "\n"
 
@@ -503,7 +503,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
                 rtt = received - sent
             if not shnums:
                 shnums = ["-"]
-            t[T.tr(style="background: %s" % self.color(server.get_serverid()))[
+            t[T.tr(style="background: %s" % self.color(server))[
                 [T.td[server.get_name()], T.td[srt(sent)], T.td[srt(received)],
                  T.td[",".join([str(shnum) for shnum in shnums])],
                  T.td[self.render_time(None, rtt)],
@@ -583,7 +583,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
             rtt = None
             if r_ev["finish_time"] is not None:
                 rtt = r_ev["finish_time"] - r_ev["start_time"]
-            color = self.color(server.get_serverid())
+            color = self.color(server)
             t[T.tr(style="background: %s" % color)[
                 T.td[server.get_name()], T.td[r_ev["shnum"]],
                 T.td["[%d:+%d]" % (r_ev["start"], r_ev["length"])],
@@ -597,7 +597,8 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
 
         return l
 
-    def color(self, peerid):
+    def color(self, server):
+        peerid = server.get_serverid() # binary
         def m(c):
             return min(ord(c) / 2 + 0x80, 0xff)
         return "#%02x%02x%02x" % (m(peerid[0]), m(peerid[1]), m(peerid[2]))
-- 
2.45.2