retain 10 most recent upload/download status objects, show them in /status . Prep for showing individual status objects

This commit is contained in:
Brian Warner 2008-02-29 22:19:03 -07:00
parent 33c7733e35
commit 1a7651ce82
8 changed files with 91 additions and 26 deletions

View File

@ -267,10 +267,18 @@ class Client(node.Node, testutil.PollMixin):
uploader = self.getServiceNamed("uploader")
return uploader.upload(uploadable)
def list_uploads(self):
def list_all_uploads(self):
uploader = self.getServiceNamed("uploader")
return uploader.list_uploads()
return uploader.list_all_uploads()
def list_downloads(self):
def list_all_downloads(self):
downloader = self.getServiceNamed("downloader")
return downloader.list_downloads()
return downloader.list_all_downloads()
def list_recent_uploads(self):
uploader = self.getServiceNamed("uploader")
return uploader.list_recent_uploads()
def list_recent_downloads(self):
downloader = self.getServiceNamed("downloader")
return downloader.list_recent_downloads()

View File

@ -1,5 +1,5 @@
import os, random, weakref
import os, random, weakref, itertools
from zope.interface import implements
from twisted.internet import defer
from twisted.internet.interfaces import IPushProducer, IConsumer
@ -327,6 +327,7 @@ class SegmentDownloader:
class DownloadStatus:
implements(IDownloadStatus)
statusid_counter = itertools.count(0)
def __init__(self):
self.storage_index = None
@ -337,6 +338,7 @@ class DownloadStatus:
self.paused = False
self.stopped = False
self.active = True
self.counter = self.statusid_counter.next()
def get_storage_index(self):
return self.storage_index
@ -355,6 +357,8 @@ class DownloadStatus:
return self.progress
def get_active(self):
return self.active
def get_counter(self):
return self.counter
def set_storage_index(self, si):
self.storage_index = si
@ -907,10 +911,12 @@ class Downloader(service.MultiService):
"""
implements(IDownloader)
name = "downloader"
MAX_DOWNLOAD_STATUSES = 10
def __init__(self):
service.MultiService.__init__(self)
self._all_downloads = weakref.WeakKeyDictionary()
self._recent_download_status = []
def download(self, u, t):
assert self.parent
@ -925,7 +931,10 @@ class Downloader(service.MultiService):
dl = FileDownloader(self.parent, u, t)
else:
raise RuntimeError("I don't know how to download a %s" % u)
self._all_downloads[dl.get_download_status()] = None
self._all_downloads[dl] = None
self._recent_download_status.append(dl.get_download_status())
while len(self._recent_download_status) > self.MAX_DOWNLOAD_STATUSES:
self._recent_download_status.pop(0)
d = dl.start()
return d
@ -938,5 +947,7 @@ class Downloader(service.MultiService):
return self.download(uri, FileHandle(filehandle))
def list_downloads(self):
def list_all_downloads(self):
return self._all_downloads.keys()
def list_recent_downloads(self):
return self._recent_download_status

View File

@ -1388,12 +1388,23 @@ class IClient(Interface):
"""
class IClientStatus(Interface):
def list_uploads():
"""Return a list of IUploadStatus objects, one for each
upload which is currently running."""
def list_downloads():
"""Return a list of IDownloadStatus objects, one for each
download which is currently running."""
def list_all_uploads():
"""Return a list of IUploadStatus objects, one for each upload which
currently has an object available. This uses weakrefs to track the
objects, so it may report uploads which have already finished. Use
get_active() to filter these out."""
def list_recent_uploads():
"""Return a list of IUploadStatus objects for the most recently
started uploads."""
def list_all_downloads():
"""Return a list of IDownloadStatus objects, one for each download
which currently has an object available. This uses weakrefs to track
the objects, so it may report downloadswhich have already finished.
Use get_active() to filter these out."""
def list_recent_downloads():
"""Return a list of IDownloadStatus objects for the most recently
started downloads."""
class IUploadStatus(Interface):
def get_storage_index():
@ -1422,6 +1433,10 @@ class IUploadStatus(Interface):
three numbers and report the sum to the user."""
def get_active():
"""Return True if the upload is currently active, False if not."""
def get_counter():
"""Each upload status gets a unique number: this method returns that
number. This provides a handle to this particular upload, so a web
page can generate a suitable hyperlink."""
class IDownloadStatus(Interface):
def get_storage_index():
@ -1443,6 +1458,10 @@ class IDownloadStatus(Interface):
first byte of plaintext is pushed to the download target."""
def get_active():
"""Return True if the download is currently active, False if not."""
def get_counter():
"""Each download status gets a unique number: this method returns
that number. This provides a handle to this particular download, so a
web page can generate a suitable hyperlink."""
class NotCapableError(Exception):

View File

@ -1171,7 +1171,7 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase):
file=("foo.txt", "data2" * 10000)))
# check that the status page exists
d.addCallback(lambda res: self.GET("status"))
d.addCallback(lambda res: self.GET("status", followRedirect=True))
# TODO: mangle the second segment of a file, to test errors that
# occur after we've already sent some good data, which uses a

