mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-06-11 12:01:44 +00:00
webish: make upload timings visible on the recent uploads/downloads status page
This commit is contained in:
parent
436baa1b19
commit
c8e24f0904
@ -267,6 +267,7 @@ class Client(node.Node, testutil.PollMixin):
|
|||||||
uploader = self.getServiceNamed("uploader")
|
uploader = self.getServiceNamed("uploader")
|
||||||
return uploader.upload(uploadable)
|
return uploader.upload(uploadable)
|
||||||
|
|
||||||
|
|
||||||
def list_all_uploads(self):
|
def list_all_uploads(self):
|
||||||
uploader = self.getServiceNamed("uploader")
|
uploader = self.getServiceNamed("uploader")
|
||||||
return uploader.list_all_uploads()
|
return uploader.list_all_uploads()
|
||||||
@ -275,6 +276,16 @@ class Client(node.Node, testutil.PollMixin):
|
|||||||
downloader = self.getServiceNamed("downloader")
|
downloader = self.getServiceNamed("downloader")
|
||||||
return downloader.list_all_downloads()
|
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):
|
def list_recent_uploads(self):
|
||||||
uploader = self.getServiceNamed("uploader")
|
uploader = self.getServiceNamed("uploader")
|
||||||
return uploader.list_recent_uploads()
|
return uploader.list_recent_uploads()
|
||||||
|
@ -949,5 +949,8 @@ class Downloader(service.MultiService):
|
|||||||
|
|
||||||
def list_all_downloads(self):
|
def list_all_downloads(self):
|
||||||
return self._all_downloads.keys()
|
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):
|
def list_recent_downloads(self):
|
||||||
return self._recent_download_status
|
return self._recent_download_status
|
||||||
|
@ -1389,19 +1389,21 @@ class IClient(Interface):
|
|||||||
|
|
||||||
class IClientStatus(Interface):
|
class IClientStatus(Interface):
|
||||||
def list_all_uploads():
|
def list_all_uploads():
|
||||||
"""Return a list of IUploadStatus objects, one for each upload which
|
"""Return a list of uploader objects, one for each upload which
|
||||||
currently has an object available. This uses weakrefs to track the
|
currently has an object available (tracked with weakrefs). This is
|
||||||
objects, so it may report uploads which have already finished. Use
|
intended for debugging purposes."""
|
||||||
get_active() to filter these out."""
|
def list_active_uploads():
|
||||||
|
"""Return a list of active IUploadStatus objects."""
|
||||||
def list_recent_uploads():
|
def list_recent_uploads():
|
||||||
"""Return a list of IUploadStatus objects for the most recently
|
"""Return a list of IUploadStatus objects for the most recently
|
||||||
started uploads."""
|
started uploads."""
|
||||||
|
|
||||||
def list_all_downloads():
|
def list_all_downloads():
|
||||||
"""Return a list of IDownloadStatus objects, one for each download
|
"""Return a list of downloader objects, one for each download which
|
||||||
which currently has an object available. This uses weakrefs to track
|
currently has an object available (tracked with weakrefs). This is
|
||||||
the objects, so it may report downloadswhich have already finished.
|
intended for debugging purposes."""
|
||||||
Use get_active() to filter these out."""
|
def list_active_downloads():
|
||||||
|
"""Return a list of active IDownloadStatus objects."""
|
||||||
def list_recent_downloads():
|
def list_recent_downloads():
|
||||||
"""Return a list of IDownloadStatus objects for the most recently
|
"""Return a list of IDownloadStatus objects for the most recently
|
||||||
started downloads."""
|
started downloads."""
|
||||||
@ -1433,6 +1435,10 @@ class IUploadStatus(Interface):
|
|||||||
three numbers and report the sum to the user."""
|
three numbers and report the sum to the user."""
|
||||||
def get_active():
|
def get_active():
|
||||||
"""Return True if the upload is currently active, False if not."""
|
"""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():
|
def get_counter():
|
||||||
"""Each upload status gets a unique number: this method returns that
|
"""Each upload status gets a unique number: this method returns that
|
||||||
number. This provides a handle to this particular upload, so a web
|
number. This provides a handle to this particular upload, so a web
|
||||||
|
@ -32,8 +32,8 @@ class FakeClient(service.MultiService):
|
|||||||
}
|
}
|
||||||
introducer_furl = "None"
|
introducer_furl = "None"
|
||||||
introducer_client = FakeIntroducerClient()
|
introducer_client = FakeIntroducerClient()
|
||||||
_all_uploads = [upload.UploadStatus()]
|
_all_upload_status = [upload.UploadStatus()]
|
||||||
_all_downloads = [download.DownloadStatus()]
|
_all_download_status = [download.DownloadStatus()]
|
||||||
|
|
||||||
def connected_to_introducer(self):
|
def connected_to_introducer(self):
|
||||||
return False
|
return False
|
||||||
@ -71,14 +71,18 @@ class FakeClient(service.MultiService):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def list_all_uploads(self):
|
def list_all_uploads(self):
|
||||||
return self._all_uploads
|
return []
|
||||||
def list_all_downloads(self):
|
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):
|
def list_recent_uploads(self):
|
||||||
return self._all_uploads
|
return self._all_upload_status
|
||||||
def list_recent_downloads(self):
|
def list_recent_downloads(self):
|
||||||
return self._all_downloads
|
return self._all_download_status
|
||||||
|
|
||||||
|
|
||||||
class WebMixin(object):
|
class WebMixin(object):
|
||||||
|
@ -573,6 +573,7 @@ class UploadStatus:
|
|||||||
self.status = "Not started"
|
self.status = "Not started"
|
||||||
self.progress = [0.0, 0.0, 0.0]
|
self.progress = [0.0, 0.0, 0.0]
|
||||||
self.active = True
|
self.active = True
|
||||||
|
self.results = None
|
||||||
self.counter = self.statusid_counter.next()
|
self.counter = self.statusid_counter.next()
|
||||||
|
|
||||||
def get_storage_index(self):
|
def get_storage_index(self):
|
||||||
@ -587,6 +588,8 @@ class UploadStatus:
|
|||||||
return tuple(self.progress)
|
return tuple(self.progress)
|
||||||
def get_active(self):
|
def get_active(self):
|
||||||
return self.active
|
return self.active
|
||||||
|
def get_results(self):
|
||||||
|
return self.results
|
||||||
def get_counter(self):
|
def get_counter(self):
|
||||||
return self.counter
|
return self.counter
|
||||||
|
|
||||||
@ -603,6 +606,8 @@ class UploadStatus:
|
|||||||
self.progress[which] = value
|
self.progress[which] = value
|
||||||
def set_active(self, value):
|
def set_active(self, value):
|
||||||
self.active = value
|
self.active = value
|
||||||
|
def set_results(self, value):
|
||||||
|
self.results = value
|
||||||
|
|
||||||
class CHKUploader:
|
class CHKUploader:
|
||||||
peer_selector_class = Tahoe2PeerSelector
|
peer_selector_class = Tahoe2PeerSelector
|
||||||
@ -616,6 +621,7 @@ class CHKUploader:
|
|||||||
self._upload_status = UploadStatus()
|
self._upload_status = UploadStatus()
|
||||||
self._upload_status.set_helper(False)
|
self._upload_status.set_helper(False)
|
||||||
self._upload_status.set_active(True)
|
self._upload_status.set_active(True)
|
||||||
|
self._upload_status.set_results(self._results)
|
||||||
|
|
||||||
def log(self, *args, **kwargs):
|
def log(self, *args, **kwargs):
|
||||||
if "parent" not in kwargs:
|
if "parent" not in kwargs:
|
||||||
@ -776,6 +782,7 @@ class LiteralUploader:
|
|||||||
s.set_helper(False)
|
s.set_helper(False)
|
||||||
s.set_progress(0, 1.0)
|
s.set_progress(0, 1.0)
|
||||||
s.set_active(False)
|
s.set_active(False)
|
||||||
|
s.set_results(self._results)
|
||||||
|
|
||||||
def start(self, uploadable):
|
def start(self, uploadable):
|
||||||
uploadable = IUploadable(uploadable)
|
uploadable = IUploadable(uploadable)
|
||||||
@ -971,6 +978,7 @@ class AssistedUploader:
|
|||||||
return d
|
return d
|
||||||
self.log("helper says file is already uploaded")
|
self.log("helper says file is already uploaded")
|
||||||
self._upload_status.set_progress(1, 1.0)
|
self._upload_status.set_progress(1, 1.0)
|
||||||
|
self._upload_status.set_results(upload_results)
|
||||||
return upload_results
|
return upload_results
|
||||||
|
|
||||||
def _build_readcap(self, upload_results):
|
def _build_readcap(self, upload_results):
|
||||||
@ -996,6 +1004,7 @@ class AssistedUploader:
|
|||||||
r.timings["helper_total"] = r.timings["total"]
|
r.timings["helper_total"] = r.timings["total"]
|
||||||
r.timings["total"] = now - self._started
|
r.timings["total"] = now - self._started
|
||||||
self._upload_status.set_status("Done")
|
self._upload_status.set_status("Done")
|
||||||
|
self._upload_status.set_results(r)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def get_upload_status(self):
|
def get_upload_status(self):
|
||||||
@ -1200,5 +1209,8 @@ class Uploader(service.MultiService):
|
|||||||
|
|
||||||
def list_all_uploads(self):
|
def list_all_uploads(self):
|
||||||
return self._all_uploads.keys()
|
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):
|
def list_recent_uploads(self):
|
||||||
return self._recent_upload_status
|
return self._recent_upload_status
|
||||||
|
@ -20,6 +20,42 @@
|
|||||||
<li>Status: <span n:render="status"/></li>
|
<li>Status: <span n:render="status"/></li>
|
||||||
</ul>
|
</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>
|
<div>Return to the <a href="/">Welcome Page</a></div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -1372,51 +1372,8 @@ class UnlinkedPUTCreateDirectory(rend.Page):
|
|||||||
# XXX add redirect_to_result
|
# XXX add redirect_to_result
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
class UploadResultsRendererMixin:
|
||||||
class UnlinkedPOSTCHKUploader(rend.Page):
|
# this requires a method named 'upload_results'
|
||||||
"""'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
|
|
||||||
|
|
||||||
def render_sharemap(self, ctx, data):
|
def render_sharemap(self, ctx, data):
|
||||||
d = self.upload_results()
|
d = self.upload_results()
|
||||||
@ -1574,6 +1531,51 @@ class UnlinkedPOSTCHKUploader(rend.Page):
|
|||||||
d.addCallback(_convert)
|
d.addCallback(_convert)
|
||||||
return d
|
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):
|
class UnlinkedPOSTSSKUploader(rend.Page):
|
||||||
def renderHTTP(self, ctx):
|
def renderHTTP(self, ctx):
|
||||||
req = inevow.IRequest(ctx)
|
req = inevow.IRequest(ctx)
|
||||||
@ -1608,9 +1610,25 @@ class UnlinkedPOSTCreateDirectory(rend.Page):
|
|||||||
d.addCallback(lambda dirnode: dirnode.get_uri())
|
d.addCallback(lambda dirnode: dirnode.get_uri())
|
||||||
return d
|
return d
|
||||||
|
|
||||||
class UploadStatusPage(rend.Page):
|
class UploadStatusPage(UploadResultsRendererMixin, rend.Page):
|
||||||
docFactory = getxmlfile("upload-status.xhtml")
|
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):
|
def render_si(self, ctx, data):
|
||||||
si_s = base32.b2a_or_none(data.get_storage_index())
|
si_s = base32.b2a_or_none(data.get_storage_index())
|
||||||
if si_s is None:
|
if si_s is None:
|
||||||
@ -1677,11 +1695,9 @@ class Status(rend.Page):
|
|||||||
addSlash = True
|
addSlash = True
|
||||||
|
|
||||||
def data_active_uploads(self, ctx, data):
|
def data_active_uploads(self, ctx, data):
|
||||||
return [u for u in IClient(ctx).list_all_uploads()
|
return [u for u in IClient(ctx).list_active_uploads()]
|
||||||
if u.get_active()]
|
|
||||||
def data_active_downloads(self, ctx, data):
|
def data_active_downloads(self, ctx, data):
|
||||||
return [d for d in IClient(ctx).list_all_downloads()
|
return [d for d in IClient(ctx).list_active_downloads()]
|
||||||
if d.get_active()]
|
|
||||||
def data_recent_uploads(self, ctx, data):
|
def data_recent_uploads(self, ctx, data):
|
||||||
return [u for u in IClient(ctx).list_recent_uploads()
|
return [u for u in IClient(ctx).list_recent_uploads()
|
||||||
if not u.get_active()]
|
if not u.get_active()]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user