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
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):
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):
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"
_all_publish_statuses = [publish.PublishStatus()]
_all_retrieve_statuses = [retrieve.RetrieveStatus()]
convergence = "some random string"
+ stats_provider = FakeStatsProvider()
def connected_to_introducer(self):
return False
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
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
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))
def _render_results(self, ctx, cr):
assert ICheckResults(cr)
- c = IClient(ctx)
+ c = self.client
data = cr.get_data()
r = []
def add(name, value):
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)
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")
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")[
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")
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")
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 ""
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):
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)
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]
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))
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):
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)
from allmydata.interfaces import ExistingChildError, NoSuchChildError, \
FileTooLargeError, NotEnoughSharesError
-class IClient(Interface):
- pass
class IOpHandleTable(Interface):
pass
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
"""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
# 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"
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"
# 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()
"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
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()
# 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
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
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):
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):
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):
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):
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])
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()
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"
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):
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
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)
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())
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:
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
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)
# 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
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
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)
# 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)
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):
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())
class FileNodeDownloadHandler(FileNodeHandler):
def childFactory(self, ctx, name):
- return FileNodeDownloadHandler(self.node, name=name)
+ return FileNodeDownloadHandler(self.client, self.node, name=name)
<h1>Helper Status</h1>
<h2>Immutable Uploads</h2>
-<ul>
+<ul n:data="helper_stats">
<li>Active: <span n:render="active_uploads" /></li>
<li>--</li>
<li>Bytes Fetched: <span n:render="upload_bytes_fetched" /></li>
import simplejson
from allmydata import get_package_versions_string
from allmydata.util import idlib
-from common import getxmlfile, get_arg, IClient
+from common import getxmlfile, get_arg
class IntroducerRoot(rend.Page):
child_operations = None
+ def __init__(self, introducer_node):
+ self.introducer_node = introducer_node
+ self.introducer_service = introducer_node.getServiceNamed("introducer")
+ rend.Page.__init__(self, introducer_node)
+
def renderHTTP(self, ctx):
t = get_arg(inevow.IRequest(ctx), "t")
if t == "json":
return rend.Page.renderHTTP(self, ctx)
def render_JSON(self, ctx):
- i = IClient(ctx).getServiceNamed("introducer")
res = {}
- clients = i.get_subscribers()
+ clients = self.introducer_service.get_subscribers()
subscription_summary = dict([ (name, len(clients[name]))
for name in clients ])
res["subscription_summary"] = subscription_summary
announcement_summary = {}
service_hosts = {}
- for (ann,when) in i.get_announcements().values():
+ for (ann,when) in self.introducer_service.get_announcements().values():
(furl, service_name, ri_name, nickname, ver, oldest) = ann
if service_name not in announcement_summary:
announcement_summary[service_name] = 0
def data_import_path(self, ctx, data):
return str(allmydata)
def data_my_nodeid(self, ctx, data):
- return idlib.nodeid_b2a(IClient(ctx).nodeid)
+ return idlib.nodeid_b2a(self.introducer_node.nodeid)
def render_announcement_summary(self, ctx, data):
- i = IClient(ctx).getServiceNamed("introducer")
services = {}
- for (ann,when) in i.get_announcements().values():
+ for (ann,when) in self.introducer_service.get_announcements().values():
(furl, service_name, ri_name, nickname, ver, oldest) = ann
if service_name not in services:
services[service_name] = 0
for service_name in service_names])
def render_client_summary(self, ctx, data):
- i = IClient(ctx).getServiceNamed("introducer")
- clients = i.get_subscribers()
+ clients = self.introducer_service.get_subscribers()
service_names = clients.keys()
service_names.sort()
return ", ".join(["%s: %d" % (service_name, len(clients[service_name]))
for service_name in service_names])
def data_services(self, ctx, data):
- i = IClient(ctx).getServiceNamed("introducer")
+ introsvc = self.introducer_service
ann = [(since,a)
- for (a,since) in i.get_announcements().values()
+ for (a,since) in introsvc.get_announcements().values()
if a[1] != "stub_client"]
ann.sort(lambda a,b: cmp( (a[1][1], a), (b[1][1], b) ) )
return ann
return ctx.tag
def data_subscribers(self, ctx, data):
- i = IClient(ctx).getServiceNamed("introducer")
# use the "stub_client" announcements to get information per nodeid
clients = {}
- for (ann,when) in i.get_announcements().values():
+ for (ann,when) in self.introducer_service.get_announcements().values():
if ann[1] != "stub_client":
continue
(furl, service_name, ri_name, nickname, ver, oldest) = ann
# then we actually provide information per subscriber
s = []
- for service_name, subscribers in i.get_subscribers().items():
+ introsvc = self.introducer_service
+ for service_name, subscribers in introsvc.get_subscribers().items():
for (rref, timestamp) in subscribers.items():
sr = rref.getSturdyRef()
nodeid = sr.tubID
from allmydata.util import idlib, log
from allmydata.interfaces import IFileNode
from allmydata.web import filenode, directory, unlinked, status, operations
-from allmydata.web import reliability
-from allmydata.web.common import abbreviate_size, IClient, \
- getxmlfile, WebError, get_arg, RenderMixin
+from allmydata.web import reliability, storage
+from allmydata.web.common import abbreviate_size, getxmlfile, WebError, \
+ get_arg, RenderMixin
class URIHandler(RenderMixin, rend.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)
+ self.client = client
+
def render_GET(self, ctx):
req = IRequest(ctx)
uri = get_arg(req, "uri", None)
if t == "":
mutable = bool(get_arg(req, "mutable", "").strip())
if mutable:
- return unlinked.PUTUnlinkedSSK(ctx)
+ return unlinked.PUTUnlinkedSSK(req, self.client)
else:
- return unlinked.PUTUnlinkedCHK(ctx)
+ return unlinked.PUTUnlinkedCHK(req, self.client)
if t == "mkdir":
- return unlinked.PUTUnlinkedCreateDirectory(ctx)
+ return unlinked.PUTUnlinkedCreateDirectory(req, self.client)
errmsg = ("/uri accepts only PUT, PUT?t=mkdir, POST?t=upload, "
"and POST?t=mkdir")
raise WebError(errmsg, http.BAD_REQUEST)
if t in ("", "upload"):
mutable = bool(get_arg(req, "mutable", "").strip())
if mutable:
- return unlinked.POSTUnlinkedSSK(ctx)
+ return unlinked.POSTUnlinkedSSK(req, self.client)
else:
- return unlinked.POSTUnlinkedCHK(ctx)
+ return unlinked.POSTUnlinkedCHK(req, self.client)
if t == "mkdir":
- return unlinked.POSTUnlinkedCreateDirectory(ctx)
+ return unlinked.POSTUnlinkedCreateDirectory(req, self.client)
errmsg = ("/uri accepts only PUT, PUT?t=mkdir, POST?t=upload, "
"and POST?t=mkdir")
raise WebError(errmsg, http.BAD_REQUEST)
def childFactory(self, ctx, name):
# 'name' is expected to be a URI
- client = IClient(ctx)
try:
- node = client.create_node_from_uri(name)
- return directory.make_handler_for(node)
+ node = self.client.create_node_from_uri(name)
+ return directory.make_handler_for(node, self.client)
except (TypeError, AssertionError):
raise WebError("'%s' is not a valid file- or directory- cap"
% name)
# 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)
+ self.client = client
+
def childFactory(self, ctx, name):
req = IRequest(ctx)
if req.method not in ("GET", "HEAD"):
raise WebError("/file can only be used with GET or HEAD")
# 'name' must be a file URI
- client = IClient(ctx)
try:
- node = client.create_node_from_uri(name)
+ node = self.client.create_node_from_uri(name)
except (TypeError, AssertionError):
raise WebError("'%s' is not a valid file- or directory- cap"
% name)
if not IFileNode.providedBy(node):
raise WebError("'%s' is not a file-cap" % name)
- return filenode.FileNodeDownloadHandler(node)
+ return filenode.FileNodeDownloadHandler(self.client, node)
def renderHTTP(self, ctx):
raise WebError("/file must be followed by a file-cap and a name",
addSlash = True
docFactory = getxmlfile("welcome.xhtml")
- def __init__(self, original=None):
- rend.Page.__init__(self, original)
+ def __init__(self, client):
+ rend.Page.__init__(self, client)
+ self.client = client
self.child_operations = operations.OphandleTable()
- child_uri = URIHandler()
- child_cap = URIHandler()
- child_file = FileHandler()
- child_named = FileHandler()
+ self.child_uri = URIHandler(client)
+ self.child_cap = URIHandler(client)
+
+ self.child_file = FileHandler(client)
+ self.child_named = FileHandler(client)
+ self.child_status = status.Status(client) # TODO: use client.history
+ self.child_statistics = status.Statistics(client.stats_provider)
+
+ def child_helper_status(self, ctx):
+ # the Helper isn't attached until after the Tub starts, so this child
+ # needs to created on each request
+ try:
+ helper = self.client.getServiceNamed("helper")
+ except KeyError:
+ helper = None
+ return status.HelperStatus(helper)
child_webform_css = webform.defaultCSS
child_tahoe_css = nevow_File(resource_filename('allmydata.web', 'tahoe.css'))
child_reliability = reliability.ReliabilityTool()
else:
child_reliability = NoReliability()
- child_status = status.Status()
- child_helper_status = status.HelperStatus()
- child_statistics = status.Statistics()
child_report_incident = IncidentReporter()
def data_import_path(self, ctx, data):
return str(allmydata)
def data_my_nodeid(self, ctx, data):
- return idlib.nodeid_b2a(IClient(ctx).nodeid)
+ return idlib.nodeid_b2a(self.client.nodeid)
def data_my_nickname(self, ctx, data):
- return IClient(ctx).nickname
+ return self.client.nickname
def render_services(self, ctx, data):
ul = T.ul()
- client = IClient(ctx)
try:
- ss = client.getServiceNamed("storage")
+ ss = self.client.getServiceNamed("storage")
allocated_s = abbreviate_size(ss.allocated_size())
allocated = "about %s allocated" % allocated_s
reserved = "%s reserved" % abbreviate_size(ss.reserved_space)
ul[T.li["Not running storage server"]]
try:
- h = client.getServiceNamed("helper")
+ h = self.client.getServiceNamed("helper")
stats = h.get_stats()
active_uploads = stats["chk_upload_helper.active_uploads"]
ul[T.li["Helper: %d active uploads" % (active_uploads,)]]
return ctx.tag[ul]
def data_introducer_furl(self, ctx, data):
- return IClient(ctx).introducer_furl
+ return self.client.introducer_furl
def data_connected_to_introducer(self, ctx, data):
- if IClient(ctx).connected_to_introducer():
+ if self.client.connected_to_introducer():
return "yes"
return "no"
def data_helper_furl(self, ctx, data):
try:
- uploader = IClient(ctx).getServiceNamed("uploader")
+ uploader = self.client.getServiceNamed("uploader")
except KeyError:
return None
furl, connected = uploader.get_helper_info()
return furl
def data_connected_to_helper(self, ctx, data):
try:
- uploader = IClient(ctx).getServiceNamed("uploader")
+ uploader = self.client.getServiceNamed("uploader")
except KeyError:
return "no" # we don't even have an Uploader
furl, connected = uploader.get_helper_info()
return "no"
def data_known_storage_servers(self, ctx, data):
- ic = IClient(ctx).introducer_client
+ ic = self.client.introducer_client
servers = [c
for c in ic.get_all_connectors().values()
if c.service_name == "storage"]
return len(servers)
def data_connected_storage_servers(self, ctx, data):
- ic = IClient(ctx).introducer_client
+ ic = self.client.introducer_client
return len(ic.get_all_connections_for("storage"))
def data_services(self, ctx, data):
- ic = IClient(ctx).introducer_client
+ ic = self.client.introducer_client
c = [ (service_name, nodeid, rsc)
for (nodeid, service_name), rsc
in ic.get_all_connectors().items() ]
ctx.fillSlots("nickname", rsc.nickname)
if rsc.rref:
rhost = rsc.remote_host
- if nodeid == IClient(ctx).nodeid:
+ if nodeid == self.client.nodeid:
rhost_s = "(loopback)"
elif isinstance(rhost, address.IPv4Address):
rhost_s = "%s:%d" % (rhost.host, rhost.port)
<link href="/webform_css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
- <body>
+ <body n:data="get_stats">
<h1>Node Statistics</h1>
from twisted.internet import defer
from nevow import rend, inevow, tags as T
from allmydata.util import base32, idlib
-from allmydata.web.common import IClient, getxmlfile, abbreviate_time, \
- abbreviate_rate, abbreviate_size, get_arg
+from allmydata.web.common import getxmlfile, get_arg, \
+ abbreviate_time, abbreviate_rate, abbreviate_size
from allmydata.interfaces import IUploadStatus, IDownloadStatus, \
IPublishStatus, IRetrieveStatus, IServermapUpdaterStatus
docFactory = getxmlfile("status.xhtml")
addSlash = True
+ def __init__(self, client):
+ rend.Page.__init__(self, client)
+ self.client = client
+
def renderHTTP(self, ctx):
- t = get_arg(inevow.IRequest(ctx), "t")
+ req = inevow.IRequest(ctx)
+ t = get_arg(req, "t")
if t == "json":
- return self.json(ctx)
+ return self.json(req)
return rend.Page.renderHTTP(self, ctx)
- def json(self, ctx):
- inevow.IRequest(ctx).setHeader("content-type", "text/plain")
- client = IClient(ctx)
+ def json(self, req):
+ req.setHeader("content-type", "text/plain")
data = {}
data["active"] = active = []
- for s in self.data_active_operations(ctx, None):
+ for s in self._get_active_operations():
si_s = base32.b2a_or_none(s.get_storage_index())
size = s.get_size()
status = s.get_status()
return simplejson.dumps(data, indent=1) + "\n"
- def _get_all_statuses(self, client):
- return itertools.chain(client.list_all_upload_statuses(),
- client.list_all_download_statuses(),
- client.list_all_mapupdate_statuses(),
- client.list_all_publish_statuses(),
- client.list_all_retrieve_statuses(),
- client.list_all_helper_statuses(),
+ def _get_all_statuses(self):
+ c = self.client
+ return itertools.chain(c.list_all_upload_statuses(),
+ c.list_all_download_statuses(),
+ c.list_all_mapupdate_statuses(),
+ c.list_all_publish_statuses(),
+ c.list_all_retrieve_statuses(),
+ c.list_all_helper_statuses(),
)
def data_active_operations(self, ctx, data):
- client = IClient(ctx)
+ return self._get_active_operations()
+
+ def _get_active_operations(self):
active = [s
- for s in self._get_all_statuses(client)
+ for s in self._get_all_statuses()
if s.get_active()]
return active
def data_recent_operations(self, ctx, data):
- client = IClient(ctx)
+ return self._get_recent_operations()
+
+ def _get_recent_operations(self):
recent = [s
- for s in self._get_all_statuses(client)
+ for s in self._get_all_statuses()
if not s.get_active()]
recent.sort(lambda a,b: cmp(a.get_started(), b.get_started()))
recent.reverse()
return ctx.tag
def childFactory(self, ctx, name):
- client = IClient(ctx)
+ client = self.client
stype,count_s = name.split("-")
count = int(count_s)
if stype == "up":
class HelperStatus(rend.Page):
docFactory = getxmlfile("helper.xhtml")
+ def __init__(self, helper):
+ rend.Page.__init__(self, helper)
+ self.helper = helper
+
def renderHTTP(self, ctx):
- t = get_arg(inevow.IRequest(ctx), "t")
+ req = inevow.IRequest(ctx)
+ t = get_arg(req, "t")
if t == "json":
- return self.render_JSON(ctx)
- # is there a better way to provide 'data' to all rendering methods?
- helper = IClient(ctx).getServiceNamed("helper")
- self.original = helper.get_stats()
+ return self.render_JSON(req)
return rend.Page.renderHTTP(self, ctx)
- def render_JSON(self, ctx):
- inevow.IRequest(ctx).setHeader("content-type", "text/plain")
- try:
- h = IClient(ctx).getServiceNamed("helper")
- except KeyError:
- return simplejson.dumps({}) + "\n"
+ def data_helper_stats(self, ctx, data):
+ return self.helper.get_stats()
- stats = h.get_stats()
- return simplejson.dumps(stats, indent=1) + "\n"
+ def render_JSON(self, req):
+ req.setHeader("content-type", "text/plain")
+ if self.helper:
+ stats = self.helper.get_stats()
+ return simplejson.dumps(stats, indent=1) + "\n"
+ return simplejson.dumps({}) + "\n"
def render_active_uploads(self, ctx, data):
return data["chk_upload_helper.active_uploads"]
class Statistics(rend.Page):
docFactory = getxmlfile("statistics.xhtml")
+ def __init__(self, provider):
+ rend.Page.__init__(self, provider)
+ self.provider = provider
+
def renderHTTP(self, ctx):
- provider = IClient(ctx).stats_provider
- stats = {'stats': {}, 'counters': {}}
- if provider:
- stats = provider.get_stats()
- t = get_arg(inevow.IRequest(ctx), "t")
+ req = inevow.IRequest(ctx)
+ t = get_arg(req, "t")
if t == "json":
- inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+ stats = self.provider.get_stats()
+ req.setHeader("content-type", "text/plain")
return simplejson.dumps(stats, indent=1) + "\n"
- # is there a better way to provide 'data' to all rendering methods?
- self.original = stats
return rend.Page.renderHTTP(self, ctx)
+ def data_get_stats(self, ctx, data):
+ return self.provider.get_stats()
+
def render_load_average(self, ctx, data):
return str(data["stats"].get("load_monitor.avg_load"))
from twisted.web import http
from twisted.internet import defer
from nevow import rend, url, tags as T
-from nevow.inevow import IRequest
from allmydata.immutable.upload import FileHandle
-from allmydata.web.common import IClient, getxmlfile, get_arg, boolean_of_arg
+from allmydata.web.common import getxmlfile, get_arg, boolean_of_arg
from allmydata.web import status
-def PUTUnlinkedCHK(ctx):
- req = IRequest(ctx)
+def PUTUnlinkedCHK(req, client):
# "PUT /uri", to create an unlinked file.
- client = IClient(ctx)
uploadable = FileHandle(req.content, client.convergence)
d = client.upload(uploadable)
d.addCallback(lambda results: results.uri)
# that fires with the URI of the new file
return d
-def PUTUnlinkedSSK(ctx):
- req = IRequest(ctx)
+def PUTUnlinkedSSK(req, client):
# SDMF: files are small, and we can only upload data
req.content.seek(0)
data = req.content.read()
- d = IClient(ctx).create_mutable_file(data)
+ d = client.create_mutable_file(data)
d.addCallback(lambda n: n.get_uri())
return d
-def PUTUnlinkedCreateDirectory(ctx):
- req = IRequest(ctx)
+def PUTUnlinkedCreateDirectory(req, client):
# "PUT /uri?t=mkdir", to create an unlinked directory.
- d = IClient(ctx).create_empty_dirnode()
+ d = client.create_empty_dirnode()
d.addCallback(lambda dirnode: dirnode.get_uri())
# XXX add redirect_to_result
return d
-def POSTUnlinkedCHK(ctx):
- req = IRequest(ctx)
- client = IClient(ctx)
+def POSTUnlinkedCHK(req, client):
fileobj = req.fields["file"].file
uploadable = FileHandle(fileobj, client.convergence)
d = client.upload(uploadable)
d.addCallback(_done, when_done)
else:
# return the Upload Results page, which includes the URI
- d.addCallback(UploadResultsPage, ctx)
+ d.addCallback(UploadResultsPage)
return d
"""'POST /uri', to create an unlinked file."""
docFactory = getxmlfile("upload-results.xhtml")
- def __init__(self, upload_results, ctx):
+ def __init__(self, upload_results):
rend.Page.__init__(self)
self.results = upload_results
["/uri/" + res.uri])
return d
-def POSTUnlinkedSSK(ctx):
- req = IRequest(ctx)
+def POSTUnlinkedSSK(req, client):
# "POST /uri", to create an unlinked file.
# SDMF: files are small, and we can only upload data
contents = req.fields["file"]
contents.file.seek(0)
data = contents.file.read()
- d = IClient(ctx).create_mutable_file(data)
+ d = client.create_mutable_file(data)
d.addCallback(lambda n: n.get_uri())
return d
-def POSTUnlinkedCreateDirectory(ctx):
- req = IRequest(ctx)
+def POSTUnlinkedCreateDirectory(req, client):
# "POST /uri?t=mkdir", to create an unlinked directory.
- d = IClient(ctx).create_empty_dirnode()
+ d = client.create_empty_dirnode()
redirect = get_arg(req, "redirect_to_result", "false")
if boolean_of_arg(redirect):
def _then_redir(res):
from allmydata.util import log
from allmydata.web import introweb, root
-from allmydata.web.common import IClient, IOpHandleTable, MyExceptionHandler
+from allmydata.web.common import IOpHandleTable, MyExceptionHandler
# we must override twisted.web.http.Request.requestReceived with a version
# that doesn't use cgi.parse_multipart() . Since we actually use Nevow, we
class WebishServer(service.MultiService):
name = "webish"
- root_class = root.Root
- def __init__(self, webport, nodeurl_path=None, staticdir=None):
+ def __init__(self, client, webport, nodeurl_path=None, staticdir=None):
service.MultiService.__init__(self)
- self.webport = webport
- self.root = self.root_class()
- self.site = site = appserver.NevowSite(self.root)
- self.site.requestFactory = MyRequest
+ # the 'data' argument to all render() methods default to the Client
+ self.root = root.Root(client)
+ self.buildServer(webport, nodeurl_path, staticdir)
if self.root.child_operations:
self.site.remember(self.root.child_operations, IOpHandleTable)
self.root.child_operations.setServiceParent(self)
+
+ def buildServer(self, webport, nodeurl_path, staticdir):
+ self.webport = webport
+ self.site = site = appserver.NevowSite(self.root)
+ self.site.requestFactory = MyRequest
+ self.site.remember(MyExceptionHandler(), inevow.ICanHandleException)
if staticdir:
self.root.putChild("static", static.File(staticdir))
s = strports.service(webport, site)
def startService(self):
service.MultiService.startService(self)
- # to make various services available to render_* methods, we stash a
- # reference to the client on the NevowSite. This will be available by
- # adapting the 'context' argument to a special marker interface named
- # IClient.
- self.site.remember(self.parent, IClient)
- # I thought you could do the same with an existing interface, but
- # apparently 'ISite' does not exist
- #self.site._client = self.parent
- self.site.remember(MyExceptionHandler(), inevow.ICanHandleException)
self._started.callback(None)
def _write_nodeurl_file(self, junk, nodeurl_path):
f.close()
class IntroducerWebishServer(WebishServer):
- root_class = introweb.IntroducerRoot
+ def __init__(self, introducer, webport, nodeurl_path=None, staticdir=None):
+ service.MultiService.__init__(self)
+ self.root = introweb.IntroducerRoot(introducer)
+ self.buildServer(webport, nodeurl_path, staticdir)
+