From c86388b79c34ba0e71bee01e5c739db2ae6e3403 Mon Sep 17 00:00:00 2001
From: Leif Ryge <leif@synthesize.us>
Date: Sat, 23 Jan 2016 14:03:05 +0000
Subject: [PATCH] revert previous commit to fix attribution (vanity)

This reverts the previous commit (modulo the one line that daira added) so that
my contributions will be properly attributed by git blame etc.
---
 src/allmydata/interfaces.py                |  1 +
 src/allmydata/storage_client.py            |  9 +++---
 src/allmydata/test/common_util.py          | 18 -----------
 src/allmydata/test/test_util.py            | 34 --------------------
 src/allmydata/test/test_web.py             | 37 ++++++----------------
 src/allmydata/util/time_format.py          | 24 --------------
 src/allmydata/web/common.py                |  8 +----
 src/allmydata/web/root.py                  | 37 ++++++++--------------
 src/allmydata/web/static/css/new-tahoe.css |  9 ------
 src/allmydata/web/welcome.xhtml            | 16 ++++++----
 src/allmydata/webish.py                    |  4 +--
 11 files changed, 40 insertions(+), 157 deletions(-)

diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index 31fc6144..e495c759 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -417,6 +417,7 @@ class IStorageBroker(Interface):
         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/storage_client.py b/src/allmydata/storage_client.py
index 81dc0042..dd9780f2 100644
--- a/src/allmydata/storage_client.py
+++ b/src/allmydata/storage_client.py
@@ -168,6 +168,7 @@ class NativeStorageServer:
     the their version information. I remember information about when we were
     last connected too, even if we aren't currently connected.
 
+    @ivar announcement_time: when we first heard about this service
     @ivar last_connect_time: when we last established a connection
     @ivar last_loss_time: when we last lost a connection
 
@@ -215,6 +216,7 @@ class NativeStorageServer:
             self._long_description = tubid_s
             self._short_description = tubid_s[:6]
 
+        self.announcement_time = time.time()
         self.last_connect_time = None
         self.last_loss_time = None
         self.remote_host = None
@@ -265,11 +267,8 @@ class NativeStorageServer:
         return self.last_connect_time
     def get_last_loss_time(self):
         return self.last_loss_time
-    def get_last_received_data_time(self):
-        if self.rref is None:
-            return None
-        else:
-            return self.rref.getDataLastReceivedAt()
+    def get_announcement_time(self):
+        return self.announcement_time
 
     def get_available_space(self):
         version = self.get_version()
diff --git a/src/allmydata/test/common_util.py b/src/allmydata/test/common_util.py
index 47dbe59a..e51ab8b0 100644
--- a/src/allmydata/test/common_util.py
+++ b/src/allmydata/test/common_util.py
@@ -173,24 +173,6 @@ class TestMixin(SignalMixin):
         if required_to_quiesce and active:
             self.fail("Reactor was still active when it was required to be quiescent.")
 
-
-class TimezoneMixin(object):
-
-    def setTimezone(self, timezone):
-        unset = object()
-        originalTimezone = os.environ.get('TZ', unset)
-        def restoreTimezone():
-            if originalTimezone is unset:
-                del os.environ['TZ']
-                time.tzset()
-            else:
-                os.environ['TZ'] = originalTimezone
-                time.tzset()
-        os.environ['TZ'] = timezone
-        time.tzset()
-        self.addCleanup(restoreTimezone)
-
-
 try:
     import win32file
     import win32con
diff --git a/src/allmydata/test/test_util.py b/src/allmydata/test/test_util.py
index 5fe2fbd0..adaec89f 100644
--- a/src/allmydata/test/test_util.py
+++ b/src/allmydata/test/test_util.py
@@ -1021,40 +1021,6 @@ class TimeFormat(unittest.TestCase):
 
     test_format_time_y2038.todo = "This test is known to fail on systems with 32-bit time_t."
 
