Merge pull request #721 from sajith/3287.status-upload-nevow-to-twisted-web

Replace nevow with twisted.web.template in status.UploadStatusPage

Fixes: ticket:3287
This commit is contained in:
Sajith Sasidharan 2020-07-06 16:20:40 -04:00 committed by GitHub
commit 25f5e659fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 241 additions and 160 deletions

0
newsfragments/3287.minor Normal file
View File

View File

@ -23,6 +23,16 @@ class Util(ShouldFailMixin, testutil.ReallyEqualMixin, unittest.TestCase):
self.failUnlessReallyEqual(common.abbreviate_time(0.000123), "123us")
self.failUnlessReallyEqual(common.abbreviate_time(-123000), "-123000000000us")
self.failUnlessReallyEqual(common.abbreviate_time(None), "")
self.failUnlessReallyEqual(common.abbreviate_time(2.5), "2.50s")
self.failUnlessReallyEqual(common.abbreviate_time(0.25), "250ms")
self.failUnlessReallyEqual(common.abbreviate_time(0.0021), "2.1ms")
self.failUnlessReallyEqual(common.abbreviate_time(0.000123), "123us")
self.failUnlessReallyEqual(common.abbreviate_rate(None), "")
self.failUnlessReallyEqual(common.abbreviate_rate(2500000), "2.50MBps")
self.failUnlessReallyEqual(common.abbreviate_rate(30100), "30.1kBps")
self.failUnlessReallyEqual(common.abbreviate_rate(123), "123Bps")
def test_compute_rate(self):
self.failUnlessReallyEqual(common.compute_rate(None, None), None)
self.failUnlessReallyEqual(common.compute_rate(None, 1), None)

View File

@ -1047,17 +1047,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.failUnlessReallyEqual(drrm.render_rate(None, 30100), "30.1kBps")
self.failUnlessReallyEqual(drrm.render_rate(None, 123), "123Bps")
urrm = status.UploadResultsRendererMixin()
self.failUnlessReallyEqual(urrm.render_time(None, None), "")
self.failUnlessReallyEqual(urrm.render_time(None, 2.5), "2.50s")
self.failUnlessReallyEqual(urrm.render_time(None, 0.25), "250ms")
self.failUnlessReallyEqual(urrm.render_time(None, 0.0021), "2.1ms")
self.failUnlessReallyEqual(urrm.render_time(None, 0.000123), "123us")
self.failUnlessReallyEqual(urrm.render_rate(None, None), "")
self.failUnlessReallyEqual(urrm.render_rate(None, 2500000), "2.50MBps")
self.failUnlessReallyEqual(urrm.render_rate(None, 30100), "30.1kBps")
self.failUnlessReallyEqual(urrm.render_rate(None, 123), "123Bps")
def test_GET_FILEURL(self):
d = self.GET(self.public_url + "/foo/bar.txt")
d.addCallback(self.failUnlessIsBarDotTxt)

View File

