webish: improve download, now you can just append the vdrive path to the base URL to get at the contents of the file. Also added a download-by-URI box

This commit is contained in:
Brian Warner 2006-12-07 14:48:37 -07:00
parent 13d6566c13
commit 4b11831da7
4 changed files with 129 additions and 72 deletions

View File

@ -103,13 +103,13 @@ class SystemTest(unittest.TestCase):
v0 = self.clients[0].getServiceNamed("vdrive") v0 = self.clients[0].getServiceNamed("vdrive")
d1 = v0.make_directory("/", "subdir1") d1 = v0.make_directory("/", "subdir1")
d1.addCallback(lambda subdir1: d1.addCallback(lambda subdir1:
v0.put_file_by_data(subdir1, "data", DATA)) v0.put_file_by_data(subdir1, "mydata567", DATA))
return d1 return d1
d.addCallback(_do_publish) d.addCallback(_do_publish)
def _publish_done(res): def _publish_done(res):
log.msg("publish finished") log.msg("publish finished")
v1 = self.clients[1].getServiceNamed("vdrive") v1 = self.clients[1].getServiceNamed("vdrive")
d1 = v1.get_file_to_data("/subdir1/data") d1 = v1.get_file_to_data("/subdir1/mydata567")
return d1 return d1
d.addCallback(_publish_done) d.addCallback(_publish_done)
def _get_done(data): def _get_done(data):
@ -133,12 +133,11 @@ class SystemTest(unittest.TestCase):
d.addCallback(lambda res: getPage(base + "vdrive/subdir1")) d.addCallback(lambda res: getPage(base + "vdrive/subdir1"))
def _got_subdir1(page): def _got_subdir1(page):
# there ought to be an href for our file # there ought to be an href for our file
self.failUnless(">data</a>" in page) self.failUnless(">mydata567</a>" in page)
d.addCallback(_got_subdir1) d.addCallback(_got_subdir1)
if False: # not implemented yet d.addCallback(lambda res: getPage(base + "vdrive/subdir1/mydata567"))
d.addCallback(lambda res: getPage(base + "vdrive/subdir/data")) def _got_data(page):
def _got_data(page): self.failUnlessEqual(page, self.data)
self.failUnlessEqual(page, self.data) d.addCallback(_got_data)
d.addCallback(_got_data)
return d return d

View File

@ -1,8 +1,9 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1"> <html xmlns:n="http://nevow.com/ns/nevow/0.1">
<head> <head>
<title n:render="title"></title> <title n:render="title"></title>
<link href="http://www.allmydata.com/common/css/styles.css" <!-- <link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/> rel="stylesheet" type="text/css"/> -->
<link href="/webform_css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head> </head>
<body> <body>

View File

@ -1,15 +1,16 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1"> <html xmlns:n="http://nevow.com/ns/nevow/0.1">
<head> <head>
<title>Welcome To AllMyData (tahoe2)</title> <title>Welcome To AllMyData (tahoe2)</title>
<link href="http://www.allmydata.com/common/css/styles.css" <!-- <link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/> rel="stylesheet" type="text/css"/> -->
<link href="/webform_css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head> </head>
<body> <body>
<h1>Welcome To AllMyData! (tahoe2)</h1> <h1>Welcome To AllMyData! (tahoe2)</h1>
<p>To view the global shared filestore, <a href="vdrive">Click Here!</a></p> <p>To view the global shared filestore, <a href="../vdrive">Click Here!</a></p>
<h2>Mesh Status</h2> <h2>Mesh Status</h2>
@ -32,6 +33,7 @@
</table> </table>
</div> </div>
<div n:render="forms"/>
</body> </body>
</html> </html>

View File