-    def test_format_delta(self):
-        time_1 = 1389812723
-        time_5s_delta = 1389812728
-        time_28m7s_delta = 1389814410
-        time_1h_delta = 1389816323
-        time_1d21h46m49s_delta = 1389977532
-
-        self.failUnlessEqual(
-            time_format.format_delta(time_1, time_1), '0s')
-
-        self.failUnlessEqual(
-            time_format.format_delta(time_1, time_5s_delta), '5s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1, time_28m7s_delta), '28m 7s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1, time_1h_delta), '1h 0m 0s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1, time_1d21h46m49s_delta), '1d 21h 46m 49s')
-
-        self.failUnlessEqual(
-            time_format.format_delta(time_1d21h46m49s_delta, time_1), '-')
-
-        # time_1 with a decimal fraction will make the delta 1s less
-        time_1decimal = 1389812723.383963
-
-        self.failUnlessEqual(
-            time_format.format_delta(time_1decimal, time_5s_delta), '4s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1decimal, time_28m7s_delta), '28m 6s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1decimal, time_1h_delta), '59m 59s')
-        self.failUnlessEqual(
-            time_format.format_delta(time_1decimal, time_1d21h46m49s_delta), '1d 21h 46m 48s')
-
 class CacheDir(unittest.TestCase):
     def test_basic(self):
         basedir = "test_util/CacheDir/test_basic"
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 5b151ecb..723ae7ac 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -172,28 +172,21 @@ class FakeHistory:
         return []
 
 class FakeDisplayableServer(StubServer):
-    def __init__(self, serverid, nickname, connected,
-                 last_connect_time, last_loss_time, last_rx_time):
+    def __init__(self, serverid, nickname):
         StubServer.__init__(self, serverid)
         self.announcement = {"my-version": "allmydata-tahoe-fake",
                              "service-name": "storage",
                              "nickname": nickname}
-        self.connected = connected
-        self.last_loss_time = last_loss_time
-        self.last_rx_time = last_rx_time
-        self.last_connect_time = last_connect_time
     def is_connected(self):
-        return self.connected
+        return True
     def get_permutation_seed(self):
         return ""
     def get_remote_host(self):
         return ""
     def get_last_loss_time(self):
-        return self.last_loss_time
-    def get_last_received_data_time(self):
-        return self.last_rx_time
-    def get_last_connect_time(self):
-        return self.last_connect_time
+        return None
+    def get_announcement_time(self):
+        return None
     def get_announcement(self):
         return self.announcement
     def get_nickname(self):
@@ -249,13 +242,7 @@ class FakeClient(Client):
         self.storage_broker = StorageFarmBroker(None, permute_peers=True)
         # fake knowledge of another server
         self.storage_broker.test_add_server("other_nodeid",
-            FakeDisplayableServer(
-                serverid="other_nodeid", nickname=u"other_nickname \u263B", connected = True,
-                last_connect_time = 10, last_loss_time = 20, last_rx_time = 30))
-        self.storage_broker.test_add_server("disconnected_nodeid",
-            FakeDisplayableServer(
-                serverid="other_nodeid", nickname=u"disconnected_nickname \u263B", connected = False,
-                last_connect_time = 15, last_loss_time = 25, last_rx_time = 35))
+                                            FakeDisplayableServer("other_nodeid", u"other_nickname \u263B"))
         self.introducer_client = None
         self.history = FakeHistory()
         self.uploader = FakeUploader()
@@ -281,16 +268,14 @@ class FakeClient(Client):
 
     MUTABLE_SIZELIMIT = FakeMutableFileNode.MUTABLE_SIZELIMIT
 
-class WebMixin(testutil.TimezoneMixin):
+class WebMixin(object):
     def setUp(self):
-        self.setTimezone('UTC-13:00')
         self.s = FakeClient()
         self.s.startService()
         self.staticdir = self.mktemp()
         self.clock = Clock()
-        self.fakeTime = 86460 # 1d 0h 1m 0s
         self.ws = webish.WebishServer(self.s, "0", staticdir=self.staticdir,
-                                      clock=self.clock, now_fn=lambda:self.fakeTime)
+                                      clock=self.clock)
         self.ws.setServiceParent(self.s)
         self.webish_port = self.ws.getPortnum()
         self.webish_url = self.ws.getURL()
