webish: make upload timings visible on the recent uploads/downloads status page

This commit is contained in:
Brian Warner 2008-03-03 14:48:52 -07:00
parent 436baa1b19
commit c8e24f0904
8 changed files with 153 additions and 65 deletions

View File

@ -267,6 +267,7 @@ class Client(node.Node, testutil.PollMixin):
uploader = self.getServiceNamed("uploader")
return uploader.upload(uploadable)
def list_all_uploads(self):
uploader = self.getServiceNamed("uploader")
return uploader.list_all_uploads()
@ -275,6 +276,16 @@ class Client(node.Node, testutil.PollMixin):
downloader = self.getServiceNamed("downloader")
return downloader.list_all_downloads()
def list_active_uploads(self):
uploader = self.getServiceNamed("uploader")
return uploader.list_active_uploads()
def list_active_downloads(self):
downloader = self.getServiceNamed("downloader")
return downloader.list_active_downloads()
def list_recent_uploads(self):
uploader = self.getServiceNamed("uploader")
return uploader.list_recent_uploads()

View File

@ -949,5 +949,8 @@ class Downloader(service.MultiService):
def list_all_downloads(self):
return self._all_downloads.keys()
def list_active_downloads(self):
return [d.get_download_status() for d in self._all_downloads.keys()
if d.get_download_status().get_active()]
def list_recent_downloads(self):
return self._recent_download_status

View File

@ -1389,19 +1389,21 @@ class IClient(Interface):
class IClientStatus(Interface):
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."""
"""Return a list of uploader objects, one for each upload which
currently has an object available (tracked with weakrefs). This is
intended for debugging purposes."""
def list_active_uploads():
"""Return a list of active IUploadStatus objects."""
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."""
"""Return a list of downloader objects, one for each download which
currently has an object available (tracked with weakrefs). This is
intended for debugging purposes."""
def list_active_downloads():
"""Return a list of active IDownloadStatus objects."""
def list_recent_downloads():
"""Return a list of IDownloadStatus objects for the most recently
started downloads."""
@ -1433,6 +1435,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_results():
"""Return an instance of UploadResults (which contains timing and
sharemap information). Might return None if the upload is not yet
finished."""
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

View File