@ -1,6 +1,6 @@
from twisted.application import service, strports from twisted.application import service, strports
from twisted.web import static, resource, server from twisted.web import static, resource, server, html
from twisted.python import util, log from twisted.python import util, log
from nevow import inevow, rend, loaders, appserver, url, tags as T from nevow import inevow, rend, loaders, appserver, url, tags as T
from allmydata.util import idlib from allmydata.util import idlib
@ -16,38 +16,12 @@ def getxmlfile(name):
class IClient(Interface): class IClient(Interface):
pass pass
class WebishServer(service.MultiService): def get_downloader_service(ctx):
name = "webish" return IClient(ctx).getServiceNamed("downloader")
def get_uploader_service(ctx):
def __init__(self, webport): return IClient(ctx).getServiceNamed("uploader")
service.MultiService.__init__(self) def get_vdrive_service(ctx):
self.root = root = static.Data("root", "text/plain") return IClient(ctx).getServiceNamed("vdrive")
w = Welcome()
root.putChild("", w)
root.putChild("vdrive",
static.Data("sorry, still initializing", "text/plain"))
self.site = site = appserver.NevowSite(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
def set_root_dirnode(self, dirnode):
self.root.putChild("vdrive", Directory(dirnode, "/"))
# I tried doing it this way and for some reason it didn't seem to work
#print "REMEMBERING", self.site, dl, IDownloader
#self.site.remember(dl, IDownloader)
class Welcome(rend.Page): class Welcome(rend.Page):
addSlash = True addSlash = True
@ -76,6 +50,31 @@ class Welcome(rend.Page):
ctx.fillSlots("connected", connected) ctx.fillSlots("connected", connected)
return ctx.tag return ctx.tag
# 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()
class Directory(rend.Page): class Directory(rend.Page):
addSlash = True addSlash = True
docFactory = getxmlfile("directory.xhtml") docFactory = getxmlfile("directory.xhtml")
@ -84,24 +83,20 @@ class Directory(rend.Page):
self._dirnode = dirnode self._dirnode = dirnode
self._dirname = dirname self._dirname = dirname
def get_service(self, ctx, name):
return IClient(ctx).getServiceNamed(name)
def childFactory(self, ctx, name): def childFactory(self, ctx, name):
if name.startswith("freeform"): # ick if name.startswith("freeform"): # ick
return None return None
if name == "_download":
args = inevow.IRequest(ctx).args
filename = args["filename"][0]
verifierid = args["verifierid"][0]
return Downloader(self.get_service(ctx, "downloader"),
self._dirname, filename, idlib.a2b(verifierid))
if self._dirname == "/": if self._dirname == "/":
dirname = "/" + name dirname = "/" + name
else: else:
dirname = self._dirname + "/" + name dirname = self._dirname + "/" + name
d = self._dirnode.callRemote("get", name) d = self._dirnode.callRemote("get", name)
d.addCallback(lambda newnode: Directory(newnode, dirname)) def _got_child(res):
if isinstance(res, str):
dl = get_downloader_service(ctx)
return Downloader(dl, name, res)
return Directory(res, dirname)
d.addCallback(_got_child)
return d return d
def render_title(self, ctx, data): def render_title(self, ctx, data):
@ -118,13 +113,15 @@ class Directory(rend.Page):
name, target = data name, target = data
if isinstance(target, str): if isinstance(target, str):
# file # file
args = {'verifierid': idlib.b2a(target), dlurl = urllib.quote(name)
'filename': name, ctx.fillSlots("filename",
} T.a(href=dlurl)[html.escape(name)])
dlurl = "_download?%s" % urllib.urlencode(args)
ctx.fillSlots("filename", T.a(href=dlurl)[name])
ctx.fillSlots("type", "FILE") ctx.fillSlots("type", "FILE")
ctx.fillSlots("fileid", idlib.b2a(target)) uri = idlib.b2a(target)
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)
ctx.fillSlots("fileid", T.a(href=dl_uri_url)[html.escape(uri)])
# this creates a button which will cause our child__delete method # this creates a button which will cause our child__delete method
# to be invoked, which deletes the file and then redirects the # to be invoked, which deletes the file and then redirects the
@ -138,13 +135,14 @@ class Directory(rend.Page):
ctx.fillSlots("delete", delete) ctx.fillSlots("delete", delete)
else: else:
# directory # directory
ctx.fillSlots("filename", T.a(href=name)[name]) subdir_url = urllib.quote(name)
ctx.fillSlots("filename",
T.a(href=subdir_url)[html.escape(name)])
ctx.fillSlots("type", "DIR") ctx.fillSlots("type", "DIR")
ctx.fillSlots("fileid", "-") ctx.fillSlots("fileid", "-")
ctx.fillSlots("delete", "-") ctx.fillSlots("delete", "-")
return ctx.tag return ctx.tag
child_webform_css = webform.defaultCSS
def render_forms(self, ctx, data): def render_forms(self, ctx, data):
return webform.renderForms() return webform.renderForms()
@ -167,14 +165,15 @@ class Directory(rend.Page):
contentsarg = annotate.Argument("contents", up) contentsarg = annotate.Argument("contents", up)
ctxarg = annotate.Argument("ctx", annotate.Context()) ctxarg = annotate.Argument("ctx", annotate.Context())
meth = annotate.Method(arguments=[contentsarg, ctxarg]) meth = annotate.Method(arguments=[contentsarg, ctxarg],
return annotate.MethodBinding("upload", meth, action="Upload File") label="Upload File to this directory")
return annotate.MethodBinding("upload", meth, action="Upload")
def upload(self, contents, ctx): def upload(self, contents, ctx):
# contents is a cgi.FieldStorage instance # contents is a cgi.FieldStorage instance
log.msg("starting webish upload") log.msg("starting webish upload")
uploader = self.get_service(ctx, "uploader") uploader = get_uploader_service(ctx)
d = uploader.upload(upload.Data(contents.value)) d = uploader.upload(upload.Data(contents.value))
name = contents.filename name = contents.filename
d.addCallback(lambda vid: d.addCallback(lambda vid:
@ -191,8 +190,8 @@ class Directory(rend.Page):
"""Make new directory 1""" """Make new directory 1"""
namearg = annotate.Argument("name", namearg = annotate.Argument("name",
annotate.String("New directory name: ")) annotate.String("New directory name: "))
meth = annotate.Method(arguments=[namearg]) meth = annotate.Method(arguments=[namearg], label="Make New Subdirectory")
return annotate.MethodBinding("mkdir", meth, action="Make Directory") return annotate.MethodBinding("mkdir", meth, action="Create Directory")
def mkdir(self, name): def mkdir(self, name):
"""mkdir2""" """mkdir2"""
@ -207,7 +206,7 @@ class Directory(rend.Page):
def child__delete(self, ctx): def child__delete(self, ctx):
# perform the delete, then redirect back to the directory page # perform the delete, then redirect back to the directory page
args = inevow.IRequest(ctx).args args = inevow.IRequest(ctx).args
vdrive = self.get_service(ctx, "vdrive") vdrive = get_vdrive_service(ctx)
d = vdrive.remove(self._dirnode, args["name"][0]) d = vdrive.remove(self._dirnode, args["name"][0])
def _deleted(res): def _deleted(res):
return url.here.up() return url.here.up()
@ -244,9 +243,8 @@ class TypedFile(static.File):
self.defaultType) self.defaultType)
class Downloader(resource.Resource): class Downloader(resource.Resource):
def __init__(self, downloader, dirname, name, verifierid): def __init__(self, downloader, name, verifierid):
self._downloader = downloader self._downloader = downloader
self._dirname = dirname
self._name = name self._name = name
self._verifierid = verifierid self._verifierid = verifierid
@ -268,3 +266,60 @@ class Downloader(resource.Resource):
return server.NOT_DONE_YET return server.NOT_DONE_YET
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
uri_a = segments[1]
elif "uri" in req.args:
# http://host/download_uri?uri=URIGOESHERE
uri_a = req.args["uri"][0]
else:
return rend.NotFound
child = Downloader(dl, filename, idlib.a2b(uri_a))
return child, ()
return rend.Page.locateChild(self, ctx, segments)
child_webform_css = webform.defaultCSS
child_welcome = Welcome()
class WebishServer(service.MultiService):
name = "webish"
def __init__(self, webport):
service.MultiService.__init__(self)
self.root = Root()
placeholder = static.Data("sorry, still initializing", "text/plain")
self.root.putChild("vdrive", placeholder)
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
def set_root_dirnode(self, dirnode):
self.root.putChild("vdrive", Directory(dirnode, "/"))
# I tried doing it this way and for some reason it didn't seem to work
#print "REMEMBERING", self.site, dl, IDownloader
#self.site.remember(dl, IDownloader)