@@ -616,6 +601,7 @@ class WebMixin(testutil.TimezoneMixin):
             self.fail("%s was supposed to Error(302), not get '%s'" %
                       (which, res))
 
+
 class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, unittest.TestCase):
     def test_create(self):
         pass
@@ -633,11 +619,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
             res_u = res.decode('utf-8')
             self.failUnlessIn(u'<td>fake_nickname \u263A</td>', res_u)
             self.failUnlessIn(u'<div class="nickname">other_nickname \u263B</div>', res_u)
-            self.failUnlessIn(u'Connected to <span>1</span>\n              of <span>2</span> known storage servers', res_u)
-            self.failUnlessIn(u'<div class="status-indicator"><img src="img/connected-yes.png" alt="Connected" /></div>\n                <a class="timestamp" title="1970-01-01 13:00:10">1d\u00A00h\u00A00m\u00A050s</a>', res_u)
-            self.failUnlessIn(u'<div class="status-indicator"><img src="img/connected-no.png" alt="Disconnected" /></div>\n                <a class="timestamp" title="1970-01-01 13:00:25">1d\u00A00h\u00A00m\u00A035s</a>', res_u)
-            self.failUnlessIn(u'<td class="service-last-received-data"><a class="timestamp" title="1970-01-01 13:00:30">1d\u00A00h\u00A00m\u00A030s</a></td>', res_u)
-            self.failUnlessIn(u'<td class="service-last-received-data"><a class="timestamp" title="1970-01-01 13:00:35">1d\u00A00h\u00A00m\u00A025s</a></td>', res_u)
             self.failUnlessIn(u'\u00A9 <a href="https://tahoe-lafs.org/">Tahoe-LAFS Software Foundation', res_u)
             self.failUnlessIn('<td><h3>Available</h3></td>', res)
             self.failUnlessIn('123.5kB', res)
diff --git a/src/allmydata/util/time_format.py b/src/allmydata/util/time_format.py
index a6fe3ec7..c481adc3 100644
--- a/src/allmydata/util/time_format.py
+++ b/src/allmydata/util/time_format.py
@@ -66,27 +66,3 @@ def parse_date(s):
     # day
     return int(iso_utc_time_to_seconds(s + "T00:00:00"))
 
-def format_delta(time_1, time_2):
-    if time_1 is None:
-        return "N/A"
-    if time_1 > time_2:
-        return '-'
-    delta = int(time_2 - time_1)
-    seconds = delta % 60
-    delta  -= seconds
-    minutes = (delta / 60) % 60
-    delta  -= minutes * 60
-    hours   = delta / (60*60) % 24
-    delta  -= hours * 24
-    days    = delta / (24*60*60)
-    if not days:
-        if not hours:
-            if not minutes:
-                return "%ss" % (seconds)
-            else:
-                return "%sm %ss" % (minutes, seconds)
-        else:
-            return "%sh %sm %ss" % (hours, minutes, seconds)
-    else:
-        return "%sd %sh %sm %ss" % (days, hours, minutes, seconds)
-
diff --git a/src/allmydata/web/common.py b/src/allmydata/web/common.py
index 5cfe84d9..b8e6d5b4 100644
--- a/src/allmydata/web/common.py
+++ b/src/allmydata/web/common.py
@@ -15,7 +15,7 @@ from allmydata.interfaces import ExistingChildError, NoSuchChildError, \
      MustBeReadonlyError, MustNotBeUnknownRWError, SDMF_VERSION, MDMF_VERSION
 from allmydata.mutable.common import UnrecoverableFileError
 from allmydata.util import abbreviate
-from allmydata.util.time_format import format_time, format_delta
+from allmydata.util.time_format import format_time
 from allmydata.util.encodingutil import to_str, quote_output
 
 
@@ -213,15 +213,9 @@ def text_plain(text, ctx):
 def spaces_to_nbsp(text):
     return unicode(text).replace(u' ', u'\u00A0')
 
-def render_time_delta(time_1, time_2):
-    return spaces_to_nbsp(format_delta(time_1, time_2))
-
 def render_time(t):
     return spaces_to_nbsp(format_time(time.localtime(t)))
 
