From 301dd3d489c3651737c066dec354577654fa2a29 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Tue, 26 Feb 2008 15:35:28 -0700
Subject: [PATCH] webish status: distinguish active uploads/downloads from
 recent ones

---
 src/allmydata/download.py      | 11 ++++++-
 src/allmydata/interfaces.py    |  4 +++
 src/allmydata/test/test_web.py |  2 +-
 src/allmydata/upload.py        | 16 ++++++++++
 src/allmydata/web/status.xhtml | 57 +++++++++++++++++++++++++++++-----
 src/allmydata/webish.py        | 13 +++++---
 6 files changed, 89 insertions(+), 14 deletions(-)

diff --git a/src/allmydata/download.py b/src/allmydata/download.py
index 7632f1e0..60a3e4f1 100644
--- a/src/allmydata/download.py
+++ b/src/allmydata/download.py
@@ -336,6 +336,7 @@ class DownloadStatus:
         self.progress = 0.0
         self.paused = False
         self.stopped = False
+        self.active = True
 
     def get_storage_index(self):
         return self.storage_index
@@ -352,6 +353,8 @@ class DownloadStatus:
         return status
     def get_progress(self):
         return self.progress
+    def get_active(self):
+        return self.active
 
     def set_storage_index(self, si):
         self.storage_index = si
@@ -367,7 +370,8 @@ class DownloadStatus:
         self.stopped = stopped
     def set_progress(self, value):
         self.progress = value
-
+    def set_active(self, value):
+        self.active = value
 
 class FileDownloader:
     implements(IPushProducer)
@@ -392,6 +396,7 @@ class FileDownloader:
         s.set_storage_index(self._storage_index)
         s.set_size(self._size)
         s.set_helper(False)
+        s.set_active(True)
 
         if IConsumer.providedBy(downloadable):
             downloadable.registerProducer(self, True)
@@ -448,6 +453,7 @@ class FileDownloader:
         self._stopped = True
         if self._status:
             self._status.set_stopped(True)
+            self._status.set_active(False)
 
     def start(self):
         self.log("starting download")
@@ -465,6 +471,7 @@ class FileDownloader:
         def _finished(res):
             if self._status:
                 self._status.set_status("Finished")
+                self._status.set_active(False)
             if IConsumer.providedBy(self._downloadable):
                 self._downloadable.unregisterProducer()
             return res
@@ -472,6 +479,7 @@ class FileDownloader:
         def _failed(why):
             if self._status:
                 self._status.set_status("Failed")
+                self._status.set_active(False)
             self._output.fail(why)
             return why
         d.addErrback(_failed)
@@ -809,6 +817,7 @@ class LiteralDownloader:
         s.set_storage_index(None)
         s.set_helper(False)
         s.set_status("Done")
+        s.set_active(False)
         s.set_progress(1.0)
 
     def start(self):
diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index fe030101..07d1cc79 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -1420,6 +1420,8 @@ class IUploadStatus(Interface):
         process has finished: for helper uploads this is dependent upon the
         helper providing progress reports. It might be reasonable to add all
         three numbers and report the sum to the user."""
+    def get_active():
+        """Return True if the upload is currently active, False if not."""
 
 class IDownloadStatus(Interface):
     def get_storage_index():
@@ -1439,6 +1441,8 @@ class IDownloadStatus(Interface):
         """Returns a float (from 0.0 to 1.0) describing the amount of the
         download that has completed. This value will remain at 0.0 until the
         first byte of plaintext is pushed to the download target."""
+    def get_active():
+        """Return True if the download is currently active, False if not."""
 
 
 class NotCapableError(Exception):
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 487b1bd3..c78b0401 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -377,7 +377,7 @@ class Web(WebMixin, unittest.TestCase):
     def test_status(self):
         d = self.GET("/status")
         def _check(res):
-            self.failUnless('Current Uploads and Downloads' in res)
+            self.failUnless('Upload and Download Status' in res)
         d.addCallback(_check)
         return d
 
diff --git a/src/allmydata/upload.py b/src/allmydata/upload.py
index 8d7a6339..bef05b92 100644
--- a/src/allmydata/upload.py
+++ b/src/allmydata/upload.py
@@ -568,6 +568,7 @@ class UploadStatus:
         self.helper = False
         self.status = "Not started"
         self.progress = [0.0, 0.0, 0.0]
+        self.active = True
 
     def get_storage_index(self):
         return self.storage_index
@@ -579,6 +580,8 @@ class UploadStatus:
         return self.status
     def get_progress(self):
         return tuple(self.progress)
+    def get_active(self):
+        return self.active
 
     def set_storage_index(self, si):
         self.storage_index = si
@@ -591,6 +594,8 @@ class UploadStatus:
     def set_progress(self, which, value):
         # [0]: chk, [1]: ciphertext, [2]: encode+push
         self.progress[which] = value
+    def set_active(self, value):
+        self.active = value
 
 class CHKUploader:
     peer_selector_class = Tahoe2PeerSelector
@@ -603,6 +608,7 @@ class CHKUploader:
         self._storage_index = None
         self._upload_status = UploadStatus()
         self._upload_status.set_helper(False)
+        self._upload_status.set_active(True)
 
     def log(self, *args, **kwargs):
         if "parent" not in kwargs:
@@ -629,6 +635,10 @@ class CHKUploader:
             d1.addCallback(lambda key: self._compute_uri(res, key))
             return d1
         d.addCallback(_uploaded)
+        def _done(res):
+            self._upload_status.set_active(False)
+            return res
+        d.addBoth(_done)
         return d
 
     def abort(self):
@@ -758,6 +768,7 @@ class LiteralUploader:
         s.set_storage_index(None)
         s.set_helper(False)
         s.set_progress(0, 1.0)
+        s.set_active(False)
 
     def start(self, uploadable):
         uploadable = IUploadable(uploadable)
@@ -874,6 +885,7 @@ class AssistedUploader:
         self._storage_index = None
         self._upload_status = s = UploadStatus()
         s.set_helper(True)
+        s.set_active(True)
 
     def log(self, msg, parent=None, **kwargs):
         if parent is None:
@@ -900,6 +912,10 @@ class AssistedUploader:
         d.addCallback(self._got_storage_index)
         d.addCallback(self._contact_helper)
         d.addCallback(self._build_readcap)
+        def _done(res):
+            self._upload_status.set_active(False)
+            return res
+        d.addBoth(_done)
         return d
 
     def _got_size(self, size):
diff --git a/src/allmydata/web/status.xhtml b/src/allmydata/web/status.xhtml
index 5e421877..62edf5f5 100644
--- a/src/allmydata/web/status.xhtml
+++ b/src/allmydata/web/status.xhtml
@@ -8,11 +8,11 @@
   </head>
   <body>
 
-<h1>Current Uploads and Downloads</h1>
+<h1>Upload and Download Status</h1>
 
 
-<h2>Current Uploads:</h2>
-<table n:render="sequence" n:data="uploads" border="1">
+<h2>Active Uploads:</h2>
+<table n:render="sequence" n:data="active_uploads" border="1">
   <tr n:pattern="header">
     <td>Storage Index</td>
     <td>Helper?</td>
@@ -31,11 +31,11 @@
     <td><n:slot name="progress_encode"/></td>
     <td><n:slot name="status"/></td>
   </tr>
-  <tr n:pattern="empty"><td>No current uploads!</td></tr>
+  <tr n:pattern="empty"><td>No active uploads!</td></tr>
 </table>
 
-<h2>Current Downloads:</h2>
-<table n:render="sequence" n:data="downloads" border="1">
+<h2>Active Downloads:</h2>
+<table n:render="sequence" n:data="active_downloads" border="1">
   <tr n:pattern="header">
     <td>Storage Index</td>
     <td>Helper?</td>
@@ -50,7 +50,50 @@
     <td><n:slot name="progress"/></td>
     <td><n:slot name="status"/></td>
   </tr>
-  <tr n:pattern="empty"><td>No current downloads!</td></tr>
+  <tr n:pattern="empty"><td>No active downloads!</td></tr>
+</table>
+
+
+<h2>Recent Uploads:</h2>
+<table n:render="sequence" n:data="recent_uploads" border="1">
+  <tr n:pattern="header">
+    <td>Storage Index</td>
+    <td>Helper?</td>
+    <td>Total Size</td>
+    <td>Progress (Hash)</td>
+    <td>Progress (Ciphertext)</td>
+    <td>Progress (Encode+Push)</td>
+    <td>Status</td>
+  </tr>
+  <tr n:pattern="item" n:render="row_upload">
+    <td><n:slot name="si"/></td>
+    <td><n:slot name="helper"/></td>
+    <td><n:slot name="total_size"/></td>
+    <td><n:slot name="progress_hash"/></td>
+    <td><n:slot name="progress_ciphertext"/></td>
+    <td><n:slot name="progress_encode"/></td>
+    <td><n:slot name="status"/></td>
+  </tr>
+  <tr n:pattern="empty"><td>No recent uploads!</td></tr>
+</table>
+
+<h2>Recent Downloads:</h2>
+<table n:render="sequence" n:data="recent_downloads" border="1">
+  <tr n:pattern="header">
+    <td>Storage Index</td>
+    <td>Helper?</td>
+    <td>Total Size</td>
+    <td>Progress</td>
+    <td>Status</td>
+  </tr>
+  <tr n:pattern="item" n:render="row_download">
+    <td><n:slot name="si"/></td>
+    <td><n:slot name="helper"/></td>
+    <td><n:slot name="total_size"/></td>
+    <td><n:slot name="progress"/></td>
+    <td><n:slot name="status"/></td>
+  </tr>
+  <tr n:pattern="empty"><td>No recent downloads!</td></tr>
 </table>
 
 <div>Return to the <a href="/">Welcome Page</a></div>
diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py
index 06ec61c9..9ef58059 100644
--- a/src/allmydata/webish.py
+++ b/src/allmydata/webish.py
@@ -1567,11 +1567,14 @@ class UnlinkedPOSTCreateDirectory(rend.Page):
 class Status(rend.Page):
     docFactory = getxmlfile("status.xhtml")
 
-    def data_uploads(self, ctx, data):
-        return IClient(ctx).list_uploads()
-
-    def data_downloads(self, ctx, data):
-        return IClient(ctx).list_downloads()
+    def data_active_uploads(self, ctx, data):
+        return [u for u in IClient(ctx).list_uploads() if u.get_active()]
+    def data_active_downloads(self, ctx, data):
+        return [d for d in IClient(ctx).list_downloads() if d.get_active()]
+    def data_recent_uploads(self, ctx, data):
+        return [u for u in IClient(ctx).list_uploads() if not u.get_active()]
+    def data_recent_downloads(self, ctx, data):
+        return [d for d in IClient(ctx).list_downloads() if not d.get_active()]
 
     def _render_common(self, ctx, data):
         s = data
-- 
2.45.2