@ -35,187 +35,236 @@ class RateAndTimeMixin(object):
def render_rate(self, ctx, data):
return abbreviate_rate(data)
class UploadResultsRendererMixin(RateAndTimeMixin):
class UploadResultsRendererMixin(Element):
# this requires a method named 'upload_results'
def render_pushed_shares(self, ctx, data):
@renderer
def pushed_shares(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_pushed_shares())
d.addCallback(lambda res: str(res.get_pushed_shares()))
return d
def render_preexisting_shares(self, ctx, data):
@renderer
def preexisting_shares(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_preexisting_shares())
d.addCallback(lambda res: str(res.get_preexisting_shares()))
return d
def render_sharemap(self, ctx, data):
@renderer
def sharemap(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_sharemap())
def _render(sharemap):
if sharemap is None:
return "None"
l = T.ul()
ul = tags.ul()
for shnum, servers in sorted(sharemap.items()):
server_names = ', '.join([s.get_name() for s in servers])
l[T.li["%d -> placed on [%s]" % (shnum, server_names)]]
return l
ul(tags.li("%d -> placed on [%s]" % (shnum, server_names)))
return ul
d.addCallback(_render)
return d
def render_servermap(self, ctx, data):
@renderer
def servermap(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_servermap())
def _render(servermap):
if servermap is None:
return "None"
l = T.ul()
ul = tags.ul()
for server, shnums in sorted(servermap.items()):
shares_s = ",".join(["#%d" % shnum for shnum in shnums])
l[T.li["[%s] got share%s: %s" % (server.get_name(),
plural(shnums), shares_s)]]
return l
ul(tags.li("[%s] got share%s: %s" % (server.get_name(),
plural(shnums), shares_s)))
return ul
d.addCallback(_render)
return d
def data_file_size(self, ctx, data):
@renderer
def file_size(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_file_size())
d.addCallback(lambda res: str(res.get_file_size()))
return d
def _get_time(self, name):
d = self.upload_results()
d.addCallback(lambda res: res.get_timings().get(name))
d.addCallback(lambda res: abbreviate_time(res.get_timings().get(name)))
return d
def data_time_total(self, ctx, data):
return self._get_time("total")
@renderer
def time_total(self, req, tag):
return tag(self._get_time("total"))
def data_time_storage_index(self, ctx, data):
return self._get_time("storage_index")
@renderer
def time_storage_index(self, req, tag):
return tag(self._get_time("storage_index"))
def data_time_contacting_helper(self, ctx, data):
return self._get_time("contacting_helper")
@renderer
def time_contacting_helper(self, req, tag):
return tag(self._get_time("contacting_helper"))
def data_time_cumulative_fetch(self, ctx, data):
return self._get_time("cumulative_fetch")
@renderer
def time_cumulative_fetch(self, req, tag):
return tag(self._get_time("cumulative_fetch"))
def data_time_helper_total(self, ctx, data):
return self._get_time("helper_total")
@renderer
def time_helper_total(self, req, tag):
return tag(self._get_time("helper_total"))
def data_time_peer_selection(self, ctx, data):
return self._get_time("peer_selection")
@renderer
def time_peer_selection(self, req, tag):
return tag(self._get_time("peer_selection"))
def data_time_total_encode_and_push(self, ctx, data):
return self._get_time("total_encode_and_push")
@renderer
def time_total_encode_and_push(self, req, tag):
return tag(self._get_time("total_encode_and_push"))
def data_time_cumulative_encoding(self, ctx, data):
return self._get_time("cumulative_encoding")
@renderer
def time_cumulative_encoding(self, req, tag):
return tag(self._get_time("cumulative_encoding"))
def data_time_cumulative_sending(self, ctx, data):
return self._get_time("cumulative_sending")
@renderer
def time_cumulative_sending(self, req, tag):
return tag(self._get_time("cumulative_sending"))
def data_time_hashes_and_close(self, ctx, data):
return self._get_time("hashes_and_close")
@renderer
def time_hashes_and_close(self, req, tag):
return tag(self._get_time("hashes_and_close"))
def _get_rate(self, name):
d = self.upload_results()
def _convert(r):
file_size = r.get_file_size()
duration = r.get_timings().get(name)
return compute_rate(file_size, duration)
return abbreviate_rate(compute_rate(file_size, duration))
d.addCallback(_convert)
return d
def data_rate_total(self, ctx, data):
return self._get_rate("total")
@renderer
def rate_total(self, req, tag):
return tag(self._get_rate("total"))
def data_rate_storage_index(self, ctx, data):
return self._get_rate("storage_index")
@renderer
def rate_storage_index(self, req, tag):
return tag(self._get_rate("storage_index"))
def data_rate_encode(self, ctx, data):
return self._get_rate("cumulative_encoding")
@renderer
def rate_encode(self, req, tag):
return tag(self._get_rate("cumulative_encoding"))
def data_rate_push(self, ctx, data):
@renderer
def rate_push(self, req, tag):
return self._get_rate("cumulative_sending")
def data_rate_encode_and_push(self, ctx, data):
@renderer
def rate_encode_and_push(self, req, tag):
d = self.upload_results()
def _convert(r):
file_size = r.get_file_size()
time1 = r.get_timings().get("cumulative_encoding")
time2 = r.get_timings().get("cumulative_sending")
if (time1 is None or time2 is None):
return None
return abbreviate_rate(None)
else:
return compute_rate(file_size, time1+time2)
return abbreviate_rate(compute_rate(file_size, time1+time2))
d.addCallback(_convert)
return d
def data_rate_ciphertext_fetch(self, ctx, data):
@renderer
def rate_ciphertext_fetch(self, req, tag):
d = self.upload_results()
def _convert(r):
fetch_size = r.get_ciphertext_fetched()
duration = r.get_timings().get("cumulative_fetch")
return compute_rate(fetch_size, duration)
return abbreviate_rate(compute_rate(fetch_size, duration))
d.addCallback(_convert)
return d
class UploadStatusPage(UploadResultsRendererMixin, rend.Page):
docFactory = getxmlfile("upload-status.xhtml")
def __init__(self, data):
rend.Page.__init__(self, data)
self.upload_status = data
class UploadStatusPage(Resource, object):
"""Renders /status/up-%d."""
def __init__(self, upload_status):
"""
:param IUploadStatus upload_status: stats provider.
"""
super(UploadStatusPage, self).__init__()
self._upload_status = upload_status
def render_GET(self, req):
elem = UploadStatusElement(self._upload_status)
return renderElement(req, elem)
class UploadStatusElement(UploadResultsRendererMixin):
loader = XMLFile(FilePath(__file__).sibling("upload-status.xhtml"))
def __init__(self, upload_status):
super(UploadStatusElement, self).__init__()
self._upload_status = upload_status
def upload_results(self):
return defer.maybeDeferred(self.upload_status.get_results)
return defer.maybeDeferred(self._upload_status.get_results)
def render_results(self, ctx, data):
@renderer
def results(self, req, tag):
d = self.upload_results()
def _got_results(results):
if results:
return ctx.tag
return tag
return ""
d.addCallback(_got_results)
return d
def render_started(self, ctx, data):
started_s = render_time(data.get_started())
return started_s
@renderer
def started(self, req, tag):
started_s = render_time(self._upload_status.get_started())
return tag(started_s)
def render_si(self, ctx, data):
si_s = base32.b2a_or_none(data.get_storage_index())
@renderer
def si(self, req, tag):
si_s = base32.b2a_or_none(self._upload_status.get_storage_index())
if si_s is None:
si_s = "(None)"
return si_s
return tag(str(si_s))
def render_helper(self, ctx, data):
return {True: "Yes",
False: "No"}[data.using_helper()]
@renderer
def helper(self, req, tag):
return tag({True: "Yes",
False: "No"}[self._upload_status.using_helper()])
def render_total_size(self, ctx, data):
size = data.get_size()
@renderer
def total_size(self, req, tag):
size = self._upload_status.get_size()
if size is None:
return "(unknown)"
return size
return tag(str(size))
def render_progress_hash(self, ctx, data):
progress = data.get_progress()[0]
@renderer
def progress_hash(self, req, tag):
progress = self._upload_status.get_progress()[0]
# TODO: make an ascii-art bar
return tag("%.1f%%" % (100.0 * progress))
@renderer
def progress_ciphertext(self, req, tag):
progress = self._upload_status.get_progress()[1]
# TODO: make an ascii-art bar
return "%.1f%%" % (100.0 * progress)
def render_progress_ciphertext(self, ctx, data):
progress = data.get_progress()[1]
@renderer
def progress_encode_push(self, req, tag):
progress = self._upload_status.get_progress()[2]
# TODO: make an ascii-art bar
return "%.1f%%" % (100.0 * progress)
return tag("%.1f%%" % (100.0 * progress))
def render_progress_encode_push(self, ctx, data):
progress = data.get_progress()[2]
# TODO: make an ascii-art bar
return "%.1f%%" % (100.0 * progress)
@renderer
def status(self, req, tag):
return tag(self._upload_status.get_status())
def render_status(self, ctx, data):
return data.get_status()
class DownloadResultsRendererMixin(RateAndTimeMixin):
# this requires a method named 'download_results'
@ -334,7 +383,7 @@ class DownloadResultsRendererMixin(RateAndTimeMixin):
l = T.ul()
for peerid in sorted(per_server.keys()):
peerid_s = idlib.shortnodeid_b2a(peerid)
times_s = ", ".join([self.render_time(None, t)
times_s = ", ".join([abbreviate_time(t)
for t in per_server[peerid]])
l[T.li["[%s]: %s" % (peerid_s, times_s)]]
return T.li["Per-Server Segment Fetch Response Times: ", l]

View File

@ -2,11 +2,25 @@
import urllib
from twisted.web import http
from twisted.internet import defer
from nevow import rend, url, tags as T
from twisted.python.filepath import FilePath
from twisted.web.resource import Resource
from twisted.web.template import (
XMLFile,
renderer,
renderElement,
tags,
)
from nevow import url
from allmydata.immutable.upload import FileHandle
from allmydata.mutable.publish import MutableFileHandle
from allmydata.web.common import getxmlfile, get_arg, boolean_of_arg, \
convert_children_json, WebError, get_format, get_mutable_type
from allmydata.web.common import (
get_arg,
boolean_of_arg,
convert_children_json,
WebError,
get_format,
get_mutable_type,
)
from allmydata.web import status
def PUTUnlinkedCHK(req, client):
@ -59,34 +73,53 @@ def POSTUnlinkedCHK(req, client):
return d
class UploadResultsPage(status.UploadResultsRendererMixin, rend.Page):
class UploadResultsPage(Resource, object):
"""'POST /uri', to create an unlinked file."""
docFactory = getxmlfile("upload-results.xhtml")
def __init__(self, upload_results):
rend.Page.__init__(self)
self.results = upload_results
"""
:param IUploadResults upload_results: stats provider.
"""
super(UploadResultsPage, self).__init__()
self._upload_results = upload_results
def render_POST(self, req):
elem = UploadResultsElement(self._upload_results)
return renderElement(req, elem)
class UploadResultsElement(status.UploadResultsRendererMixin):
loader = XMLFile(FilePath(__file__).sibling("upload-results.xhtml"))
def __init__(self, upload_results):
super(UploadResultsElement, self).__init__()
self._upload_results = upload_results
def upload_results(self):
return defer.succeed(self.results)
return defer.succeed(self._upload_results)
def data_done(self, ctx, data):
@renderer
def done(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: "done!")
return d
def data_uri(self, ctx, data):
@renderer
def uri(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res: res.get_uri())
return d
def render_download_link(self, ctx, data):
@renderer
def download_link(self, req, tag):
d = self.upload_results()
d.addCallback(lambda res:
T.a(href="/uri/" + urllib.quote(res.get_uri()))
["/uri/" + res.get_uri()])
tags.a("/uri/" + res.get_uri(),
href="/uri/" + urllib.quote(res.get_uri())))
return d
def POSTUnlinkedSSK(req, client, version):
# "POST /uri", to create an unlinked file.
# SDMF: files are small, and we can only upload data

View File

@ -1,4 +1,4 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
<html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
<head>
<title>Tahoe-LAFS - File Uploaded</title>
<link href="/tahoe.css" rel="stylesheet" type="text/css"/>
@ -7,37 +7,37 @@
</head>
<body>
<h1>Uploading File... <span n:render="string" n:data="done" /></h1>
<h1>Uploading File... <t:transparent t:render="done" /></h1>
<h2>Upload Results:</h2>
<ul>
<li>URI: <tt><span n:render="string" n:data="uri" /></tt></li>
<li>Download link: <span n:render="download_link" /></li>
<li>Sharemap: <span n:render="sharemap" /></li>
<li>Servermap: <span n:render="servermap" /></li>
<li>URI: <tt><span><t:transparent t:render="uri" /></span></tt></li>
<li>Download link: <t:transparent t:render="download_link" /></li>
<li>Sharemap: <t:transparent t:render="sharemap" /></li>
<li>Servermap: <t:transparent t: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>
<li>File Size: <t:transparent t:render="file_size" /> bytes</li>
<li>Total: <t:transparent t:render="time_total" />
(<t:transparent t:render="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>
<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>Storage Index: <t:transparent t:render="time_storage_index" />
(<t:transparent t:render="rate_storage_index" />)</li>
<li>[Contacting Helper]: <t:transparent t:render="time_contacting_helper" /></li>
<li>[Upload Ciphertext To Helper]: <t:transparent t:render="time_cumulative_fetch" />
(<t:transparent t:render="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>
<li>Peer Selection: <t:transparent t:render="time_peer_selection" /></li>
<li>Encode And Push: <t:transparent t:render="time_total_encode_and_push" />
(<t:transparent t:render="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>
<li>Cumulative Encoding: <t:transparent t:render="time_cumulative_encoding" />
(<t:transparent t:render="rate_encode" />)</li>
<li>Cumulative Pushing: <t:transparent t:render="time_cumulative_sending" />
(<t:transparent t:render="rate_push" />)</li>
<li>Send Hashes And Close: <t:transparent t:render="time_hashes_and_close" /></li>
</ul>
<li>[Helper Total]: <span n:render="time" n:data="time_helper_total" /></li>
<li>[Helper Total]: <t:transparent t:render="time_helper_total" /></li>
</ul>
</ul>
</ul>

View File

@ -1,4 +1,4 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
<html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
<head>
<title>Tahoe-LAFS - File Upload Status</title>
<link href="/tahoe.css" rel="stylesheet" type="text/css"/>
@ -10,46 +10,46 @@
<h1>File Upload Status</h1>
<ul>
<li>Started: <span n:render="started"/></li>
<li>Storage Index: <span n:render="si"/></li>
<li>Helper?: <span n:render="helper"/></li>
<li>Total Size: <span n:render="total_size"/></li>
<li>Progress (Hash): <span n:render="progress_hash"/></li>
<li>Progress (Ciphertext): <span n:render="progress_ciphertext"/></li>
<li>Progress (Encode+Push): <span n:render="progress_encode_push"/></li>
<li>Status: <span n:render="status"/></li>
<li>Started: <t:transparent t:render="started"/></li>
<li>Storage Index: <t:transparent t:render="si"/></li>
<li>Helper?: <t:transparent t:render="helper"/></li>
<li>Total Size: <t:transparent t:render="total_size"/></li>
<li>Progress (Hash): <t:transparent t:render="progress_hash"/></li>
<li>Progress (Ciphertext): <t:transparent t:render="progress_ciphertext"/></li>
<li>Progress (Encode+Push): <t:transparent t:render="progress_encode_push"/></li>
<li>Status: <t:transparent t:render="status"/></li>
</ul>
<div n:render="results">
<div t:render="results">
<h2>Upload Results</h2>
<ul>
<li>Shares Pushed: <span n:render="pushed_shares" /></li>
<li>Shares Already Present: <span n:render="preexisting_shares" /></li>
<li>Sharemap: <span n:render="sharemap" /></li>
<li>Servermap: <span n:render="servermap" /></li>
<li>Shares Pushed: <t:transparent t:render="pushed_shares" /></li>
<li>Shares Already Present: <t:transparent t:render="preexisting_shares" /></li>
<li>Sharemap: <t:transparent t:render="sharemap" /></li>
<li>Servermap: <t:transparent t: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>
<li>File Size: <t:transparent t:render="file_size" /> bytes</li>
<li>Total: <t:transparent t:render="time_total" />
(<t:transparent t:render="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>
<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>Storage Index: <t:transparent t:render="time_storage_index" />
(<t:transparent t:render="rate_storage_index" />)</li>
<li>[Contacting Helper]: <t:transparent t:render="time_contacting_helper" /></li>
<li>[Upload Ciphertext To Helper]: <t:transparent t:render="time_cumulative_fetch" />
(<t:transparent t:render="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>
<li>Peer Selection: <t:transparent t:render="time_peer_selection" /></li>
<li>Encode And Push: <t:transparent t:render="time_total_encode_and_push" />
(<t:transparent t:render="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>
<li>Cumulative Encoding: <t:transparent t:render="time_cumulative_encoding" />
(<t:transparent t:render="rate_encode" />)</li>
<li>Cumulative Pushing: <t:transparent t:render="time_cumulative_sending" />
(<t:transparent t:render="rate_push" />)</li>
<li>Send Hashes And Close: <t:transparent t:render="time_hashes_and_close" /></li>
</ul>
<li>[Helper Total]: <span n:render="time" n:data="time_helper_total" /></li>
<li>[Helper Total]: <t:transparent t:render="time_helper_total" /></li>
</ul>
</ul>
</ul>