-def render_time_attr(t):
-    return format_time(time.localtime(t))
-
 class WebError(Exception):
     def __init__(self, text, code=http.BAD_REQUEST):
         self.text = text
diff --git a/src/allmydata/web/root.py b/src/allmydata/web/root.py
index d8d789cf..c46a6dd5 100644
--- a/src/allmydata/web/root.py
+++ b/src/allmydata/web/root.py
@@ -14,7 +14,7 @@ from allmydata.interfaces import IFileNode
 from allmydata.web import filenode, directory, unlinked, status, operations
 from allmydata.web import storage
 from allmydata.web.common import abbreviate_size, getxmlfile, WebError, \
-     get_arg, RenderMixin, get_format, get_mutable_type, render_time_delta, render_time, render_time_attr
+     get_arg, RenderMixin, get_format, get_mutable_type, render_time
 
 
 class URIHandler(RenderMixin, rend.Page):
@@ -138,13 +138,12 @@ class Root(rend.Page):
         "no": "Disconnected",
         }
 
-    def __init__(self, client, clock=None, now_fn=None):
+    def __init__(self, client, clock=None):
         rend.Page.__init__(self, client)
         self.client = client
         # If set, clock is a twisted.internet.task.Clock that the tests
         # use to test ophandle expiration.
         self.child_operations = operations.OphandleTable(clock)
-        self.now_fn = now_fn
         try:
             s = client.getServiceNamed("storage")
         except KeyError:
@@ -283,7 +282,7 @@ class Root(rend.Page):
         ctx.fillSlots("peerid", server.get_longname())
         ctx.fillSlots("nickname", server.get_nickname())
         rhost = server.get_remote_host()
-        if server.is_connected():
+        if rhost:
             if nodeid == self.client.nodeid:
                 rhost_s = "(loopback)"
             elif isinstance(rhost, address.IPv4Address):
@@ -291,37 +290,29 @@ class Root(rend.Page):
             else:
                 rhost_s = str(rhost)
             addr = rhost_s
-            service_connection_status = "yes"
-            last_connect_time = server.get_last_connect_time()
-            service_connection_status_rel_time = render_time_delta(last_connect_time, self.now_fn())
-            service_connection_status_abs_time = render_time_attr(last_connect_time)
+            connected = "yes"
+            since = server.get_last_connect_time()
         else:
             addr = "N/A"
-            service_connection_status = "no"
-            last_loss_time = server.get_last_loss_time()
-            service_connection_status_rel_time = render_time_delta(last_loss_time, self.now_fn())
-            service_connection_status_abs_time = render_time_attr(last_loss_time)
-
-        last_received_data_time = server.get_last_received_data_time()
-        last_received_data_rel_time = render_time_delta(last_received_data_time, self.now_fn())
-        last_received_data_abs_time = render_time_attr(last_received_data_time)
-
+            connected = "no"
+            since = server.get_last_loss_time()
+        announced = server.get_announcement_time()
         announcement = server.get_announcement()
         version = announcement["my-version"]
+        service_name = announcement["service-name"]
         available_space = server.get_available_space()
         if available_space is None:
             available_space = "N/A"
         else:
             available_space = abbreviate_size(available_space)
         ctx.fillSlots("address", addr)
-        ctx.fillSlots("service_connection_status", service_connection_status)
-        ctx.fillSlots("service_connection_status_alt", self._connectedalts[service_connection_status])
+        ctx.fillSlots("connected", connected)
+        ctx.fillSlots("connected_alt", self._connectedalts[connected])
         ctx.fillSlots("connected-bool", bool(rhost))
-        ctx.fillSlots("service_connection_status_abs_time", service_connection_status_abs_time)
-        ctx.fillSlots("service_connection_status_rel_time", service_connection_status_rel_time)
-        ctx.fillSlots("last_received_data_abs_time", last_received_data_abs_time)
-        ctx.fillSlots("last_received_data_rel_time", last_received_data_rel_time)
+        ctx.fillSlots("since", render_time(since))
+        ctx.fillSlots("announced", render_time(announced))
         ctx.fillSlots("version", version)
+        ctx.fillSlots("service_name", service_name)
         ctx.fillSlots("available_space", available_space)
 
         return ctx.tag
