2006-12-04 11:06:09 +00:00
|
|
|
|
2006-12-07 19:47:40 +00:00
|
|
|
from twisted.application import service, strports
|
2007-07-03 20:47:37 +00:00
|
|
|
from twisted.web import static, resource, server, html, http
|
2006-12-04 12:15:36 +00:00
|
|
|
from twisted.python import util, log
|
|
|
|
from nevow import inevow, rend, loaders, appserver, url, tags as T
|
2007-06-15 08:32:20 +00:00
|
|
|
from nevow.static import File as nevow_File # TODO: merge with static.File?
|
2006-12-04 11:06:09 +00:00
|
|
|
from allmydata.util import idlib
|
2007-05-04 20:07:32 +00:00
|
|
|
from allmydata.uri import unpack_uri
|
2007-06-25 20:23:51 +00:00
|
|
|
from allmydata.interfaces import IDownloadTarget, IDirectoryNode, IFileNode
|
2007-06-27 00:16:58 +00:00
|
|
|
from allmydata.dirnode import FileNode
|
2007-06-15 07:37:32 +00:00
|
|
|
from allmydata import upload
|
2006-12-05 02:54:35 +00:00
|
|
|
from zope.interface import implements, Interface
|
2006-12-04 11:06:09 +00:00
|
|
|
import urllib
|
2006-12-04 12:15:36 +00:00
|
|
|
from formless import annotate, webform
|
2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
def getxmlfile(name):
|
|
|
|
return loaders.xmlfile(util.sibpath(__file__, "web/%s" % name))
|
|
|
|
|
2006-12-05 02:54:35 +00:00
|
|
|
class IClient(Interface):
|
|
|
|
pass
|
|
|
|
|
2006-12-07 21:48:37 +00:00
|
|
|
def get_downloader_service(ctx):
|
|
|
|
return IClient(ctx).getServiceNamed("downloader")
|
|
|
|
def get_uploader_service(ctx):
|
|
|
|
return IClient(ctx).getServiceNamed("uploader")
|
2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
class Welcome(rend.Page):
|
|
|
|
addSlash = True
|
|
|
|
docFactory = getxmlfile("welcome.xhtml")
|
|
|
|
|
2007-06-11 17:51:11 +00:00
|
|
|
def data_version(self, ctx, data):
|
|
|
|
v = IClient(ctx).get_versions()
|
|
|
|
return "tahoe: %s, zfec: %s, foolscap: %s, twisted: %s" % \
|
|
|
|
(v['allmydata'], v['zfec'], v['foolscap'], v['twisted'])
|
|
|
|
|
2007-03-29 21:31:55 +00:00
|
|
|
def data_my_nodeid(self, ctx, data):
|
|
|
|
return idlib.b2a(IClient(ctx).nodeid)
|
2007-05-22 21:08:30 +00:00
|
|
|
def data_introducer_furl(self, ctx, data):
|
2007-03-27 23:12:11 +00:00
|
|
|
return IClient(ctx).introducer_furl
|
2007-04-20 00:30:21 +00:00
|
|
|
def data_connected_to_introducer(self, ctx, data):
|
2007-06-10 04:03:57 +00:00
|
|
|
if IClient(ctx).connected_to_introducer():
|
|
|
|
return "yes"
|
|
|
|
return "no"
|
|
|
|
def data_connected_to_vdrive(self, ctx, data):
|
2007-06-28 00:11:06 +00:00
|
|
|
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
2006-12-05 19:51:32 +00:00
|
|
|
return "yes"
|
|
|
|
return "no"
|
2006-12-05 02:54:35 +00:00
|
|
|
def data_num_peers(self, ctx, data):
|
|
|
|
#client = inevow.ISite(ctx)._client
|
|
|
|
client = IClient(ctx)
|
2007-03-28 00:44:49 +00:00
|
|
|
return len(list(client.get_all_peerids()))
|
2007-01-17 04:01:18 +00:00
|
|
|
|
2006-12-05 02:54:35 +00:00
|
|
|
def data_peers(self, ctx, data):
|
2007-01-17 04:01:18 +00:00
|
|
|
d = []
|
|
|
|
client = IClient(ctx)
|
2007-03-27 23:12:11 +00:00
|
|
|
for nodeid in sorted(client.get_all_peerids()):
|
|
|
|
row = (idlib.b2a(nodeid),)
|
2007-01-17 04:01:18 +00:00
|
|
|
d.append(row)
|
|
|
|
return d
|
|
|
|
|
2006-12-05 02:54:35 +00:00
|
|
|
def render_row(self, ctx, data):
|
2007-03-27 23:12:11 +00:00
|
|
|
(nodeid_a,) = data
|
2007-01-17 04:01:18 +00:00
|
|
|
ctx.fillSlots("peerid", nodeid_a)
|
2006-12-05 02:54:35 +00:00
|
|
|
return ctx.tag
|
2006-12-04 19:03:29 +00:00
|
|
|
|
2007-06-15 08:33:24 +00:00
|
|
|
def render_global_vdrive(self, ctx, data):
|
2007-06-28 00:11:06 +00:00
|
|
|
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
2007-06-10 04:03:57 +00:00
|
|
|
return T.p["To view the global shared filestore, ",
|
2007-06-15 08:33:24 +00:00
|
|
|
T.a(href="../global_vdrive")["Click Here!"],
|
|
|
|
]
|
|
|
|
return T.p["vdrive.furl not specified (or vdrive server not "
|
|
|
|
"responding), no vdrive available."]
|
|
|
|
|
2007-06-29 02:07:52 +00:00
|
|
|
def render_private_vdrive(self, ctx, data):
|
2007-06-28 00:11:06 +00:00
|
|
|
if IClient(ctx).getServiceNamed("vdrive").have_private_root():
|
2007-06-15 08:33:24 +00:00
|
|
|
return T.p["To view your personal private non-shared filestore, ",
|
2007-06-29 02:07:52 +00:00
|
|
|
T.a(href="../private_vdrive")["Click Here!"],
|
2007-06-10 04:03:57 +00:00
|
|
|
]
|
2007-06-15 08:33:24 +00:00
|
|
|
return T.p["personal vdrive not available."]
|
2007-06-10 04:03:57 +00:00
|
|
|
|
2006-12-07 21:48:37 +00:00
|
|
|
# this is a form where users can download files by URI
|
|
|
|
|
|
|
|
def bind_download(self, ctx):
|
|
|
|
uriarg = annotate.Argument("uri",
|
|
|
|
annotate.String("URI of file to download: "))
|
|
|
|
namearg = annotate.Argument("filename",
|
|
|
|
annotate.String("Filename to download as: "))
|
|
|
|
ctxarg = annotate.Argument("ctx", annotate.Context())
|
|
|
|
meth = annotate.Method(arguments=[uriarg, namearg, ctxarg],
|
|
|
|
label="Download File by URI")
|
|
|
|
# buttons always use value=data.label
|
|
|
|
# MethodBindingRenderer uses value=(data.action or data.label)
|
|
|
|
return annotate.MethodBinding("download", meth, action="Download")
|
|
|
|
|
|
|
|
def download(self, uri, filename, ctx):
|
|
|
|
log.msg("webish downloading URI")
|
|
|
|
target = url.here.sibling("download_uri").add("uri", uri)
|
|
|
|
if filename:
|
|
|
|
target = target.add("filename", filename)
|
|
|
|
return target
|
|
|
|
|
|
|
|
def render_forms(self, ctx, data):
|
|
|
|
return webform.renderForms()
|
|
|
|
|
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
class Directory(rend.Page):
|
|
|
|
addSlash = True
|
|
|
|
docFactory = getxmlfile("directory.xhtml")
|
|
|
|
|
2007-06-15 07:37:32 +00:00
|
|
|
def __init__(self, dirnode, dirname):
|
2006-12-04 11:06:09 +00:00
|
|
|
self._dirnode = dirnode
|
|
|
|
self._dirname = dirname
|
2006-12-05 02:54:35 +00:00
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
def childFactory(self, ctx, name):
|
|
|
|
if name.startswith("freeform"): # ick
|
|
|
|
return None
|
2007-06-27 02:55:21 +00:00
|
|
|
if name == "@manifest": # ick, this time it's my fault
|
|
|
|
return Manifest(self._dirnode, self._dirname)
|
2006-12-04 11:06:09 +00:00
|
|
|
if self._dirname == "/":
|
|
|
|
dirname = "/" + name
|
|
|
|
else:
|
|
|
|
dirname = self._dirname + "/" + name
|
2007-06-15 07:37:32 +00:00
|
|
|
d = self._dirnode.get(name)
|
2006-12-07 21:48:37 +00:00
|
|
|
def _got_child(res):
|
2007-06-25 20:23:51 +00:00
|
|
|
if IFileNode.providedBy(res):
|
2006-12-07 21:48:37 +00:00
|
|
|
dl = get_downloader_service(ctx)
|
|
|
|
return Downloader(dl, name, res)
|
2007-06-25 20:23:51 +00:00
|
|
|
elif IDirectoryNode.providedBy(res):
|
2007-06-15 07:37:32 +00:00
|
|
|
return Directory(res, dirname)
|
2007-06-15 03:14:34 +00:00
|
|
|
else:
|
|
|
|
raise RuntimeError("what is this %s" % res)
|
2006-12-07 21:48:37 +00:00
|
|
|
d.addCallback(_got_child)
|
2006-12-04 11:06:09 +00:00
|
|
|
return d
|
|
|
|
|
|
|
|
def render_title(self, ctx, data):
|
2007-06-29 18:17:18 +00:00
|
|
|
return ctx.tag["Directory '%s':" % self._dirname]
|
2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
def render_header(self, ctx, data):
|
2007-06-29 18:17:18 +00:00
|
|
|
parent_directories = self._dirname.split("/")
|
|
|
|
num_dirs = len(parent_directories)
|
|
|
|
|
|
|
|
header = ["Directory '"]
|
|
|
|
for i,d in enumerate(parent_directories):
|
|
|
|
if d == "":
|
|
|
|
link = "/".join([".."] * (num_dirs - i))
|
|
|
|
header.append(T.a(href=link)["/"])
|
|
|
|
else:
|
|
|
|
if i == num_dirs-1:
|
|
|
|
link = "."
|
|
|
|
else:
|
|
|
|
link = "/".join([".."] * (num_dirs - i - 1))
|
|
|
|
header.append(T.a(href=link)[d])
|
|
|
|
if i < num_dirs - 1:
|
|
|
|
header.append("/")
|
|
|
|
header.append("'")
|
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
if not self._dirnode.is_mutable():
|
2007-06-29 18:17:18 +00:00
|
|
|
header.append(" (readonly)")
|
|
|
|
header.append(":")
|
|
|
|
return ctx.tag[header]
|
2006-12-04 11:06:09 +00:00
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
def data_share_uri(self, ctx, data):
|
|
|
|
return self._dirnode.get_uri()
|
|
|
|
def data_share_readonly_uri(self, ctx, data):
|
|
|
|
return self._dirnode.get_immutable_uri()
|
2007-06-15 09:31:23 +00:00
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
def data_children(self, ctx, data):
|
2007-06-15 07:37:32 +00:00
|
|
|
d = self._dirnode.list()
|
2007-06-25 20:23:51 +00:00
|
|
|
d.addCallback(lambda dict: sorted(dict.items()))
|
2006-12-04 11:06:09 +00:00
|
|
|
return d
|
|
|
|
|
|
|
|
def render_row(self, ctx, data):
|
|
|
|
name, target = data
|
2007-06-25 20:23:51 +00:00
|
|
|
|
|
|
|
if self._dirnode.is_mutable():
|
|
|
|
# this creates a button which will cause our child__delete method
|
|
|
|
# to be invoked, which deletes the file and then redirects the
|
|
|
|
# browser back to this directory
|
|
|
|
del_url = url.here.child("_delete")
|
|
|
|
#del_url = del_url.add("uri", target.uri)
|
|
|
|
del_url = del_url.add("name", name)
|
|
|
|
delete = T.form(action=del_url, method="post")[
|
|
|
|
T.input(type='submit', value='del', name="del"),
|
|
|
|
]
|
|
|
|
else:
|
|
|
|
delete = "-"
|
|
|
|
ctx.fillSlots("delete", delete)
|
|
|
|
|
|
|
|
if IFileNode.providedBy(target):
|
2006-12-04 11:06:09 +00:00
|
|
|
# file
|
2006-12-07 21:48:37 +00:00
|
|
|
dlurl = urllib.quote(name)
|
|
|
|
ctx.fillSlots("filename",
|
|
|
|
T.a(href=dlurl)[html.escape(name)])
|
2006-12-04 11:06:09 +00:00
|
|
|
ctx.fillSlots("type", "FILE")
|
2007-06-15 07:37:32 +00:00
|
|
|
uri = target.uri
|
2006-12-07 21:48:37 +00:00
|
|
|
dl_uri_url = url.root.child("download_uri").child(uri)
|
|
|
|
# add a filename= query argument to give it a Content-Type
|
|
|
|
dl_uri_url = dl_uri_url.add("filename", name)
|
2007-01-17 02:55:53 +00:00
|
|
|
ctx.fillSlots("uri", T.a(href=dl_uri_url)[html.escape(uri)])
|
2006-12-05 02:27:38 +00:00
|
|
|
|
2007-05-04 20:07:32 +00:00
|
|
|
#extract and display file size
|
2007-05-23 18:18:49 +00:00
|
|
|
ctx.fillSlots("size", unpack_uri(uri)['size'])
|
2007-05-04 20:07:32 +00:00
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
elif IDirectoryNode.providedBy(target):
|
2006-12-04 11:06:09 +00:00
|
|
|
# directory
|
2006-12-07 21:48:37 +00:00
|
|
|
subdir_url = urllib.quote(name)
|
|
|
|
ctx.fillSlots("filename",
|
|
|
|
T.a(href=subdir_url)[html.escape(name)])
|
2007-06-26 19:37:00 +00:00
|
|
|
if target.is_mutable():
|
|
|
|
dirtype = "DIR"
|
|
|
|
else:
|
|
|
|
dirtype = "DIR-RO"
|
|
|
|
ctx.fillSlots("type", dirtype)
|
2007-05-04 20:07:32 +00:00
|
|
|
ctx.fillSlots("size", "-")
|
2007-01-17 02:55:53 +00:00
|
|
|
ctx.fillSlots("uri", "-")
|
2007-06-15 07:37:32 +00:00
|
|
|
else:
|
|
|
|
raise RuntimeError("unknown thing %s" % (target,))
|
2006-12-04 11:06:09 +00:00
|
|
|
return ctx.tag
|
|
|
|
|
2006-12-04 12:15:36 +00:00
|
|
|
def render_forms(self, ctx, data):
|
2007-06-25 20:23:51 +00:00
|
|
|
if self._dirnode.is_mutable():
|
|
|
|
return webform.renderForms()
|
|
|
|
return T.div["No upload forms: directory is immutable"]
|
2006-12-04 12:15:36 +00:00
|
|
|
|
2007-05-16 15:40:19 +00:00
|
|
|
def render_results(self, ctx, data):
|
|
|
|
req = inevow.IRequest(ctx)
|
|
|
|
if "results" in req.args:
|
|
|
|
return req.args["results"]
|
|
|
|
else:
|
|
|
|
return ""
|
|
|
|
|
2006-12-05 01:49:24 +00:00
|
|
|
def bind_upload(self, ctx):
|
|
|
|
"""upload1"""
|
|
|
|
# Note: this comment is no longer accurate, as it reflects the older
|
|
|
|
# (apparently deprecated) formless.autocallable /
|
|
|
|
# annotate.TypedInterface approach.
|
|
|
|
|
|
|
|
# Each method gets a box. The string in the autocallable(action=)
|
|
|
|
# argument is put on the border of the box, as well as in the submit
|
|
|
|
# button. The top-most contents of the box are the method's
|
|
|
|
# docstring, if any. Each row contains a string for the argument
|
|
|
|
# followed by the argument's input box. If you do not provide an
|
|
|
|
# action= argument to autocallable, the method name is capitalized
|
|
|
|
# and used instead.
|
|
|
|
up = annotate.FileUpload(label="Choose a file to upload: ",
|
|
|
|
required=True,
|
|
|
|
requiredFailMessage="Do iT!")
|
|
|
|
contentsarg = annotate.Argument("contents", up)
|
|
|
|
|
2007-05-16 15:40:19 +00:00
|
|
|
privateUpload = annotate.Radio(label="Private?", choices=["Yes"])
|
|
|
|
privatearg = annotate.Argument("privateupload", privateUpload)
|
|
|
|
|
2006-12-05 01:49:24 +00:00
|
|
|
ctxarg = annotate.Argument("ctx", annotate.Context())
|
2007-05-16 15:40:19 +00:00
|
|
|
meth = annotate.Method(arguments=[contentsarg, privatearg, ctxarg],
|
2006-12-07 21:48:37 +00:00
|
|
|
label="Upload File to this directory")
|
|
|
|
return annotate.MethodBinding("upload", meth, action="Upload")
|
2006-12-05 01:49:24 +00:00
|
|
|
|
2007-05-16 15:40:19 +00:00
|
|
|
def uploadprivate(self, filename, uri):
|
|
|
|
message = "webish upload complete, filename %s %s" % (filename, uri)
|
|
|
|
log.msg(message)
|
|
|
|
return url.here.add("filename", filename).add("results", message)
|
|
|
|
|
|
|
|
def upload(self, contents, privateupload, ctx):
|
2006-12-04 12:15:36 +00:00
|
|
|
# contents is a cgi.FieldStorage instance
|
|
|
|
log.msg("starting webish upload")
|
|
|
|
|
2006-12-07 21:48:37 +00:00
|
|
|
uploader = get_uploader_service(ctx)
|
2007-06-25 20:23:51 +00:00
|
|
|
uploadable = upload.FileHandle(contents.file)
|
2006-12-04 12:15:36 +00:00
|
|
|
name = contents.filename
|
2007-06-25 20:23:51 +00:00
|
|
|
if privateupload:
|
|
|
|
d = uploader.upload(uploadable)
|
|
|
|
d.addCallback(lambda uri: self.uploadprivate(name, uri))
|
|
|
|
else:
|
|
|
|
d = self._dirnode.add_file(name, uploadable)
|
2006-12-04 12:15:36 +00:00
|
|
|
def _done(res):
|
|
|
|
log.msg("webish upload complete")
|
|
|
|
return res
|
|
|
|
d.addCallback(_done)
|
2007-06-15 03:14:34 +00:00
|
|
|
return d # TODO: huh?
|
2006-12-04 12:15:36 +00:00
|
|
|
return url.here.add("results",
|
|
|
|
"upload of '%s' complete!" % contents.filename)
|
|
|
|
|
2006-12-05 01:49:24 +00:00
|
|
|
def bind_mkdir(self, ctx):
|
|
|
|
"""Make new directory 1"""
|
|
|
|
namearg = annotate.Argument("name",
|
|
|
|
annotate.String("New directory name: "))
|
2006-12-07 21:48:37 +00:00
|
|
|
meth = annotate.Method(arguments=[namearg], label="Make New Subdirectory")
|
|
|
|
return annotate.MethodBinding("mkdir", meth, action="Create Directory")
|
2006-12-05 01:49:24 +00:00
|
|
|
|
2006-12-04 19:03:29 +00:00
|
|
|
def mkdir(self, name):
|
2006-12-05 01:49:24 +00:00
|
|
|
"""mkdir2"""
|
2007-06-15 09:48:19 +00:00
|
|
|
log.msg("making new webish directory: %s" % (name,))
|
2007-06-15 07:37:32 +00:00
|
|
|
d = self._dirnode.create_empty_directory(name)
|
2006-12-04 19:03:29 +00:00
|
|
|
def _done(res):
|
|
|
|
log.msg("webish mkdir complete")
|
|
|
|
return res
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
|
|
|
|
2007-06-15 09:31:23 +00:00
|
|
|
def bind_mount(self, ctx):
|
|
|
|
namearg = annotate.Argument("name",
|
|
|
|
annotate.String("Name to place incoming directory: "))
|
2007-06-25 20:23:51 +00:00
|
|
|
uriarg = annotate.Argument("uri",
|
|
|
|
annotate.String("URI of Shared Directory"))
|
|
|
|
meth = annotate.Method(arguments=[namearg, uriarg],
|
2007-06-15 09:31:23 +00:00
|
|
|
label="Add Shared Directory")
|
|
|
|
return annotate.MethodBinding("mount", meth,
|
|
|
|
action="Mount Shared Directory")
|
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
def mount(self, name, uri):
|
|
|
|
d = self._dirnode.set_uri(name, uri)
|
2007-06-15 09:34:24 +00:00
|
|
|
#d.addCallback(lambda done: url.here.child(name))
|
2007-06-15 09:31:23 +00:00
|
|
|
return d
|
|
|
|
|
2006-12-05 02:27:38 +00:00
|
|
|
def child__delete(self, ctx):
|
|
|
|
# perform the delete, then redirect back to the directory page
|
|
|
|
args = inevow.IRequest(ctx).args
|
2007-06-15 03:14:34 +00:00
|
|
|
name = args["name"][0]
|
2007-06-25 20:23:51 +00:00
|
|
|
d = self._dirnode.delete(name)
|
2007-06-15 09:34:24 +00:00
|
|
|
d.addCallback(lambda done: url.here.up())
|
2006-12-05 02:27:38 +00:00
|
|
|
return d
|
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
class WebDownloadTarget:
|
|
|
|
implements(IDownloadTarget)
|
2007-07-03 20:47:37 +00:00
|
|
|
def __init__(self, req, content_type, content_encoding):
|
2006-12-04 11:06:09 +00:00
|
|
|
self._req = req
|
2007-07-03 20:47:37 +00:00
|
|
|
self._content_type = content_type
|
|
|
|
self._content_encoding = content_encoding
|
|
|
|
self._opened = False
|
|
|
|
|
2007-07-03 22:09:00 +00:00
|
|
|
def open(self, size):
|
2007-07-03 20:47:37 +00:00
|
|
|
self._opened = True
|
|
|
|
self._req.setHeader("content-type", self._content_type)
|
|
|
|
if self._content_encoding:
|
2007-07-03 22:09:00 +00:00
|
|
|
self._req.setHeader("content-encoding", self._content_encoding)
|
|
|
|
self._req.setHeader("content-length", str(size))
|
2007-07-03 20:47:37 +00:00
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
def write(self, data):
|
|
|
|
self._req.write(data)
|
|
|
|
def close(self):
|
|
|
|
self._req.finish()
|
2007-07-03 20:47:37 +00:00
|
|
|
|
2007-07-03 20:18:14 +00:00
|
|
|
def fail(self, why):
|
2007-07-03 20:47:37 +00:00
|
|
|
if self._opened:
|
|
|
|
# The content-type is already set, and the response code
|
|
|
|
# has already been sent, so we can't provide a clean error
|
|
|
|
# indication. We can emit text (which a browser might interpret
|
|
|
|
# as something else), and if we sent a Size header, they might
|
|
|
|
# notice that we've truncated the data. Keep the error message
|
|
|
|
# small to improve the chances of having our error response be
|
|
|
|
# shorter than the intended results.
|
|
|
|
#
|
|
|
|
# We don't have a lot of options, unfortunately.
|
|
|
|
self._req.write("problem during download\n")
|
|
|
|
else:
|
|
|
|
# We haven't written anything yet, so we can provide a sensible
|
|
|
|
# error message.
|
|
|
|
msg = str(why.type)
|
|
|
|
msg.replace("\n", "|")
|
|
|
|
self._req.setResponseCode(http.INTERNAL_SERVER_ERROR, msg)
|
|
|
|
self._req.setHeader("content-type", "text/plain")
|
|
|
|
# TODO: HTML-formatted exception?
|
|
|
|
self._req.write(str(why))
|
2006-12-04 11:06:09 +00:00
|
|
|
self._req.finish()
|
2007-07-03 20:47:37 +00:00
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
def register_canceller(self, cb):
|
|
|
|
pass
|
|
|
|
def finish(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class TypedFile(static.File):
|
|
|
|
# serve data from a named file, but using a Content-Type derived from a
|
|
|
|
# different filename
|
|
|
|
isLeaf = True
|
|
|
|
def __init__(self, path, requested_filename):
|
|
|
|
static.File.__init__(self, path)
|
|
|
|
gte = static.getTypeAndEncoding
|
|
|
|
self.type, self.encoding = gte(requested_filename,
|
|
|
|
self.contentTypes,
|
|
|
|
self.contentEncodings,
|
|
|
|
self.defaultType)
|
|
|
|
|
|
|
|
class Downloader(resource.Resource):
|
2007-06-15 07:37:32 +00:00
|
|
|
def __init__(self, downloader, name, filenode):
|
2006-12-04 11:06:09 +00:00
|
|
|
self._downloader = downloader
|
|
|
|
self._name = name
|
2007-06-25 20:23:51 +00:00
|
|
|
IFileNode(filenode)
|
2007-06-15 07:37:32 +00:00
|
|
|
self._filenode = filenode
|
2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
def render(self, ctx):
|
|
|
|
req = inevow.IRequest(ctx)
|
|
|
|
gte = static.getTypeAndEncoding
|
|
|
|
type, encoding = gte(self._name,
|
|
|
|
static.File.contentTypes,
|
|
|
|
static.File.contentEncodings,
|
|
|
|
defaultType="text/plain")
|
|
|
|
|
2007-07-03 20:47:37 +00:00
|
|
|
d = self._filenode.download(WebDownloadTarget(req, type, encoding))
|
2007-07-03 20:18:14 +00:00
|
|
|
# exceptions during download are handled by the WebDownloadTarget
|
|
|
|
d.addErrback(lambda why: None)
|
2006-12-04 11:06:09 +00:00
|
|
|
return server.NOT_DONE_YET
|
2006-12-04 12:15:36 +00:00
|
|
|
|
2007-06-27 02:55:21 +00:00
|
|
|
class Manifest(rend.Page):
|
|
|
|
docFactory = getxmlfile("manifest.xhtml")
|
|
|
|
def __init__(self, dirnode, dirname):
|
|
|
|
self._dirnode = dirnode
|
|
|
|
self._dirname = dirname
|
|
|
|
|
|
|
|
def render_title(self, ctx):
|
|
|
|
return T.title["Manifest of %s" % self._dirname]
|
|
|
|
|
|
|
|
def render_header(self, ctx):
|
|
|
|
return T.p["Manifest of %s" % self._dirname]
|
|
|
|
|
|
|
|
def data_items(self, ctx, data):
|
|
|
|
return self._dirnode.build_manifest()
|
|
|
|
|
|
|
|
def render_row(self, ctx, refresh_cap):
|
|
|
|
ctx.fillSlots("refresh_capability", refresh_cap)
|
|
|
|
return ctx.tag
|
2006-12-04 12:15:36 +00:00
|
|
|
|
2006-12-07 21:48:37 +00:00
|
|
|
|
|
|
|
class Root(rend.Page):
|
|
|
|
def locateChild(self, ctx, segments):
|
|
|
|
if segments[0] == "download_uri":
|
|
|
|
req = inevow.IRequest(ctx)
|
|
|
|
dl = get_downloader_service(ctx)
|
|
|
|
filename = "unknown_filename"
|
|
|
|
if "filename" in req.args:
|
|
|
|
filename = req.args["filename"][0]
|
|
|
|
if len(segments) > 1:
|
|
|
|
# http://host/download_uri/URIGOESHERE
|
2007-01-17 21:46:02 +00:00
|
|
|
uri = segments[1]
|
2006-12-07 21:48:37 +00:00
|
|
|
elif "uri" in req.args:
|
|
|
|
# http://host/download_uri?uri=URIGOESHERE
|
2007-01-17 21:46:02 +00:00
|
|
|
uri = req.args["uri"][0]
|
2006-12-07 21:48:37 +00:00
|
|
|
else:
|
|
|
|
return rend.NotFound
|
2007-06-15 07:37:32 +00:00
|
|
|
child = Downloader(dl, filename, FileNode(uri, IClient(ctx)))
|
2006-12-07 21:48:37 +00:00
|
|
|
return child, ()
|
|
|
|
return rend.Page.locateChild(self, ctx, segments)
|
|
|
|
|
|
|
|
child_webform_css = webform.defaultCSS
|
2007-06-15 08:32:20 +00:00
|
|
|
child_tahoe_css = nevow_File(util.sibpath(__file__, "web/tahoe.css"))
|
2006-12-07 21:48:37 +00:00
|
|
|
|
|
|
|
child_welcome = Welcome()
|
|
|
|
|
2007-06-28 00:11:06 +00:00
|
|
|
def child_global_vdrive(self, ctx):
|
|
|
|
client = IClient(ctx)
|
|
|
|
vdrive = client.getServiceNamed("vdrive")
|
|
|
|
if vdrive.have_public_root():
|
|
|
|
d = vdrive.get_public_root()
|
|
|
|
d.addCallback(lambda dirnode: Directory(dirnode, "/"))
|
|
|
|
return d
|
|
|
|
else:
|
|
|
|
return static.Data("sorry, still initializing", "text/plain")
|
|
|
|
|
|
|
|
def child_private_vdrive(self, ctx):
|
|
|
|
client = IClient(ctx)
|
|
|
|
vdrive = client.getServiceNamed("vdrive")
|
|
|
|
if vdrive.have_private_root():
|
|
|
|
d = vdrive.get_private_root()
|
|
|
|
d.addCallback(lambda dirnode: Directory(dirnode, "~"))
|
|
|
|
return d
|
|
|
|
else:
|
|
|
|
return static.Data("sorry, still initializing", "text/plain")
|
|
|
|
|
2006-12-07 21:48:37 +00:00
|
|
|
|
|
|
|
class WebishServer(service.MultiService):
|
|
|
|
name = "webish"
|
|
|
|
|
|
|
|
def __init__(self, webport):
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
self.root = Root()
|
|
|
|
self.root.putChild("", url.here.child("welcome"))#Welcome())
|
|
|
|
|
|
|
|
self.site = site = appserver.NevowSite(self.root)
|
|
|
|
s = strports.service(webport, site)
|
|
|
|
s.setServiceParent(self)
|
|
|
|
self.listener = s # stash it so the tests can query for the portnum
|
|
|
|
|
|
|
|
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
|