@ -32,8 +32,8 @@ class FakeClient(service.MultiService):
}
introducer_furl = "None"
introducer_client = FakeIntroducerClient()
_all_uploads = [upload.UploadStatus()]
_all_downloads = [download.DownloadStatus()]
_all_upload_status = [upload.UploadStatus()]
_all_download_status = [download.DownloadStatus()]
def connected_to_introducer(self):
return False
@ -71,14 +71,18 @@ class FakeClient(service.MultiService):
return d
def list_all_uploads(self):
return self._all_uploads
return []
def list_all_downloads(self):
return self._all_downloads
return []
def list_active_uploads(self):
return self._all_upload_status
def list_active_downloads(self):
return self._all_download_status
def list_recent_uploads(self):
return self._all_uploads
return self._all_upload_status
def list_recent_downloads(self):
return self._all_downloads
return self._all_download_status
class WebMixin(object):
@ -1331,7 +1335,7 @@ class Web(WebMixin, unittest.TestCase):
"ctime": 1002777696.7564139,
"mtime": 1002777696.7564139
}
} ],
} ],
"atomic_added_2": [ "filenode", { "rw_uri": "%s",
"size": 1,
"metadata": {

View File

@ -573,6 +573,7 @@ class UploadStatus:
self.status = "Not started"
self.progress = [0.0, 0.0, 0.0]
self.active = True
self.results = None
self.counter = self.statusid_counter.next()
def get_storage_index(self):
@ -587,6 +588,8 @@ class UploadStatus:
return tuple(self.progress)
def get_active(self):
return self.active
def get_results(self):
return self.results
def get_counter(self):
return self.counter
@ -603,6 +606,8 @@ class UploadStatus:
self.progress[which] = value
def set_active(self, value):
self.active = value
def set_results(self, value):
self.results = value
class CHKUploader:
peer_selector_class = Tahoe2PeerSelector
@ -616,6 +621,7 @@ class CHKUploader:
self._upload_status = UploadStatus()
self._upload_status.set_helper(False)
self._upload_status.set_active(True)
self._upload_status.set_results(self._results)
def log(self, *args, **kwargs):
if "parent" not in kwargs:
@ -776,6 +782,7 @@ class LiteralUploader:
s.set_helper(False)
s.set_progress(0, 1.0)
s.set_active(False)
s.set_results(self._results)
def start(self, uploadable):
uploadable = IUploadable(uploadable)
@ -971,6 +978,7 @@ class AssistedUploader:
return d
self.log("helper says file is already uploaded")
self._upload_status.set_progress(1, 1.0)
self._upload_status.set_results(upload_results)
return upload_results
def _build_readcap(self, upload_results):
@ -996,6 +1004,7 @@ class AssistedUploader:
r.timings["helper_total"] = r.timings["total"]
r.timings["total"] = now - self._started
self._upload_status.set_status("Done")
self._upload_status.set_results(r)
return r
def get_upload_status(self):
@ -1200,5 +1209,8 @@ class Uploader(service.MultiService):
def list_all_uploads(self):
return self._all_uploads.keys()
def list_active_uploads(self):
return [u.get_upload_status() for u in self._all_uploads.keys()
if u.get_upload_status().get_active()]
def list_recent_uploads(self):
return self._recent_upload_status

View File

@ -20,6 +20,42 @@
<li>Status: <span n:render="status"/></li>
</ul>
<div n:render="results">
<h2>Upload Results</h2>
<ul>
<li>Sharemap: <span n:render="sharemap" /></li>
<li>Servermap: <span n:render="servermap" /></li>
<li>Timings:</li>
<ul>
<li>File Size: <span n:render="string" n:data="file_size" /> bytes</li>
<li>Total: <span n:render="time" n:data="time_total" />
(<span n:render="rate" n:data="rate_total" />)</li>
<ul>
<li>Storage Index: <span n:render="time" n:data="time_storage_index" />
(<span n:render="rate" n:data="rate_storage_index" />)</li>
<li>[Contacting Helper]: <span n:render="time" n:data="time_contacting_helper" /></li>
<ul>
<li>[Helper Already-In-Grid Check]: <span n:render="time" n:data="time_existence_check" /></li>
</ul>
<li>[Upload Ciphertext To Helper]: <span n:render="time" n:data="time_cumulative_fetch" />
(<span n:render="rate" n:data="rate_ciphertext_fetch" />)</li>
<li>Peer Selection: <span n:render="time" n:data="time_peer_selection" /></li>
<li>Encode And Push: <span n:render="time" n:data="time_total_encode_and_push" />
(<span n:render="rate" n:data="rate_encode_and_push" />)</li>
<ul>
<li>Cumulative Encoding: <span n:render="time" n:data="time_cumulative_encoding" />
(<span n:render="rate" n:data="rate_encode" />)</li>
<li>Cumulative Pushing: <span n:render="time" n:data="time_cumulative_sending" />
(<span n:render="rate" n:data="rate_push" />)</li>
<li>Send Hashes And Close: <span n:render="time" n:data="time_hashes_and_close" /></li>
</ul>
<li>[Helper Total]: <span n:render="time" n:data="time_helper_total" /></li>
</ul>
</ul>
</ul>
</div>
<div>Return to the <a href="/">Welcome Page</a></div>
</body>

View File

@ -1372,51 +1372,8 @@ class UnlinkedPUTCreateDirectory(rend.Page):
# XXX add redirect_to_result
return d
class UnlinkedPOSTCHKUploader(rend.Page):
"""'POST /uri', to create an unlinked file."""
docFactory = getxmlfile("unlinked-upload.xhtml")
def __init__(self, client, req):
rend.Page.__init__(self)
# we start the upload now, and distribute notification of its
# completion to render_ methods with an ObserverList
assert req.method == "POST"
self._done = observer.OneShotObserverList()
fileobj = req.fields["file"].file
uploadable = FileHandle(fileobj)
d = client.upload(uploadable)
d.addBoth(self._done.fire)
def renderHTTP(self, ctx):
req = inevow.IRequest(ctx)
when_done = get_arg(req, "when_done", None)
if when_done:
# if when_done= is provided, return a redirect instead of our
# usual upload-results page
d = self._done.when_fired()
d.addCallback(lambda res: url.URL.fromString(when_done))
return d
return rend.Page.renderHTTP(self, ctx)
def upload_results(self):
return self._done.when_fired()
def data_done(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: "done!")
return d
def data_uri(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: res.uri)
return d
def render_download_link(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: T.a(href="/uri/" + urllib.quote(res.uri))
["/uri/" + res.uri])
return d
class UploadResultsRendererMixin:
# this requires a method named 'upload_results'
def render_sharemap(self, ctx, data):
d = self.upload_results()
@ -1574,6 +1531,51 @@ class UnlinkedPOSTCHKUploader(rend.Page):
d.addCallback(_convert)
return d
class UnlinkedPOSTCHKUploader(UploadResultsRendererMixin, rend.Page):
"""'POST /uri', to create an unlinked file."""
docFactory = getxmlfile("upload-results.xhtml")
def __init__(self, client, req):
rend.Page.__init__(self)
# we start the upload now, and distribute notification of its
# completion to render_ methods with an ObserverList
assert req.method == "POST"
self._done = observer.OneShotObserverList()
fileobj = req.fields["file"].file
uploadable = FileHandle(fileobj)
d = client.upload(uploadable)
d.addBoth(self._done.fire)
def renderHTTP(self, ctx):
req = inevow.IRequest(ctx)
when_done = get_arg(req, "when_done", None)
if when_done:
# if when_done= is provided, return a redirect instead of our
# usual upload-results page
d = self._done.when_fired()
d.addCallback(lambda res: url.URL.fromString(when_done))
return d
return rend.Page.renderHTTP(self, ctx)
def upload_results(self):
return self._done.when_fired()
def data_done(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: "done!")
return d
def data_uri(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: res.uri)
return d
def render_download_link(self, ctx, data):
d = self.upload_results()
d.addCallback(lambda res: T.a(href="/uri/" + urllib.quote(res.uri))
["/uri/" + res.uri])
return d
class UnlinkedPOSTSSKUploader(rend.Page):
def renderHTTP(self, ctx):
req = inevow.IRequest(ctx)
@ -1608,9 +1610,25 @@ class UnlinkedPOSTCreateDirectory(rend.Page):
d.addCallback(lambda dirnode: dirnode.get_uri())
return d
class UploadStatusPage(rend.Page):
class UploadStatusPage(UploadResultsRendererMixin, rend.Page):
docFactory = getxmlfile("upload-status.xhtml")
def __init__(self, data):
rend.Page.__init__(self, data)
self.upload_status = data
def upload_results(self):
return defer.maybeDeferred(self.upload_status.get_results)
def render_results(self, ctx, data):
d = self.upload_results()
def _got_results(results):
if results:
return ctx.tag
return ""
d.addCallback(_got_results)
return d
def render_si(self, ctx, data):
si_s = base32.b2a_or_none(data.get_storage_index())
if si_s is None:
@ -1677,11 +1695,9 @@ class Status(rend.Page):
addSlash = True
def data_active_uploads(self, ctx, data):
return [u for u in IClient(ctx).list_all_uploads()
if u.get_active()]
return [u for u in IClient(ctx).list_active_uploads()]
def data_active_downloads(self, ctx, data):
return [d for d in IClient(ctx).list_all_downloads()
if d.get_active()]
return [d for d in IClient(ctx).list_active_downloads()]
def data_recent_uploads(self, ctx, data):
return [u for u in IClient(ctx).list_recent_uploads()
if not u.get_active()]