From c6c30ac5d4965dc4b480e374dec5d4cb4e6815f1 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Fri, 20 Feb 2009 12:15:54 -0700 Subject: [PATCH] webapi: pass client through constructor arguments, remove IClient, should make it easier to test web renderers in isolation --- src/allmydata/client.py | 4 +- src/allmydata/introducer/server.py | 2 +- src/allmydata/test/test_web.py | 8 ++- src/allmydata/web/check_results.py | 61 +++++++++++-------- src/allmydata/web/common.py | 2 - src/allmydata/web/directory.py | 77 +++++++++++++----------- src/allmydata/web/filenode.py | 50 +++++++--------- src/allmydata/web/helper.xhtml | 2 +- src/allmydata/web/introweb.py | 30 +++++----- src/allmydata/web/root.py | 89 +++++++++++++++------------ src/allmydata/web/statistics.xhtml | 2 +- src/allmydata/web/status.py | 96 +++++++++++++++++------------- src/allmydata/web/unlinked.py | 35 ++++------- src/allmydata/webish.py | 33 +++++----- 14 files changed, 265 insertions(+), 226 deletions(-) diff --git a/src/allmydata/client.py b/src/allmydata/client.py index a77bda4f..766cae04 100644 --- a/src/allmydata/client.py +++ b/src/allmydata/client.py @@ -91,6 +91,8 @@ class Client(node.Node, pollmixin.PollMixin): hotline = TimerService(1.0, self._check_hotline, hotline_file) hotline.setServiceParent(self) + # this needs to happen last, so it can use getServiceNamed() to + # acquire references to StorageServer and other web-statusable things webport = self.get_config("node", "web.port", None) if webport: self.init_web(webport) # strports string @@ -269,7 +271,7 @@ class Client(node.Node, pollmixin.PollMixin): nodeurl_path = os.path.join(self.basedir, "node.url") staticdir = self.get_config("node", "web.static", "public_html") staticdir = os.path.expanduser(staticdir) - ws = WebishServer(webport, nodeurl_path, staticdir) + ws = WebishServer(self, webport, nodeurl_path, staticdir) self.add_service(ws) def init_ftp_server(self): diff --git a/src/allmydata/introducer/server.py b/src/allmydata/introducer/server.py index 5e519533..d0ed6412 100644 --- a/src/allmydata/introducer/server.py +++ b/src/allmydata/introducer/server.py @@ -41,7 +41,7 @@ class IntroducerNode(node.Node): from allmydata.webish import IntroducerWebishServer nodeurl_path = os.path.join(self.basedir, "node.url") - ws = IntroducerWebishServer(webport, nodeurl_path) + ws = IntroducerWebishServer(self, webport, nodeurl_path) self.add_service(ws) class IntroducerService(service.MultiService, Referenceable): diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 940a1c8b..e2ae8fc4 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -33,6 +33,11 @@ class FakeIntroducerClient: def get_all_peerids(self): return frozenset() +class FakeStatsProvider: + def get_stats(self): + stats = {'stats': {}, 'counters': {}} + return stats + class FakeClient(service.MultiService): nodeid = "fake_nodeid" nickname = "fake_nickname" @@ -51,6 +56,7 @@ class FakeClient(service.MultiService): _all_publish_statuses = [publish.PublishStatus()] _all_retrieve_statuses = [retrieve.RetrieveStatus()] convergence = "some random string" + stats_provider = FakeStatsProvider() def connected_to_introducer(self): return False @@ -134,7 +140,7 @@ class WebMixin(object): self.s = FakeClient() self.s.startService() self.staticdir = self.mktemp() - self.ws = s = webish.WebishServer("0", staticdir=self.staticdir) + self.ws = s = webish.WebishServer(self.s, "0", staticdir=self.staticdir) s.setServiceParent(self.s) self.webish_port = port = s.listener._port.getHost().port self.webish_url = "http://localhost:%d" % port diff --git a/src/allmydata/web/check_results.py b/src/allmydata/web/check_results.py index bf7d75db..eeb30709 100644 --- a/src/allmydata/web/check_results.py +++ b/src/allmydata/web/check_results.py @@ -3,8 +3,7 @@ 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, \ - IClient, WebError +from allmydata.web.common import getxmlfile, get_arg, get_root, WebError from allmydata.web.operations import ReloadMixin from allmydata.interfaces import ICheckAndRepairResults, ICheckResults from allmydata.util import base32, idlib @@ -68,6 +67,9 @@ def json_check_and_repair_results(r): return data class ResultsBase: + # self.client must point to the Client, so we can get nicknames and + # determine the permuted peer order + def _join_pathstring(self, path): if path: pathstring = "/".join(self._html(path)) @@ -77,7 +79,7 @@ class ResultsBase: def _render_results(self, ctx, cr): assert ICheckResults(cr) - c = IClient(ctx) + c = self.client data = cr.get_data() r = [] def add(name, value): @@ -178,6 +180,10 @@ class ResultsBase: class LiteralCheckResults(rend.Page, ResultsBase): docFactory = getxmlfile("literal-check-results.xhtml") + def __init__(self, client): + self.client = client + rend.Page.__init__(self, client) + def renderHTTP(self, ctx): if self.want_json(ctx): return self.json(ctx) @@ -217,8 +223,10 @@ class CheckerBase: class CheckResults(CheckerBase, rend.Page, ResultsBase): docFactory = getxmlfile("check-results.xhtml") - def __init__(self, results): + def __init__(self, client, results): + self.client = client self.r = ICheckResults(results) + rend.Page.__init__(self, results) def json(self, ctx): inevow.IRequest(ctx).setHeader("content-type", "text/plain") @@ -227,18 +235,18 @@ class CheckResults(CheckerBase, rend.Page, ResultsBase): def render_summary(self, ctx, data): results = [] - if self.r.is_healthy(): + if data.is_healthy(): results.append("Healthy") - elif self.r.is_recoverable(): + elif data.is_recoverable(): results.append("Not Healthy!") else: results.append("Not Recoverable!") results.append(" : ") - results.append(self._html(self.r.get_summary())) + results.append(self._html(data.get_summary())) return ctx.tag[results] def render_repair(self, ctx, data): - if self.r.is_healthy(): + if data.is_healthy(): return "" repair = T.form(action=".", method="post", enctype="multipart/form-data")[ @@ -250,14 +258,16 @@ class CheckResults(CheckerBase, rend.Page, ResultsBase): return ctx.tag[repair] def render_results(self, ctx, data): - cr = self._render_results(ctx, self.r) + cr = self._render_results(ctx, data) return ctx.tag[cr] class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase): docFactory = getxmlfile("check-and-repair-results.xhtml") - def __init__(self, results): + def __init__(self, client, results): + self.client = client self.r = ICheckAndRepairResults(results) + rend.Page.__init__(self, results) def json(self, ctx): inevow.IRequest(ctx).setHeader("content-type", "text/plain") @@ -265,7 +275,7 @@ class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase): return simplejson.dumps(data, indent=1) + "\n" def render_summary(self, ctx, data): - cr = self.r.get_post_repair_results() + cr = data.get_post_repair_results() results = [] if cr.is_healthy(): results.append("Healthy") @@ -278,20 +288,20 @@ class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase): return ctx.tag[results] def render_repair_results(self, ctx, data): - if self.r.get_repair_attempted(): - if self.r.get_repair_successful(): + if data.get_repair_attempted(): + if data.get_repair_successful(): return ctx.tag["Repair successful"] else: return ctx.tag["Repair unsuccessful"] return ctx.tag["No repair necessary"] def render_post_repair_results(self, ctx, data): - cr = self._render_results(ctx, self.r.get_post_repair_results()) + cr = self._render_results(ctx, data.get_post_repair_results()) return ctx.tag[T.div["Post-Repair Checker Results:"], cr] def render_maybe_pre_repair_results(self, ctx, data): - if self.r.get_repair_attempted(): - cr = self._render_results(ctx, self.r.get_pre_repair_results()) + if data.get_repair_attempted(): + cr = self._render_results(ctx, data.get_pre_repair_results()) return ctx.tag[T.div["Pre-Repair Checker Results:"], cr] return "" @@ -299,7 +309,8 @@ class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase): class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin): docFactory = getxmlfile("deep-check-results.xhtml") - def __init__(self, monitor): + def __init__(self, client, monitor): + self.client = client self.monitor = monitor def childFactory(self, ctx, name): @@ -310,7 +321,8 @@ class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin): si = base32.a2b(name) r = self.monitor.get_status() try: - return CheckResults(r.get_results_for_storage_index(si)) + return CheckResults(self.client, + r.get_results_for_storage_index(si)) except KeyError: raise WebError("No detailed results for SI %s" % html.escape(name), http.NOT_FOUND) @@ -397,8 +409,7 @@ class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin): def render_server_problem(self, ctx, data): serverid = data data = [idlib.shortnodeid_b2a(serverid)] - c = IClient(ctx) - nickname = c.get_nickname_for_peerid(serverid) + nickname = self.client.get_nickname_for_peerid(serverid) if nickname: data.append(" (%s)" % self._html(nickname)) return ctx.tag[data] @@ -412,7 +423,7 @@ class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin): return self.monitor.get_status().get_corrupt_shares() def render_share_problem(self, ctx, data): serverid, storage_index, sharenum = data - nickname = IClient(ctx).get_nickname_for_peerid(serverid) + nickname = self.client.get_nickname_for_peerid(serverid) ctx.fillSlots("serverid", idlib.shortnodeid_b2a(serverid)) if nickname: ctx.fillSlots("nickname", self._html(nickname)) @@ -450,9 +461,8 @@ class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin): class DeepCheckAndRepairResults(rend.Page, ResultsBase, ReloadMixin): docFactory = getxmlfile("deep-check-and-repair-results.xhtml") - def __init__(self, monitor): - #assert IDeepCheckAndRepairResults(results) - #self.r = results + def __init__(self, client, monitor): + self.client = client self.monitor = monitor def childFactory(self, ctx, name): @@ -463,7 +473,8 @@ class DeepCheckAndRepairResults(rend.Page, ResultsBase, ReloadMixin): si = base32.a2b(name) r = self.monitor.get_status() try: - return CheckAndRepairResults(r.get_results_for_storage_index(si)) + return CheckAndRepairResults(self.client, + r.get_results_for_storage_index(si)) except KeyError: raise WebError("No detailed results for SI %s" % html.escape(name), http.NOT_FOUND) diff --git a/src/allmydata/web/common.py b/src/allmydata/web/common.py index a831b80d..ec86d46a 100644 --- a/src/allmydata/web/common.py +++ b/src/allmydata/web/common.py @@ -7,8 +7,6 @@ from nevow.util import resource_filename from allmydata.interfaces import ExistingChildError, NoSuchChildError, \ FileTooLargeError, NotEnoughSharesError -class IClient(Interface): - pass class IOpHandleTable(Interface): pass diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py index e8ce3f7a..d4798665 100644 --- a/src/allmydata/web/directory.py +++ b/src/allmydata/web/directory.py @@ -20,7 +20,7 @@ from allmydata.interfaces import IDirectoryNode, IFileNode, IMutableFileNode, \ from allmydata.monitor import Monitor, OperationCancelledError from allmydata import dirnode from allmydata.web.common import text_plain, WebError, \ - IClient, IOpHandleTable, NeedOperationHandleError, \ + IOpHandleTable, NeedOperationHandleError, \ boolean_of_arg, get_arg, get_root, \ should_create_intermediate_directories, \ getxmlfile, RenderMixin @@ -38,22 +38,23 @@ class BlockingFileError(Exception): """We cannot auto-create a parent directory, because there is a file in the way""" -def make_handler_for(node, parentnode=None, name=None): +def make_handler_for(node, client, parentnode=None, name=None): if parentnode: assert IDirectoryNode.providedBy(parentnode) if IMutableFileNode.providedBy(node): - return FileNodeHandler(node, parentnode, name) + return FileNodeHandler(client, node, parentnode, name) if IFileNode.providedBy(node): - return FileNodeHandler(node, parentnode, name) + return FileNodeHandler(client, node, parentnode, name) if IDirectoryNode.providedBy(node): - return DirectoryNodeHandler(node, parentnode, name) + return DirectoryNodeHandler(client, node, parentnode, name) raise WebError("Cannot provide handler for '%s'" % node) class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): addSlash = True - def __init__(self, node, parentnode=None, name=None): + def __init__(self, client, node, parentnode=None, name=None): rend.Page.__init__(self) + self.client = client assert node self.node = node self.parentnode = parentnode @@ -87,7 +88,8 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # create intermediate directories if DEBUG: print " making intermediate directory" d = self.node.create_empty_directory(name) - d.addCallback(make_handler_for, self.node, name) + d.addCallback(make_handler_for, + self.client, self.node, name) return d else: if DEBUG: print " terminal" @@ -96,7 +98,8 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): if DEBUG: print " making final directory" # final directory d = self.node.create_empty_directory(name) - d.addCallback(make_handler_for, self.node, name) + d.addCallback(make_handler_for, + self.client, self.node, name) return d if (method,t) in ( ("PUT",""), ("PUT","uri"), ): if DEBUG: print " PUT, making leaf placeholder" @@ -105,7 +108,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # since that's the leaf node that we're about to create. # We make a dummy one, which will respond to the PUT # request by replacing itself. - return PlaceHolderNodeHandler(self.node, name) + return PlaceHolderNodeHandler(self.client, self.node, name) if DEBUG: print " 404" # otherwise, we just return a no-such-child error return rend.FourOhFour() @@ -120,7 +123,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): "a file was in the way" % name, http.CONFLICT) if DEBUG: print "good child" - return make_handler_for(node, self.node, name) + return make_handler_for(node, self.client, self.node, name) def render_DELETE(self, ctx): assert self.parentnode and self.name @@ -129,7 +132,6 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): return d def render_GET(self, ctx): - client = IClient(ctx) req = IRequest(ctx) # This is where all of the directory-related ?t=* code goes. t = get_arg(req, "t", "").strip() @@ -164,7 +166,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # they're trying to set_uri and that name is already occupied # (by us). raise ExistingChildError() - d = self.replace_me_with_a_childcap(ctx, replace) + d = self.replace_me_with_a_childcap(req, self.client, replace) # TODO: results return d @@ -279,10 +281,10 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): f = node_or_failure f.trap(NoSuchChildError) # create a placeholder which will see POST t=upload - return PlaceHolderNodeHandler(self.node, name) + return PlaceHolderNodeHandler(self.client, self.node, name) else: node = node_or_failure - return make_handler_for(node, self.node, name) + return make_handler_for(node, self.client, self.node, name) 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 @@ -358,10 +360,10 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): add_lease = boolean_of_arg(get_arg(req, "add-lease", "false")) if repair: d = self.node.check_and_repair(Monitor(), verify, add_lease) - d.addCallback(lambda res: CheckAndRepairResults(res)) + d.addCallback(lambda res: CheckAndRepairResults(self.client, res)) else: d = self.node.check(Monitor(), verify, add_lease) - d.addCallback(lambda res: CheckResults(res)) + d.addCallback(lambda res: CheckResults(self.client, res)) return d def _start_operation(self, monitor, renderer, ctx): @@ -378,10 +380,10 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false")) if repair: monitor = self.node.start_deep_check_and_repair(verify, add_lease) - renderer = DeepCheckAndRepairResults(monitor) + renderer = DeepCheckAndRepairResults(self.client, monitor) else: monitor = self.node.start_deep_check(verify, add_lease) - renderer = DeepCheckResults(monitor) + renderer = DeepCheckResults(self.client, monitor) return self._start_operation(monitor, renderer, ctx) def _POST_stream_deep_check(self, ctx): @@ -408,21 +410,21 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): if not get_arg(ctx, "ophandle"): raise NeedOperationHandleError("slow operation requires ophandle=") monitor = self.node.build_manifest() - renderer = ManifestResults(monitor) + renderer = ManifestResults(self.client, monitor) return self._start_operation(monitor, renderer, ctx) def _POST_start_deep_size(self, ctx): if not get_arg(ctx, "ophandle"): raise NeedOperationHandleError("slow operation requires ophandle=") monitor = self.node.start_deep_stats() - renderer = DeepSizeResults(monitor) + renderer = DeepSizeResults(self.client, monitor) return self._start_operation(monitor, renderer, ctx) def _POST_start_deep_stats(self, ctx): if not get_arg(ctx, "ophandle"): raise NeedOperationHandleError("slow operation requires ophandle=") monitor = self.node.start_deep_stats() - renderer = DeepStatsResults(monitor) + renderer = DeepStatsResults(self.client, monitor) return self._start_operation(monitor, renderer, ctx) def _POST_stream_manifest(self, ctx): @@ -761,15 +763,17 @@ class RenameForm(rend.Page): class ManifestResults(rend.Page, ReloadMixin): docFactory = getxmlfile("manifest.xhtml") - def __init__(self, monitor): + def __init__(self, client, monitor): + self.client = client self.monitor = monitor def renderHTTP(self, ctx): - output = get_arg(inevow.IRequest(ctx), "output", "html").lower() + req = inevow.IRequest(ctx) + output = get_arg(req, "output", "html").lower() if output == "text": - return self.text(ctx) + return self.text(req) if output == "json": - return self.json(ctx) + return self.json(req) return rend.Page.renderHTTP(self, ctx) def slashify_path(self, path): @@ -777,8 +781,8 @@ class ManifestResults(rend.Page, ReloadMixin): return "" return "/".join([p.encode("utf-8") for p in path]) - def text(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + def text(self, req): + req.setHeader("content-type", "text/plain") lines = [] is_finished = self.monitor.is_finished() lines.append("finished: " + {True: "yes", False: "no"}[is_finished]) @@ -786,8 +790,8 @@ class ManifestResults(rend.Page, ReloadMixin): lines.append(self.slashify_path(path) + " " + cap) return "\n".join(lines) + "\n" - def json(self, ctx): - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + def json(self, req): + req.setHeader("content-type", "text/plain") m = self.monitor s = m.get_status() @@ -839,14 +843,16 @@ class ManifestResults(rend.Page, ReloadMixin): return ctx.tag class DeepSizeResults(rend.Page): - def __init__(self, monitor): + def __init__(self, client, monitor): + self.client = client self.monitor = monitor def renderHTTP(self, ctx): - output = get_arg(inevow.IRequest(ctx), "output", "html").lower() - inevow.IRequest(ctx).setHeader("content-type", "text/plain") + req = inevow.IRequest(ctx) + output = get_arg(req, "output", "html").lower() + req.setHeader("content-type", "text/plain") if output == "json": - return self.json(ctx) + return self.json(req) # plain text is_finished = self.monitor.is_finished() output = "finished: " + {True: "yes", False: "no"}[is_finished] + "\n" @@ -858,14 +864,15 @@ class DeepSizeResults(rend.Page): output += "size: %d\n" % total return output - def json(self, ctx): + def json(self, req): status = {"finished": self.monitor.is_finished(), "size": self.monitor.get_status(), } return simplejson.dumps(status) class DeepStatsResults(rend.Page): - def __init__(self, monitor): + def __init__(self, client, monitor): + self.client = client self.monitor = monitor def renderHTTP(self, ctx): diff --git a/src/allmydata/web/filenode.py b/src/allmydata/web/filenode.py index 0a2081a7..78e235b6 100644 --- a/src/allmydata/web/filenode.py +++ b/src/allmydata/web/filenode.py @@ -12,7 +12,7 @@ from allmydata.immutable.upload import FileHandle from allmydata.immutable.filenode import LiteralFileNode from allmydata.util import log, base32 -from allmydata.web.common import text_plain, WebError, IClient, RenderMixin, \ +from allmydata.web.common import text_plain, WebError, RenderMixin, \ boolean_of_arg, get_arg, should_create_intermediate_directories from allmydata.web.check_results import CheckResults, \ CheckAndRepairResults, LiteralCheckResults @@ -20,10 +20,8 @@ from allmydata.web.info import MoreInfo class ReplaceMeMixin: - def replace_me_with_a_child(self, ctx, replace): + def replace_me_with_a_child(self, req, client, replace): # a new file is being uploaded in our place. - req = IRequest(ctx) - client = IClient(ctx) mutable = boolean_of_arg(get_arg(req, "mutable", "false")) if mutable: req.content.seek(0) @@ -53,11 +51,9 @@ class ReplaceMeMixin: d.addCallback(_done) return d - def replace_me_with_a_childcap(self, ctx, replace): - req = IRequest(ctx) + def replace_me_with_a_childcap(self, req, client, replace): req.content.seek(0) childcap = req.content.read() - client = IClient(ctx) childnode = client.create_node_from_uri(childcap) d = self.parentnode.set_node(self.name, childnode, overwrite=replace) d.addCallback(lambda res: childnode.get_uri()) @@ -71,10 +67,8 @@ class ReplaceMeMixin: data = contents.file.read() return data - def replace_me_with_a_formpost(self, ctx, replace): + def replace_me_with_a_formpost(self, req, client, replace): # create a new file, maybe mutable, maybe immutable - req = IRequest(ctx) - client = IClient(ctx) mutable = boolean_of_arg(get_arg(req, "mutable", "false")) if mutable: @@ -95,8 +89,9 @@ class ReplaceMeMixin: return d class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): - def __init__(self, parentnode, name): + def __init__(self, client, parentnode, name): rend.Page.__init__(self) + self.client = client assert parentnode self.parentnode = parentnode self.name = name @@ -111,9 +106,9 @@ class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): raise WebError("Content-Range in PUT not yet supported", http.NOT_IMPLEMENTED) if not t: - return self.replace_me_with_a_child(ctx, replace) + return self.replace_me_with_a_child(req, self.client, replace) if t == "uri": - return self.replace_me_with_a_childcap(ctx, replace) + return self.replace_me_with_a_childcap(req, self.client, replace) raise WebError("PUT to a file: bad t=%s" % t) @@ -127,7 +122,7 @@ class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # or POST /uri/path/file?t=upload, or # POST /uri/path/dir?t=upload&name=foo . All have the same # behavior, we just ignore any name= argument - d = self.replace_me_with_a_formpost(ctx, replace) + d = self.replace_me_with_a_formpost(req, self.client, replace) else: # t=mkdir is handled in DirectoryNodeHandler._POST_mkdir, so # there are no other t= values left to be handled by the @@ -141,8 +136,9 @@ class PlaceHolderNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): - def __init__(self, node, parentnode=None, name=None): + def __init__(self, client, node, parentnode=None, name=None): rend.Page.__init__(self) + self.client = client assert node self.node = node self.parentnode = parentnode @@ -210,19 +206,19 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): replace = boolean_of_arg(get_arg(req, "replace", "true")) if not t: if self.node.is_mutable(): - return self.replace_my_contents(ctx) + return self.replace_my_contents(req) if not replace: # this is the early trap: if someone else modifies the # directory while we're uploading, the add_file(overwrite=) # call in replace_me_with_a_child will do the late trap. raise ExistingChildError() assert self.parentnode and self.name - return self.replace_me_with_a_child(ctx, replace) + return self.replace_me_with_a_child(req, self.client, replace) if t == "uri": if not replace: raise ExistingChildError() assert self.parentnode and self.name - return self.replace_me_with_a_childcap(ctx, replace) + return self.replace_me_with_a_childcap(req, self.client, replace) raise WebError("PUT to a file: bad t=%s" % t) @@ -239,12 +235,12 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # POST /uri/path/dir?t=upload&name=foo . All have the same # behavior, we just ignore any name= argument if self.node.is_mutable(): - d = self.replace_my_contents_with_a_formpost(ctx) + d = self.replace_my_contents_with_a_formpost(req) else: if not replace: raise ExistingChildError() assert self.parentnode and self.name - d = self.replace_me_with_a_formpost(ctx, replace) + d = self.replace_me_with_a_formpost(req, self.client, replace) else: raise WebError("POST to file: bad t=%s" % t) @@ -258,13 +254,13 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): repair = boolean_of_arg(get_arg(req, "repair", "false")) add_lease = boolean_of_arg(get_arg(req, "add-lease", "false")) if isinstance(self.node, LiteralFileNode): - return defer.succeed(LiteralCheckResults()) + return defer.succeed(LiteralCheckResults(self.client)) if repair: d = self.node.check_and_repair(Monitor(), verify, add_lease) - d.addCallback(lambda res: CheckAndRepairResults(res)) + d.addCallback(lambda res: CheckAndRepairResults(self.client, res)) else: d = self.node.check(Monitor(), verify, add_lease) - d.addCallback(lambda res: CheckResults(res)) + d.addCallback(lambda res: CheckResults(self.client, res)) return d def render_DELETE(self, ctx): @@ -273,18 +269,16 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): d.addCallback(lambda res: self.node.get_uri()) return d - def replace_my_contents(self, ctx): - req = IRequest(ctx) + def replace_my_contents(self, req): req.content.seek(0) new_contents = req.content.read() d = self.node.overwrite(new_contents) d.addCallback(lambda res: self.node.get_uri()) return d - def replace_my_contents_with_a_formpost(self, ctx): + def replace_my_contents_with_a_formpost(self, req): # we have a mutable file. Get the data from the formpost, and replace # the mutable file's contents with it. - req = IRequest(ctx) new_contents = self._read_data_from_formpost(req) d = self.node.overwrite(new_contents) d.addCallback(lambda res: self.node.get_uri()) @@ -449,4 +443,4 @@ def FileReadOnlyURI(ctx, filenode): class FileNodeDownloadHandler(FileNodeHandler): def childFactory(self, ctx, name): - return FileNodeDownloadHandler(self.node, name=name) + return FileNodeDownloadHandler(self.client, self.node, name=name) diff --git a/src/allmydata/web/helper.xhtml b/src/allmydata/web/helper.xhtml index bea58017..f5c9e298 100644 --- a/src/allmydata/web/helper.xhtml +++ b/src/allmydata/web/helper.xhtml @@ -11,7 +11,7 @@

Helper Status

Immutable Uploads

-