From fd81c7e7ced38cbdd6ea9d1880419c645b6cad0b Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 6 Jan 2014 02:16:06 +0000 Subject: [PATCH] Nevow removal work-in-progress. refs #1963 Signed-off-by: Daira Hopwood --- src/allmydata/test/common_web.py | 9 +- src/allmydata/test/test_web.py | 6 +- src/allmydata/web/check_results.py | 55 ++++---- src/allmydata/web/common.py | 20 ++- src/allmydata/web/directory.py | 38 +++--- src/allmydata/web/filenode.py | 17 ++- src/allmydata/web/info.py | 9 +- src/allmydata/web/introweb.py | 20 ++- src/allmydata/web/operations.py | 8 +- src/allmydata/web/root.py | 25 ++-- src/allmydata/web/status.py | 196 ++++++++++++++++++++++++----- src/allmydata/web/storage.py | 13 +- src/allmydata/web/unlinked.py | 12 +- src/allmydata/webish.py | 11 +- 14 files changed, 297 insertions(+), 142 deletions(-) diff --git a/src/allmydata/test/common_web.py b/src/allmydata/test/common_web.py index f6e0ac7a..96ae21d8 100644 --- a/src/allmydata/test/common_web.py +++ b/src/allmydata/test/common_web.py @@ -3,7 +3,10 @@ import re from twisted.internet import defer from twisted.web import client from nevow.testutil import FakeRequest -from nevow import inevow, context +from nevow import context + +from allmydata.web.common import IRequest, IData + class WebRenderingMixin: # d=page.renderString() or s=page.renderSynchronously() will exercise @@ -22,8 +25,8 @@ class WebRenderingMixin: def make_context(self, req): ctx = context.RequestContext(tag=req) - ctx.remember(req, inevow.IRequest) - ctx.remember(None, inevow.IData) + ctx.remember(req, IRequest) + ctx.remember(None, IData) ctx = context.WovenContext(parent=ctx, precompile=False) return ctx diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 52c53b5b..2a5b7388 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -11,9 +11,6 @@ from twisted.python import failure, log from foolscap.api import fireEventually, flushEventualQueue -from nevow.util import escapeToXML -from nevow import rend - from allmydata import interfaces, uri, webish, dirnode from allmydata.storage.shares import get_share_file from allmydata.storage_client import StorageFarmBroker, StubServer @@ -23,6 +20,7 @@ from allmydata.dirnode import DirectoryNode from allmydata.nodemaker import NodeMaker from allmydata.unknown import UnknownNode from allmydata.web import status, common +from allmydata.web.common import Page, escapeToXML from allmydata.scripts.debug import CorruptShareOptions, corrupt_share from allmydata.util import fileutil, base32, hashutil from allmydata.util.consumer import download_to_data @@ -5856,6 +5854,6 @@ class Grid(GridTestMixin, WebErrorMixin, ShouldFailMixin, testutil.ReallyEqualMi class CompletelyUnhandledError(Exception): pass -class ErrorBoom(rend.Page): +class ErrorBoom(Page): def beforeRender(self, ctx): raise CompletelyUnhandledError("whoops") diff --git a/src/allmydata/web/check_results.py b/src/allmydata/web/check_results.py index 5a62b24c..e212abd5 100644 --- a/src/allmydata/web/check_results.py +++ b/src/allmydata/web/check_results.py @@ -1,9 +1,10 @@ import time import simplejson -from nevow import rend, inevow, tags as T + from twisted.web import http, html -from allmydata.web.common import getxmlfile, get_arg, get_root, WebError +from allmydata.web.common import getxmlfile, get_arg, get_root, WebError, \ + Page, IRequest, renderer, T from allmydata.web.operations import ReloadMixin from allmydata.interfaces import ICheckAndRepairResults, ICheckResults from allmydata.util import base32, dictutil @@ -166,14 +167,14 @@ class ResultsBase: return [html.escape(w) for w in s] def want_json(self, ctx): - output = get_arg(inevow.IRequest(ctx), "output", "").lower() + output = get_arg(IRequest(ctx), "output", "").lower() if output.lower() == "json": return True return False def _render_si_link(self, ctx, storage_index): si_s = base32.b2a(storage_index) - req = inevow.IRequest(ctx) + req = IRequest(ctx) ophandle = req.prepath[-1] target = "%s/operations/%s/%s" % (get_root(ctx), ophandle, si_s) output = get_arg(ctx, "output") @@ -181,25 +182,25 @@ class ResultsBase: target = target + "?output=%s" % output return T.a(href=target)[si_s] -class LiteralCheckResultsRenderer(rend.Page, ResultsBase): +class LiteralCheckResultsRenderer(Page, ResultsBase): docFactory = getxmlfile("literal-check-results.xhtml") def __init__(self, client): self.client = client - rend.Page.__init__(self, client) + Page.__init__(self, client) def renderHTTP(self, ctx): if self.want_json(ctx): return self.json(ctx) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") data = json_check_results(None) return simplejson.dumps(data, indent=1) + "\n" def render_return(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) return_to = get_arg(req, "return_to", None) if return_to: return T.div[T.a(href=return_to)["Return to file."]] @@ -210,28 +211,28 @@ class CheckerBase: def renderHTTP(self, ctx): if self.want_json(ctx): return self.json(ctx) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def render_storage_index(self, ctx, data): return self.r.get_storage_index_string() def render_return(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) return_to = get_arg(req, "return_to", None) if return_to: return T.div[T.a(href=return_to)["Return to file/directory."]] return "" -class CheckResultsRenderer(CheckerBase, rend.Page, ResultsBase): +class CheckResultsRenderer(CheckerBase, Page, ResultsBase): docFactory = getxmlfile("check-results.xhtml") def __init__(self, client, results): self.client = client self.r = ICheckResults(results) - rend.Page.__init__(self, results) + Page.__init__(self, results) def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") data = json_check_results(self.r) return simplejson.dumps(data, indent=1) + "\n" @@ -265,7 +266,7 @@ class CheckResultsRenderer(CheckerBase, rend.Page, ResultsBase): cr = self._render_results(ctx, data) return ctx.tag[cr] -class CheckAndRepairResultsRenderer(CheckerBase, rend.Page, ResultsBase): +class CheckAndRepairResultsRenderer(CheckerBase, Page, ResultsBase): docFactory = getxmlfile("check-and-repair-results.xhtml") def __init__(self, client, results): @@ -273,10 +274,10 @@ class CheckAndRepairResultsRenderer(CheckerBase, rend.Page, ResultsBase): self.r = None if results: self.r = ICheckAndRepairResults(results) - rend.Page.__init__(self, results) + Page.__init__(self, results) def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") data = json_check_and_repair_results(self.r) return simplejson.dumps(data, indent=1) + "\n" @@ -312,7 +313,7 @@ class CheckAndRepairResultsRenderer(CheckerBase, rend.Page, ResultsBase): return "" -class DeepCheckResultsRenderer(rend.Page, ResultsBase, ReloadMixin): +class DeepCheckResultsRenderer(Page, ResultsBase, ReloadMixin): docFactory = getxmlfile("deep-check-results.xhtml") def __init__(self, client, monitor): @@ -336,10 +337,10 @@ class DeepCheckResultsRenderer(rend.Page, ResultsBase, ReloadMixin): def renderHTTP(self, ctx): if self.want_json(ctx): return self.json(ctx) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") data = {} data["finished"] = self.monitor.is_finished() res = self.monitor.get_status() @@ -437,7 +438,7 @@ class DeepCheckResultsRenderer(rend.Page, ResultsBase, ReloadMixin): return ctx.tag def render_return(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) return_to = get_arg(req, "return_to", None) if return_to: return T.div[T.a(href=return_to)["Return to file/directory."]] @@ -459,11 +460,11 @@ class DeepCheckResultsRenderer(rend.Page, ResultsBase, ReloadMixin): return ctx.tag def render_runtime(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) runtime = time.time() - req.processing_started_timestamp return ctx.tag["runtime: %s seconds" % runtime] -class DeepCheckAndRepairResultsRenderer(rend.Page, ResultsBase, ReloadMixin): +class DeepCheckAndRepairResultsRenderer(Page, ResultsBase, ReloadMixin): docFactory = getxmlfile("deep-check-and-repair-results.xhtml") def __init__(self, client, monitor): @@ -487,10 +488,10 @@ class DeepCheckAndRepairResultsRenderer(rend.Page, ResultsBase, ReloadMixin): def renderHTTP(self, ctx): if self.want_json(ctx): return self.json(ctx) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") res = self.monitor.get_status() data = {} data["finished"] = self.monitor.is_finished() @@ -616,7 +617,7 @@ class DeepCheckAndRepairResultsRenderer(rend.Page, ResultsBase, ReloadMixin): def render_return(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) return_to = get_arg(req, "return_to", None) if return_to: return T.div[T.a(href=return_to)["Return to file/directory."]] @@ -644,6 +645,6 @@ class DeepCheckAndRepairResultsRenderer(rend.Page, ResultsBase, ReloadMixin): return ctx.tag def render_runtime(self, ctx, data): - req = inevow.IRequest(ctx) + req = IRequest(ctx) runtime = time.time() - req.processing_started_timestamp return ctx.tag["runtime: %s seconds" % runtime] diff --git a/src/allmydata/web/common.py b/src/allmydata/web/common.py index be6df366..d288b744 100644 --- a/src/allmydata/web/common.py +++ b/src/allmydata/web/common.py @@ -3,9 +3,19 @@ import simplejson from twisted.web import http, server from twisted.python import log from zope.interface import Interface -from nevow import loaders, appserver -from nevow.inevow import IRequest -from nevow.util import resource_filename +from nevow import loaders, appserver, url +from nevow import tags as T +from nevow.rend import Page +from nevow.static import File +from nevow.inevow import IRequest, IData, ICanHandleException +from nevow.util import resource_filename, escapeToXML +#from twisted.web.resource import Resource as Page +#from twisted.web.static import File +#from twisted.web.iweb import IRequest +#from twisted.web.template import renderer +#from twisted.web.template import tags as T +#from allmydata.util import url + from allmydata import blacklist from allmydata.interfaces import ExistingChildError, NoSuchChildError, \ FileTooLargeError, NotEnoughSharesError, NoSharesError, \ @@ -16,6 +26,10 @@ from allmydata.util import abbreviate from allmydata.util.encodingutil import to_str, quote_output +def renderer(func): + return func + + TIME_FORMAT = "%H:%M:%S %d-%b-%Y" diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py index 4dfe36fa..38de9ad0 100644 --- a/src/allmydata/web/directory.py +++ b/src/allmydata/web/directory.py @@ -7,8 +7,6 @@ from twisted.internet import defer from twisted.internet.interfaces import IPushProducer from twisted.python.failure import Failure from twisted.web import http -from nevow import url, rend, inevow, tags as T -from nevow.inevow import IRequest from foolscap.api import fireEventually @@ -26,7 +24,8 @@ from allmydata.web.common import text_plain, WebError, \ boolean_of_arg, get_arg, get_root, parse_replace_arg, \ should_create_intermediate_directories, \ getxmlfile, RenderMixin, humanize_failure, convert_children_json, \ - get_format, get_mutable_type + get_format, get_mutable_type, \ + Page, IRequest, renderer, T, url from allmydata.web.filenode import ReplaceMeMixin, \ FileNodeHandler, PlaceHolderNodeHandler from allmydata.web.check_results import CheckResultsRenderer, \ @@ -51,11 +50,11 @@ def make_handler_for(node, client, parentnode=None, name=None): return DirectoryNodeHandler(client, node, parentnode, name) return UnknownNodeHandler(client, node, parentnode, name) -class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): +class DirectoryNodeHandler(RenderMixin, Page, ReplaceMeMixin): addSlash = True def __init__(self, client, node, parentnode=None, name=None): - rend.Page.__init__(self) + Page.__init__(self) self.client = client assert node self.node = node @@ -164,8 +163,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): return "" if not t: - # render the directory as HTML, using the docFactory and Nevow's - # whole templating thing. + # render the directory as HTML, using the docFactory and templating thing. return DirectoryAsHTML(self.node, self.client.mutable_file_default) @@ -331,7 +329,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): d.addBoth(_maybe_got_node) # now we have a placeholder or a filenodehandler, and we can just # delegate to it. We could return the resource back out of - # DirectoryNodeHandler.renderHTTP, and nevow would recurse into it, + # DirectoryNodeHandler.renderHTTP, and it would be recursed into, # but the addCallback() that handles when_done= would break. d.addCallback(lambda child: child.renderHTTP(ctx)) return d @@ -575,14 +573,14 @@ def abbreviated_dirnode(dirnode): SPACE = u"\u00A0"*2 -class DirectoryAsHTML(rend.Page): +class DirectoryAsHTML(Page): # The remainder of this class is to render the directory into # human+browser -oriented HTML. docFactory = getxmlfile("directory.xhtml") addSlash = True def __init__(self, node, default_mutable_format): - rend.Page.__init__(self) + Page.__init__(self) self.node = node assert default_mutable_format in (MDMF_VERSION, SDMF_VERSION) @@ -934,7 +932,7 @@ def DirectoryURI(ctx, dirnode): def DirectoryReadonlyURI(ctx, dirnode): return text_plain(dirnode.get_readonly_uri(), ctx) -class RenameForm(rend.Page): +class RenameForm(Page): addSlash = True docFactory = getxmlfile("rename-form.xhtml") @@ -960,7 +958,7 @@ class RenameForm(rend.Page): ctx.tag.attributes['value'] = name return ctx.tag -class ManifestResults(rend.Page, ReloadMixin): +class ManifestResults(Page, ReloadMixin): docFactory = getxmlfile("manifest.xhtml") def __init__(self, client, monitor): @@ -968,13 +966,13 @@ class ManifestResults(rend.Page, ReloadMixin): self.monitor = monitor def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) output = get_arg(req, "output", "html").lower() if output == "text": return self.text(req) if output == "json": return self.json(req) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def slashify_path(self, path): if not path: @@ -1052,13 +1050,13 @@ class ManifestResults(rend.Page, ReloadMixin): ctx.fillSlots("cap", "") return ctx.tag -class DeepSizeResults(rend.Page): +class DeepSizeResults(Page): def __init__(self, client, monitor): self.client = client self.monitor = monitor def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) output = get_arg(req, "output", "html").lower() req.setHeader("content-type", "text/plain") if output == "json": @@ -1080,14 +1078,14 @@ class DeepSizeResults(rend.Page): } return simplejson.dumps(status) -class DeepStatsResults(rend.Page): +class DeepStatsResults(Page): def __init__(self, client, monitor): self.client = client self.monitor = monitor def renderHTTP(self, ctx): # JSON only - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") s = self.monitor.get_status().copy() s["finished"] = self.monitor.is_finished() return simplejson.dumps(s, indent=1) @@ -1228,9 +1226,9 @@ class DeepCheckStreamer(dirnode.DeepStats): return "" -class UnknownNodeHandler(RenderMixin, rend.Page): +class UnknownNodeHandler(RenderMixin, Page): def __init__(self, client, node, parentnode=None, name=None): - rend.Page.__init__(self) + Page.__init__(self) assert node self.node = node self.parentnode = parentnode diff --git a/src/allmydata/web/filenode.py b/src/allmydata/web/filenode.py index bce8e90c..df8fa251 100644 --- a/src/allmydata/web/filenode.py +++ b/src/allmydata/web/filenode.py @@ -3,8 +3,6 @@ import simplejson from twisted.web import http, static from twisted.internet import defer -from nevow import url, rend -from nevow.inevow import IRequest from allmydata.interfaces import ExistingChildError, SDMF_VERSION, MDMF_VERSION from allmydata.monitor import Monitor @@ -18,7 +16,8 @@ from allmydata.blacklist import FileProhibited, ProhibitedNode from allmydata.web.common import text_plain, WebError, RenderMixin, \ boolean_of_arg, get_arg, should_create_intermediate_directories, \ MyExceptionHandler, parse_replace_arg, parse_offset_arg, \ - get_format, get_mutable_type + get_format, get_mutable_type, \ + Page, IRequest, renderer, url from allmydata.web.check_results import CheckResultsRenderer, \ CheckAndRepairResultsRenderer, LiteralCheckResultsRenderer from allmydata.web.info import MoreInfo @@ -87,9 +86,9 @@ class ReplaceMeMixin: return d -class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): +class PlaceHolderNodeHandler(RenderMixin, Page, ReplaceMeMixin): def __init__(self, client, parentnode, name): - rend.Page.__init__(self) + Page.__init__(self) self.client = client assert parentnode self.parentnode = parentnode @@ -135,9 +134,9 @@ class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): return d -class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): +class FileNodeHandler(RenderMixin, Page, ReplaceMeMixin): def __init__(self, client, node, parentnode=None, name=None): - rend.Page.__init__(self) + Page.__init__(self) self.client = client assert node self.node = node @@ -346,9 +345,9 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): return d -class FileDownloader(rend.Page): +class FileDownloader(Page): def __init__(self, filenode, filename): - rend.Page.__init__(self) + Page.__init__(self) self.filenode = filenode self.filename = filename diff --git a/src/allmydata/web/info.py b/src/allmydata/web/info.py index ee1affae..6a4bab52 100644 --- a/src/allmydata/web/info.py +++ b/src/allmydata/web/info.py @@ -1,15 +1,14 @@ import os, urllib -from nevow import rend, tags as T -from nevow.inevow import IRequest - from allmydata.util import base32 from allmydata.interfaces import IDirectoryNode, IFileNode, MDMF_VERSION -from allmydata.web.common import getxmlfile +from allmydata.web.common import getxmlfile, \ + Page, IRequest, renderer, T from allmydata.mutable.common import UnrecoverableFileError # TODO: move -class MoreInfo(rend.Page): + +class MoreInfo(Page): addSlash = False docFactory = getxmlfile("info.xhtml") diff --git a/src/allmydata/web/introweb.py b/src/allmydata/web/introweb.py index cc8b2ce1..8086881d 100644 --- a/src/allmydata/web/introweb.py +++ b/src/allmydata/web/introweb.py @@ -1,16 +1,14 @@ -import time, os -from nevow import rend, inevow -from nevow.static import File as nevow_File -from nevow.util import resource_filename +import time, os, simplejson + import allmydata -import simplejson from allmydata import get_package_versions_string from allmydata.util import idlib -from allmydata.web.common import getxmlfile, get_arg, TIME_FORMAT +from allmydata.web.common import getxmlfile, get_arg, TIME_FORMAT, \ + Page, IRequest, File, resource_filename -class IntroducerRoot(rend.Page): +class IntroducerRoot(Page): addSlash = True docFactory = getxmlfile("introducer.xhtml") @@ -20,16 +18,16 @@ class IntroducerRoot(rend.Page): def __init__(self, introducer_node): self.introducer_node = introducer_node self.introducer_service = introducer_node.getServiceNamed("introducer") - rend.Page.__init__(self, introducer_node) + Page.__init__(self, introducer_node) static_dir = resource_filename("allmydata.web", "static") for filen in os.listdir(static_dir): - self.putChild(filen, nevow_File(os.path.join(static_dir, filen))) + self.putChild(filen, File(os.path.join(static_dir, filen))) def renderHTTP(self, ctx): - t = get_arg(inevow.IRequest(ctx), "t") + t = get_arg(IRequest(ctx), "t") if t == "json": return self.render_JSON(ctx) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def render_JSON(self, ctx): res = {} diff --git a/src/allmydata/web/operations.py b/src/allmydata/web/operations.py index 8ee9f202..6c616109 100644 --- a/src/allmydata/web/operations.py +++ b/src/allmydata/web/operations.py @@ -1,8 +1,7 @@ import time from zope.interface import implements -from nevow import rend, url, tags as T -from nevow.inevow import IRequest + from twisted.python.failure import Failure from twisted.internet import reactor, defer from twisted.web.http import NOT_FOUND @@ -10,7 +9,8 @@ from twisted.web.html import escape from twisted.application import service from allmydata.web.common import IOpHandleTable, WebError, \ - get_root, get_arg, boolean_of_arg + get_root, get_arg, boolean_of_arg, \ + Page, IRequest, renderer, T, url MINUTE = 60 HOUR = 60*MINUTE @@ -18,7 +18,7 @@ DAY = 24*HOUR (MONITOR, RENDERER, WHEN_ADDED) = range(3) -class OphandleTable(rend.Page, service.Service): +class OphandleTable(Page, service.Service): implements(IOpHandleTable) UNCOLLECTED_HANDLE_LIFETIME = 4*DAY diff --git a/src/allmydata/web/root.py b/src/allmydata/web/root.py index 9495d3df..d17d2e30 100644 --- a/src/allmydata/web/root.py +++ b/src/allmydata/web/root.py @@ -2,10 +2,6 @@ import time, os from twisted.internet import address from twisted.web import http -from nevow import rend, url, tags as T -from nevow.inevow import IRequest -from nevow.static import File as nevow_File # TODO: merge with static.File? -from nevow.util import resource_filename import allmydata # to display import path from allmydata import get_package_versions_string @@ -14,15 +10,16 @@ from allmydata.interfaces import IFileNode from allmydata.web import filenode, directory, unlinked, status, operations from allmydata.web import storage from allmydata.web.common import abbreviate_size, getxmlfile, WebError, \ - get_arg, RenderMixin, get_format, get_mutable_type, TIME_FORMAT + get_arg, RenderMixin, get_format, get_mutable_type, TIME_FORMAT, \ + Page, File, IRequest, renderer, T, url, resource_filename -class URIHandler(RenderMixin, rend.Page): +class URIHandler(RenderMixin, Page): # I live at /uri . There are several operations defined on /uri itself, # mostly involved with creation of unlinked files and directories. def __init__(self, client): - rend.Page.__init__(self, client) + Page.__init__(self, client) self.client = client def render_GET(self, ctx): @@ -33,7 +30,7 @@ class URIHandler(RenderMixin, rend.Page): there = url.URL.fromContext(ctx) there = there.clear("uri") # I thought about escaping the childcap that we attach to the URL - # here, but it seems that nevow does that for us. + # here, but it seems that is done for us. there = there.child(uri) return there @@ -89,12 +86,12 @@ class URIHandler(RenderMixin, rend.Page): raise WebError("'%s' is not a valid file- or directory- cap" % name) -class FileHandler(rend.Page): +class FileHandler(Page): # I handle /file/$FILECAP[/IGNORED] , which provides a URL from which a # file can be downloaded correctly by tools like "wget". def __init__(self, client): - rend.Page.__init__(self, client) + Page.__init__(self, client) self.client = client def childFactory(self, ctx, name): @@ -116,7 +113,7 @@ class FileHandler(rend.Page): raise WebError("/file must be followed by a file-cap and a name", http.NOT_FOUND) -class IncidentReporter(RenderMixin, rend.Page): +class IncidentReporter(RenderMixin, Page): def render_POST(self, ctx): req = IRequest(ctx) log.msg(format="User reports incident through web page: %(details)s", @@ -127,13 +124,13 @@ class IncidentReporter(RenderMixin, rend.Page): SPACE = u"\u00A0"*2 -class Root(rend.Page): +class Root(Page): addSlash = True docFactory = getxmlfile("welcome.xhtml") def __init__(self, client, clock=None): - rend.Page.__init__(self, client) + Page.__init__(self, client) self.client = client # If set, clock is a twisted.internet.task.Clock that the tests # use to test ophandle expiration. @@ -153,7 +150,7 @@ class Root(rend.Page): self.child_statistics = status.Statistics(client.stats_provider) static_dir = resource_filename("allmydata.web", "static") for filen in os.listdir(static_dir): - self.putChild(filen, nevow_File(os.path.join(static_dir, filen))) + self.putChild(filen, File(os.path.join(static_dir, filen))) def child_helper_status(self, ctx): # the Helper isn't attached until after the Tub starts, so this child diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index b363f857..9279cc7c 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -2,34 +2,39 @@ import time, pprint, itertools import simplejson from twisted.internet import defer -from nevow import rend, inevow, tags as T + from allmydata.util import base32, idlib from allmydata.web.common import getxmlfile, get_arg, \ - abbreviate_time, abbreviate_rate, abbreviate_size, plural, compute_rate + abbreviate_time, abbreviate_rate, abbreviate_size, plural, compute_rate, \ + Page, IRequest, renderer, T, url from allmydata.interfaces import IUploadStatus, IDownloadStatus, \ IPublishStatus, IRetrieveStatus, IServermapUpdaterStatus class RateAndTimeMixin: - + @renderer def render_time(self, ctx, data): return abbreviate_time(data) + @renderer def render_rate(self, ctx, data): return abbreviate_rate(data) class UploadResultsRendererMixin(RateAndTimeMixin): # this requires a method named 'upload_results' + @renderer def render_pushed_shares(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_pushed_shares()) return d + @renderer def render_preexisting_shares(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_preexisting_shares()) return d + @renderer def render_sharemap(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_sharemap()) @@ -44,6 +49,7 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_render) return d + @renderer def render_servermap(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_servermap()) @@ -59,6 +65,7 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_render) return d + @renderer def data_file_size(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_file_size()) @@ -69,33 +76,43 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(lambda res: res.get_timings().get(name)) return d + @renderer def data_time_total(self, ctx, data): return self._get_time("total") + @renderer def data_time_storage_index(self, ctx, data): return self._get_time("storage_index") + @renderer def data_time_contacting_helper(self, ctx, data): return self._get_time("contacting_helper") + @renderer def data_time_cumulative_fetch(self, ctx, data): return self._get_time("cumulative_fetch") + @renderer def data_time_helper_total(self, ctx, data): return self._get_time("helper_total") + @renderer def data_time_peer_selection(self, ctx, data): return self._get_time("peer_selection") + @renderer def data_time_total_encode_and_push(self, ctx, data): return self._get_time("total_encode_and_push") + @renderer def data_time_cumulative_encoding(self, ctx, data): return self._get_time("cumulative_encoding") + @renderer def data_time_cumulative_sending(self, ctx, data): return self._get_time("cumulative_sending") + @renderer def data_time_hashes_and_close(self, ctx, data): return self._get_time("hashes_and_close") @@ -108,18 +125,23 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_convert) return d + @renderer def data_rate_total(self, ctx, data): return self._get_rate("total") + @renderer def data_rate_storage_index(self, ctx, data): return self._get_rate("storage_index") + @renderer def data_rate_encode(self, ctx, data): return self._get_rate("cumulative_encoding") + @renderer def data_rate_push(self, ctx, data): return self._get_rate("cumulative_sending") + @renderer def data_rate_encode_and_push(self, ctx, data): d = self.upload_results() def _convert(r): @@ -133,6 +155,7 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_convert) return d + @renderer def data_rate_ciphertext_fetch(self, ctx, data): d = self.upload_results() def _convert(r): @@ -142,16 +165,17 @@ class UploadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_convert) return d -class UploadStatusPage(UploadResultsRendererMixin, rend.Page): +class UploadStatusPage(UploadResultsRendererMixin, Page): docFactory = getxmlfile("upload-status.xhtml") def __init__(self, data): - rend.Page.__init__(self, data) + Page.__init__(self, data) self.upload_status = data def upload_results(self): return defer.maybeDeferred(self.upload_status.get_results) + @renderer def render_results(self, ctx, data): d = self.upload_results() def _got_results(results): @@ -161,49 +185,58 @@ class UploadStatusPage(UploadResultsRendererMixin, rend.Page): d.addCallback(_got_results) return d + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_total_size(self, ctx, data): size = data.get_size() if size is None: return "(unknown)" return size + @renderer def render_progress_hash(self, ctx, data): progress = data.get_progress()[0] # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_progress_ciphertext(self, ctx, data): progress = data.get_progress()[1] # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer 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 render_status(self, ctx, data): return data.get_status() class DownloadResultsRendererMixin(RateAndTimeMixin): # this requires a method named 'download_results' + @renderer def render_servermap(self, ctx, data): d = self.download_results() d.addCallback(lambda res: res.servermap) @@ -222,6 +255,7 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_render) return d + @renderer def render_servers_used(self, ctx, data): d = self.download_results() d.addCallback(lambda res: res.servers_used) @@ -234,6 +268,7 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_got) return d + @renderer def render_problems(self, ctx, data): d = self.download_results() d.addCallback(lambda res: res.server_problems) @@ -248,6 +283,7 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_got) return d + @renderer def data_file_size(self, ctx, data): d = self.download_results() d.addCallback(lambda res: res.file_size) @@ -258,30 +294,39 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(lambda res: res.timings.get(name)) return d + @renderer def data_time_total(self, ctx, data): return self._get_time("total") + @renderer def data_time_peer_selection(self, ctx, data): return self._get_time("peer_selection") + @renderer def data_time_uri_extension(self, ctx, data): return self._get_time("uri_extension") + @renderer def data_time_hashtrees(self, ctx, data): return self._get_time("hashtrees") + @renderer def data_time_segments(self, ctx, data): return self._get_time("segments") + @renderer def data_time_cumulative_fetch(self, ctx, data): return self._get_time("cumulative_fetch") + @renderer def data_time_cumulative_decode(self, ctx, data): return self._get_time("cumulative_decode") + @renderer def data_time_cumulative_decrypt(self, ctx, data): return self._get_time("cumulative_decrypt") + @renderer def data_time_paused(self, ctx, data): return self._get_time("paused") @@ -294,21 +339,27 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_convert) return d + @renderer def data_rate_total(self, ctx, data): return self._get_rate("total") + @renderer def data_rate_segments(self, ctx, data): return self._get_rate("segments") + @renderer def data_rate_fetch(self, ctx, data): return self._get_rate("cumulative_fetch") + @renderer def data_rate_decode(self, ctx, data): return self._get_rate("cumulative_decode") + @renderer def data_rate_decrypt(self, ctx, data): return self._get_rate("cumulative_decrypt") + @renderer def render_server_timings(self, ctx, data): d = self.download_results() d.addCallback(lambda res: res.timings.get("fetch_per_server")) @@ -325,11 +376,11 @@ class DownloadResultsRendererMixin(RateAndTimeMixin): d.addCallback(_render) return d -class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): +class DownloadStatusPage(DownloadResultsRendererMixin, Page): docFactory = getxmlfile("download-status.xhtml") def __init__(self, data): - rend.Page.__init__(self, data) + Page.__init__(self, data) self.download_status = data def child_timeline(self, ctx): @@ -438,7 +489,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): return new_events, highest_rownums def child_event_json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + IRequest(ctx).setHeader("content-type", "text/plain") data = { } # this will be returned to the GET ds = self.download_status @@ -474,8 +525,8 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): data["bounds"] = {"min": ds.first_timestamp, "max": ds.last_timestamp} return simplejson.dumps(data, indent=1) + "\n" + @renderer def render_timeline_link(self, ctx, data): - from nevow import url return T.a(href=url.URL.fromContext(ctx).child("timeline"))["timeline"] def _rate_and_time(self, bytes, seconds): @@ -485,6 +536,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): return T.span(title=rate)[time_s] return T.span[time_s] + @renderer def render_events(self, ctx, data): if not self.download_status.storage_index: return @@ -604,6 +656,7 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): return min(ord(c) / 2 + 0x80, 0xff) return "#%02x%02x%02x" % (m(peerid[0]), m(peerid[1]), m(peerid[2])) + @renderer def render_results(self, ctx, data): d = self.download_results() def _got_results(results): @@ -613,110 +666,130 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page): d.addCallback(_got_results) return d + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + " (%s)" % data.get_started() + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_total_size(self, ctx, data): size = data.get_size() if size is None: return "(unknown)" return size + @renderer def render_progress(self, ctx, data): progress = data.get_progress() # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_status(self, ctx, data): return data.get_status() -class DownloadStatusTimelinePage(rend.Page): +class DownloadStatusTimelinePage(Page): docFactory = getxmlfile("download-status-timeline.xhtml") + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + " (%s)" % data.get_started() + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_total_size(self, ctx, data): size = data.get_size() if size is None: return "(unknown)" return size + @renderer def render_progress(self, ctx, data): progress = data.get_progress() # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_status(self, ctx, data): return data.get_status() -class RetrieveStatusPage(rend.Page, RateAndTimeMixin): +class RetrieveStatusPage(Page, RateAndTimeMixin): docFactory = getxmlfile("retrieve-status.xhtml") def __init__(self, data): - rend.Page.__init__(self, data) + Page.__init__(self, data) self.retrieve_status = data + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_current_size(self, ctx, data): size = data.get_size() if size is None: size = "(unknown)" return size + @renderer def render_progress(self, ctx, data): progress = data.get_progress() # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_status(self, ctx, data): return data.get_status() + @renderer def render_encoding(self, ctx, data): k, n = data.get_encoding() return ctx.tag["Encoding: %s of %s" % (k, n)] + @renderer def render_problems(self, ctx, data): problems = data.get_problems() if not problems: @@ -732,26 +805,35 @@ class RetrieveStatusPage(rend.Page, RateAndTimeMixin): time = self.retrieve_status.timings.get(name) return compute_rate(file_size, time) + @renderer def data_time_total(self, ctx, data): return self.retrieve_status.timings.get("total") + @renderer def data_rate_total(self, ctx, data): return self._get_rate(data, "total") + @renderer def data_time_fetch(self, ctx, data): return self.retrieve_status.timings.get("fetch") + @renderer def data_rate_fetch(self, ctx, data): return self._get_rate(data, "fetch") + @renderer def data_time_decode(self, ctx, data): return self.retrieve_status.timings.get("decode") + @renderer def data_rate_decode(self, ctx, data): return self._get_rate(data, "decode") + @renderer def data_time_decrypt(self, ctx, data): return self.retrieve_status.timings.get("decrypt") + @renderer def data_rate_decrypt(self, ctx, data): return self._get_rate(data, "decrypt") + @renderer def render_server_timings(self, ctx, data): per_server = self.retrieve_status.timings.get("fetch_per_server") if not per_server: @@ -764,47 +846,55 @@ class RetrieveStatusPage(rend.Page, RateAndTimeMixin): return T.li["Per-Server Fetch Response Times: ", l] -class PublishStatusPage(rend.Page, RateAndTimeMixin): +class PublishStatusPage(Page, RateAndTimeMixin): docFactory = getxmlfile("publish-status.xhtml") def __init__(self, data): - rend.Page.__init__(self, data) + Page.__init__(self, data) self.publish_status = data + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_current_size(self, ctx, data): size = data.get_size() if size is None: size = "(unknown)" return size + @renderer def render_progress(self, ctx, data): progress = data.get_progress() # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_status(self, ctx, data): return data.get_status() + @renderer def render_encoding(self, ctx, data): k, n = data.get_encoding() return ctx.tag["Encoding: %s of %s" % (k, n)] + @renderer def render_sharemap(self, ctx, data): servermap = data.get_servermap() if servermap is None: @@ -817,6 +907,7 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): for server in sharemap[shnum]])]] return ctx.tag["Sharemap:", l] + @renderer def render_problems(self, ctx, data): problems = data.get_problems() if not problems: @@ -834,36 +925,49 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): time = self.publish_status.timings.get(name) return compute_rate(file_size, time) + @renderer def data_time_total(self, ctx, data): return self.publish_status.timings.get("total") + @renderer def data_rate_total(self, ctx, data): return self._get_rate(data, "total") + @renderer def data_time_setup(self, ctx, data): return self.publish_status.timings.get("setup") + @renderer def data_time_encrypt(self, ctx, data): return self.publish_status.timings.get("encrypt") + @renderer def data_rate_encrypt(self, ctx, data): return self._get_rate(data, "encrypt") + @renderer def data_time_encode(self, ctx, data): return self.publish_status.timings.get("encode") + @renderer def data_rate_encode(self, ctx, data): return self._get_rate(data, "encode") + @renderer def data_time_pack(self, ctx, data): return self.publish_status.timings.get("pack") + @renderer def data_rate_pack(self, ctx, data): return self._get_rate(data, "pack") + @renderer def data_time_sign(self, ctx, data): return self.publish_status.timings.get("sign") + @renderer def data_time_push(self, ctx, data): return self.publish_status.timings.get("push") + @renderer def data_rate_push(self, ctx, data): return self._get_rate(data, "push") + @renderer def render_server_timings(self, ctx, data): per_server = self.publish_status.timings.get("send_per_server") if not per_server: @@ -875,19 +979,21 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): l[T.li["[%s]: %s" % (server.get_name(), times_s)]] return T.li["Per-Server Response Times: ", l] -class MapupdateStatusPage(rend.Page, RateAndTimeMixin): +class MapupdateStatusPage(Page, RateAndTimeMixin): docFactory = getxmlfile("map-update-status.xhtml") def __init__(self, data): - rend.Page.__init__(self, data) + Page.__init__(self, data) self.update_status = data + @renderer def render_started(self, ctx, data): TIME_FORMAT = "%H:%M:%S %d-%b-%Y" started_s = time.strftime(TIME_FORMAT, time.localtime(data.get_started())) return started_s + @renderer def render_finished(self, ctx, data): when = data.get_finished() if not when: @@ -897,24 +1003,29 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): time.localtime(data.get_finished())) return started_s + @renderer def render_si(self, ctx, data): si_s = base32.b2a_or_none(data.get_storage_index()) if si_s is None: si_s = "(None)" return si_s + @renderer def render_helper(self, ctx, data): return {True: "Yes", False: "No"}[data.using_helper()] + @renderer def render_progress(self, ctx, data): progress = data.get_progress() # TODO: make an ascii-art bar return "%.1f%%" % (100.0 * progress) + @renderer def render_status(self, ctx, data): return data.get_status() + @renderer def render_problems(self, ctx, data): problems = data.problems if not problems: @@ -925,6 +1036,7 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): l[T.li["[%s]: %s" % (peerid_s, problems[peerid])]] return ctx.tag["Server Problems:", l] + @renderer def render_privkey_from(self, ctx, data): server = data.get_privkey_from() if server: @@ -932,15 +1044,19 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): else: return "" + @renderer def data_time_total(self, ctx, data): return self.update_status.timings.get("total") + @renderer def data_time_initial_queries(self, ctx, data): return self.update_status.timings.get("initial_queries") + @renderer def data_time_cumulative_verify(self, ctx, data): return self.update_status.timings.get("cumulative_verify") + @renderer def render_server_timings(self, ctx, data): per_server = self.update_status.timings.get("per_server") if not per_server: @@ -963,6 +1079,7 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): l[T.li["[%s]: %s" % (server.get_name(), times_s)]] return T.li["Per-Server Response Times: ", l] + @renderer def render_timing_chart(self, ctx, data): imageurl = self._timing_chart() return ctx.tag[imageurl] @@ -1034,20 +1151,20 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): return T.img(src=url,border="1",align="right", float="right") -class Status(rend.Page): +class Status(Page): docFactory = getxmlfile("status.xhtml") addSlash = True def __init__(self, history): - rend.Page.__init__(self, history) + Page.__init__(self, history) self.history = history def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) t = get_arg(req, "t") if t == "json": return self.json(req) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def json(self, req): req.setHeader("content-type", "text/plain") @@ -1087,6 +1204,7 @@ class Status(rend.Page): h.list_all_helper_statuses(), ) + @renderer def data_active_operations(self, ctx, data): return self._get_active_operations() @@ -1096,6 +1214,7 @@ class Status(rend.Page): if s.get_active()] return active + @renderer def data_recent_operations(self, ctx, data): return self._get_recent_operations() @@ -1107,6 +1226,7 @@ class Status(rend.Page): recent.reverse() return recent + @renderer def render_row(self, ctx, data): s = data @@ -1189,19 +1309,19 @@ class Status(rend.Page): return RetrieveStatusPage(s) -class HelperStatus(rend.Page): +class HelperStatus(Page): docFactory = getxmlfile("helper.xhtml") def __init__(self, helper): - rend.Page.__init__(self, helper) + Page.__init__(self, helper) self.helper = helper def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) t = get_arg(req, "t") if t == "json": return self.render_JSON(req) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def data_helper_stats(self, ctx, data): return self.helper.get_stats() @@ -1213,99 +1333,119 @@ class HelperStatus(rend.Page): return simplejson.dumps(stats, indent=1) + "\n" return simplejson.dumps({}) + "\n" + @renderer def render_active_uploads(self, ctx, data): return data["chk_upload_helper.active_uploads"] + @renderer def render_incoming(self, ctx, data): return "%d bytes in %d files" % (data["chk_upload_helper.incoming_size"], data["chk_upload_helper.incoming_count"]) + @renderer def render_encoding(self, ctx, data): return "%d bytes in %d files" % (data["chk_upload_helper.encoding_size"], data["chk_upload_helper.encoding_count"]) + @renderer def render_upload_requests(self, ctx, data): return str(data["chk_upload_helper.upload_requests"]) + @renderer def render_upload_already_present(self, ctx, data): return str(data["chk_upload_helper.upload_already_present"]) + @renderer def render_upload_need_upload(self, ctx, data): return str(data["chk_upload_helper.upload_need_upload"]) + @renderer def render_upload_bytes_fetched(self, ctx, data): return str(data["chk_upload_helper.fetched_bytes"]) + @renderer def render_upload_bytes_encoded(self, ctx, data): return str(data["chk_upload_helper.encoded_bytes"]) -class Statistics(rend.Page): +class Statistics(Page): docFactory = getxmlfile("statistics.xhtml") def __init__(self, provider): - rend.Page.__init__(self, provider) + Page.__init__(self, provider) self.provider = provider def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) t = get_arg(req, "t") if t == "json": stats = self.provider.get_stats() req.setHeader("content-type", "text/plain") return simplejson.dumps(stats, indent=1) + "\n" - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) + @renderer def data_get_stats(self, ctx, data): return self.provider.get_stats() + @renderer def render_load_average(self, ctx, data): return str(data["stats"].get("load_monitor.avg_load")) + @renderer def render_peak_load(self, ctx, data): return str(data["stats"].get("load_monitor.max_load")) + @renderer def render_uploads(self, ctx, data): files = data["counters"].get("uploader.files_uploaded", 0) bytes = data["counters"].get("uploader.bytes_uploaded", 0) return ("%s files / %s bytes (%s)" % (files, bytes, abbreviate_size(bytes))) + @renderer def render_downloads(self, ctx, data): files = data["counters"].get("downloader.files_downloaded", 0) bytes = data["counters"].get("downloader.bytes_downloaded", 0) return ("%s files / %s bytes (%s)" % (files, bytes, abbreviate_size(bytes))) + @renderer def render_publishes(self, ctx, data): files = data["counters"].get("mutable.files_published", 0) bytes = data["counters"].get("mutable.bytes_published", 0) return "%s files / %s bytes (%s)" % (files, bytes, abbreviate_size(bytes)) + @renderer def render_retrieves(self, ctx, data): files = data["counters"].get("mutable.files_retrieved", 0) bytes = data["counters"].get("mutable.bytes_retrieved", 0) return "%s files / %s bytes (%s)" % (files, bytes, abbreviate_size(bytes)) + @renderer def render_drop_monitored(self, ctx, data): dirs = data["counters"].get("drop_upload.dirs_monitored", 0) return "%s directories" % (dirs,) + @renderer def render_drop_uploads(self, ctx, data): # TODO: bytes uploaded files = data["counters"].get("drop_upload.files_uploaded", 0) return "%s files" % (files,) + @renderer def render_drop_queued(self, ctx, data): files = data["counters"].get("drop_upload.files_queued", 0) return "%s files" % (files,) + @renderer def render_drop_failed(self, ctx, data): files = data["counters"].get("drop_upload.files_failed", 0) return "%s files" % (files,) + @renderer def render_raw(self, ctx, data): raw = pprint.pformat(data) return ctx.tag[raw] diff --git a/src/allmydata/web/storage.py b/src/allmydata/web/storage.py index 24d769bb..0754094a 100644 --- a/src/allmydata/web/storage.py +++ b/src/allmydata/web/storage.py @@ -1,7 +1,8 @@ import time, simplejson -from nevow import rend, tags as T, inevow -from allmydata.web.common import getxmlfile, abbreviate_time, get_arg + +from allmydata.web.common import getxmlfile, abbreviate_time, get_arg, \ + Page, IRequest, renderer, T from allmydata.util.abbreviate import abbreviate_space from allmydata.util import time_format, idlib @@ -10,21 +11,21 @@ def remove_prefix(s, prefix): return None return s[len(prefix):] -class StorageStatus(rend.Page): +class StorageStatus(Page): docFactory = getxmlfile("storage_status.xhtml") # the default 'data' argument is the StorageServer instance def __init__(self, storage, nickname=""): - rend.Page.__init__(self, storage) + Page.__init__(self, storage) self.storage = storage self.nickname = nickname def renderHTTP(self, ctx): - req = inevow.IRequest(ctx) + req = IRequest(ctx) t = get_arg(req, "t") if t == "json": return self.render_JSON(req) - return rend.Page.renderHTTP(self, ctx) + return Page.renderHTTP(self, ctx) def render_JSON(self, req): req.setHeader("content-type", "text/plain") diff --git a/src/allmydata/web/unlinked.py b/src/allmydata/web/unlinked.py index 8a84a402..623be409 100644 --- a/src/allmydata/web/unlinked.py +++ b/src/allmydata/web/unlinked.py @@ -2,11 +2,12 @@ import urllib from twisted.web import http from twisted.internet import defer -from nevow import rend, url, tags as T + 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 + convert_children_json, WebError, get_format, get_mutable_type, \ + Page, renderer, T, url from allmydata.web import status def PUTUnlinkedCHK(req, client): @@ -59,27 +60,30 @@ def POSTUnlinkedCHK(req, client): return d -class UploadResultsPage(status.UploadResultsRendererMixin, rend.Page): +class UploadResultsPage(status.UploadResultsRendererMixin, Page): """'POST /uri', to create an unlinked file.""" docFactory = getxmlfile("upload-results.xhtml") def __init__(self, upload_results): - rend.Page.__init__(self) + Page.__init__(self) self.results = upload_results def upload_results(self): return defer.succeed(self.results) + @renderer def data_done(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: "done!") return d + @renderer def data_uri(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: res.get_uri()) return d + @renderer def render_download_link(self, ctx, data): d = self.upload_results() d.addCallback(lambda res: diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py index 813856cb..2c61da4d 100644 --- a/src/allmydata/webish.py +++ b/src/allmydata/webish.py @@ -2,11 +2,14 @@ import re, time from twisted.application import service, strports, internet from twisted.web import http from twisted.internet import defer -from nevow import appserver, inevow, static +from nevow import appserver + from allmydata.util import log, fileutil from allmydata.web import introweb, root -from allmydata.web.common import IOpHandleTable, MyExceptionHandler +from allmydata.web.common import IOpHandleTable, MyExceptionHandler, \ + File, ICanHandleException + # we must override twisted.web.http.Request.requestReceived with a version # that doesn't use cgi.parse_multipart() . Since we actually use Nevow, we @@ -146,9 +149,9 @@ class WebishServer(service.MultiService): self.webport = webport self.site = site = appserver.NevowSite(self.root) self.site.requestFactory = MyRequest - self.site.remember(MyExceptionHandler(), inevow.ICanHandleException) + self.site.remember(MyExceptionHandler(), ICanHandleException) if staticdir: - self.root.putChild("static", static.File(staticdir)) + self.root.putChild("static", File(staticdir)) if re.search(r'^\d', webport): webport = "tcp:"+webport # twisted warns about bare "0" or "3456" s = strports.service(webport, site) -- 2.45.2