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()
-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
class DownloadStatus:
implements(IDownloadStatus)
+ statusid_counter = itertools.count(0)
def __init__(self):
self.storage_index = None
self.paused = False
self.stopped = False
self.active = True
+ self.counter = self.statusid_counter.next()
def get_storage_index(self):
return self.storage_index
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
"""
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
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
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
"""
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():
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():
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):
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
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()]
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)
-import os, time, weakref
+import os, time, weakref, itertools
from zope.interface import implements
from twisted.python import failure
from twisted.internet import defer
class UploadStatus:
implements(IUploadStatus)
+ statusid_counter = itertools.count(0)
def __init__(self):
self.storage_index = None
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
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
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):
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):
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
<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>
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
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
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):