diff --git a/src/allmydata/web/static/css/new-tahoe.css b/src/allmydata/web/static/css/new-tahoe.css
index 8ab7f47d..175c3e33 100644
--- a/src/allmydata/web/static/css/new-tahoe.css
+++ b/src/allmydata/web/static/css/new-tahoe.css
@@ -77,12 +77,3 @@ body {
     float: left;
     margin: 5px;
 }
-
-.nickname-and-peerid .timestamp {
-    float: right;
-}
-
-a.timestamp {
-    color: inherit;
-    text-decoration:none;
-}
diff --git a/src/allmydata/web/welcome.xhtml b/src/allmydata/web/welcome.xhtml
index ca238767..3e23fc73 100644
--- a/src/allmydata/web/welcome.xhtml
+++ b/src/allmydata/web/welcome.xhtml
@@ -1,5 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
-      Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
 <html lang="en" xmlns:n="http://nevow.com/ns/nevow/0.1">
   <head>
     <meta charset="utf-8"/>
@@ -170,24 +169,27 @@
               <tr n:pattern="header">
                 <td><h3>Nickname</h3></td>
                 <td><h3>Address</h3></td>
-                <td><h3>Last&nbsp;RX</h3></td>
+                <td><h3>Service</h3></td>
+                <td><h3>Since</h3></td>
+                <td><h3>Announced</h3></td>
                 <td><h3>Version</h3></td>
                 <td><h3>Available</h3></td>
               </tr>
             </thead>
             <tr n:pattern="item" n:render="service_row">
               <td class="nickname-and-peerid">
-                <div class="status-indicator"><img><n:attr name="src">img/connected-<n:slot name="service_connection_status" />.png</n:attr><n:attr name="alt"><n:slot name="service_connection_status_alt" /></n:attr></img></div>
-                <a class="timestamp"><n:attr name="title"><n:slot name="service_connection_status_abs_time"/></n:attr><n:slot name="service_connection_status_rel_time"/></a>
+              <div class="status-indicator"><img><n:attr name="src">img/connected-<n:slot name="connected" />.png</n:attr><n:attr name="alt"><n:slot name="connected_alt" /></n:attr></img></div>
                 <div class="nickname"><n:slot name="nickname"/></div>
                 <div class="nodeid"><n:slot name="peerid"/></div>
               </td>
               <td class="address"><n:slot name="address"/></td>
-              <td class="service-last-received-data"><a class="timestamp"><n:attr name="title"><n:slot name="last_received_data_abs_time"/></n:attr><n:slot name="last_received_data_rel_time"/></a></td>
+            <td class="service-service-name"><n:slot name="service_name"/></td>
+              <td class="service-since timestamp"><n:slot name="since"/></td>
+              <td class="service-announced timestamp"><n:slot name="announced"/></td>
               <td class="service-version"><n:slot name="version"/></td>
               <td class="service-available-space"><n:slot name="available_space"/></td>
             </tr>
-            <tr n:pattern="empty"><td colspan="5">You are not presently connected to any peers</td></tr>
+            <tr n:pattern="empty"><td>You are not presently connected to any peers</td></tr>
           </table>
         </div><!--/span-->
       </div><!--/row-->
diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py
index b26b34da..e2029fee 100644
--- a/src/allmydata/webish.py
+++ b/src/allmydata/webish.py
@@ -129,14 +129,14 @@ class WebishServer(service.MultiService):
     name = "webish"
 
     def __init__(self, client, webport, nodeurl_path=None, staticdir=None,
-                 clock=None, now_fn=time.time):
+                 clock=None):
         service.MultiService.__init__(self)
         # the 'data' argument to all render() methods default to the Client
         # the 'clock' argument to root.Root is, if set, a
         # twisted.internet.task.Clock that is provided by the unit tests
         # so that they can test features that involve the passage of
         # time in a deterministic manner.
-        self.root = root.Root(client, clock, now_fn)
+        self.root = root.Root(client, clock)
         self.buildServer(webport, nodeurl_path, staticdir)
         if self.root.child_operations:
             self.site.remember(self.root.child_operations, IOpHandleTable)
-- 
2.45.2