View File

@ -67,9 +67,14 @@ class FakeClient(service.MultiService):
d.addCallback(_got_data)
return d
def list_uploads(self):
def list_all_uploads(self):
return [upload.UploadStatus()]
def list_downloads(self):
def list_all_downloads(self):
return [download.DownloadStatus()]
def list_recent_uploads(self):
return [upload.UploadStatus()]
def list_recent_downloads(self):
return [download.DownloadStatus()]
@ -375,7 +380,7 @@ class Web(WebMixin, unittest.TestCase):
return d
def test_status(self):
d = self.GET("/status")
d = self.GET("/status", followRedirect=True)
def _check(res):
self.failUnless('Upload and Download Status' in res)
d.addCallback(_check)

View File

@ -1,5 +1,5 @@
import os, time, weakref
import os, time, weakref, itertools
from zope.interface import implements
from twisted.python import failure
from twisted.internet import defer
@ -564,6 +564,7 @@ class EncryptAnUploadable:
class UploadStatus:
implements(IUploadStatus)
statusid_counter = itertools.count(0)
def __init__(self):
self.storage_index = None
@ -572,6 +573,7 @@ class UploadStatus:
self.status = "Not started"
self.progress = [0.0, 0.0, 0.0]
self.active = True
self.counter = self.statusid_counter.next()
def get_storage_index(self):
return self.storage_index
@ -585,6 +587,8 @@ class UploadStatus:
return tuple(self.progress)
def get_active(self):
return self.active
def get_counter(self):
return self.counter
def set_storage_index(self, si):
self.storage_index = si
@ -1139,11 +1143,13 @@ class Uploader(service.MultiService):
name = "uploader"
uploader_class = CHKUploader
URI_LIT_SIZE_THRESHOLD = 55
MAX_UPLOAD_STATUSES = 10
def __init__(self, helper_furl=None):
self._helper_furl = helper_furl
self._helper = None
self._all_uploads = weakref.WeakKeyDictionary()
self._recent_upload_status = []
service.MultiService.__init__(self)
def startService(self):
@ -1180,7 +1186,10 @@ class Uploader(service.MultiService):
uploader = AssistedUploader(self._helper)
else:
uploader = self.uploader_class(self.parent)
self._all_uploads[uploader.get_upload_status()] = None
self._all_uploads[uploader] = None
self._recent_upload_status.append(uploader.get_upload_status())
while len(self._recent_upload_status) > self.MAX_UPLOAD_STATUSES:
self._recent_upload_status.pop(0)
return uploader.start(uploadable)
d.addCallback(_got_size)
def _done(res):
@ -1189,5 +1198,7 @@ class Uploader(service.MultiService):
d.addBoth(_done)
return d
def list_uploads(self):
def list_all_uploads(self):
return self._all_uploads.keys()
def list_recent_uploads(self):
return self._recent_upload_status

View File

@ -12,7 +12,7 @@
<div>Please visit the <a href="http://allmydata.org">Tahoe home page</a> for
code updates and bug reporting. The <a href="provisioning">provisioning
tool</a> may also be useful. <a href="status">Current Uploads and
tool</a> may also be useful. <a href="status/">Current Uploads and
Downloads</a></div>
<h2>Grid Status</h2>

View File

@ -9,7 +9,7 @@ from nevow.static import File as nevow_File # TODO: merge with static.File?
from allmydata.util import base32, fileutil, idlib, observer, log
import simplejson
from allmydata.interfaces import IDownloadTarget, IDirectoryNode, IFileNode, \
IMutableFileNode
IMutableFileNode, IUploadStatus, IDownloadStatus
import allmydata # to display import path
from allmydata import download
from allmydata.upload import FileHandle, FileName
@ -1610,15 +1610,20 @@ class UnlinkedPOSTCreateDirectory(rend.Page):
class Status(rend.Page):
docFactory = getxmlfile("status.xhtml")
addSlash = True
def data_active_uploads(self, ctx, data):
return [u for u in IClient(ctx).list_uploads() if u.get_active()]
return [u for u in IClient(ctx).list_all_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()]
return [d for d in IClient(ctx).list_all_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()]
return [u for u in IClient(ctx).list_recent_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()]
return [d for d in IClient(ctx).list_recent_downloads()
if not d.get_active()]
def _render_common(self, ctx, data):
s = data
@ -1632,6 +1637,12 @@ class Status(rend.Page):
if size is None:
size = "(unknown)"
ctx.fillSlots("total_size", size)
if IUploadStatus.providedBy(data):
link = "up-%d" % data.get_counter()
else:
assert IDownloadStatus.providedBy(data)
link = "down-%d" % data.get_counter()
#ctx.fillSlots("status", T.a(href=link)[s.get_status()])
ctx.fillSlots("status", s.get_status())
def render_row_upload(self, ctx, data):