From c8e24f09048abeb136fcc6cb9c6f65069b0970df Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 3 Mar 2008 14:48:52 -0700 Subject: [PATCH] webish: make upload timings visible on the recent uploads/downloads status page --- src/allmydata/client.py | 11 ++ src/allmydata/download.py | 3 + src/allmydata/interfaces.py | 22 ++-- src/allmydata/test/test_web.py | 18 +-- src/allmydata/upload.py | 12 ++ ...nked-upload.xhtml => upload-results.xhtml} | 0 src/allmydata/web/upload-status.xhtml | 36 ++++++ src/allmydata/webish.py | 116 ++++++++++-------- 8 files changed, 153 insertions(+), 65 deletions(-) rename src/allmydata/web/{unlinked-upload.xhtml => upload-results.xhtml} (100%) diff --git a/src/allmydata/client.py b/src/allmydata/client.py index c8c1b183..c20d422b 100644 --- a/src/allmydata/client.py +++ b/src/allmydata/client.py @@ -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() diff --git a/src/allmydata/download.py b/src/allmydata/download.py index 83bebb37..907f9387 100644 --- a/src/allmydata/download.py +++ b/src/allmydata/download.py @@ -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 diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py index 35bf0a34..2d7f71ed 100644 --- a/src/allmydata/interfaces.py +++ b/src/allmydata/interfaces.py @@ -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 diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 7f686d2b..9678ae52 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -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": { diff --git a/src/allmydata/upload.py b/src/allmydata/upload.py index 04cc9317..c3dd29df 100644 --- a/src/allmydata/upload.py +++ b/src/allmydata/upload.py @@ -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 diff --git a/src/allmydata/web/unlinked-upload.xhtml b/src/allmydata/web/upload-results.xhtml similarity index 100% rename from src/allmydata/web/unlinked-upload.xhtml rename to src/allmydata/web/upload-results.xhtml diff --git a/src/allmydata/web/upload-status.xhtml b/src/allmydata/web/upload-status.xhtml index 10a6e08a..1d8c7e0f 100644 --- a/src/allmydata/web/upload-status.xhtml +++ b/src/allmydata/web/upload-status.xhtml @@ -20,6 +20,42 @@
  • Status:
  • +
    +

    Upload Results

    + +
    +
    Return to the Welcome Page
    diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py index 31192991..427e7ef7 100644 --- a/src/allmydata/webish.py +++ b/src/allmydata/webish.py @@ -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()] -- 2.37.2