2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
from twisted.application import service, internet
|
|
|
|
from twisted.web import static, resource, server
|
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
|
2006-12-04 11:06:09 +00:00
|
|
|
from allmydata.util import idlib
|
|
|
|
from allmydata.download import IDownloadTarget#, IDownloader
|
2006-12-04 12:15:36 +00:00
|
|
|
from allmydata import upload
|
2006-12-04 11:06:09 +00:00
|
|
|
from zope.interface import implements
|
|
|
|
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))
|
|
|
|
|
|
|
|
class WebishServer(service.MultiService):
|
|
|
|
name = "webish"
|
|
|
|
WEBPORTFILE = "webport"
|
|
|
|
|
|
|
|
def __init__(self, webport):
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
self.root = root = static.Data("root", "text/plain")
|
|
|
|
w = Welcome()
|
|
|
|
root.putChild("", w)
|
|
|
|
root.putChild("vdrive",
|
|
|
|
static.Data("sorry, still initializing", "text/plain"))
|
|
|
|
self.site = site = appserver.NevowSite(root)
|
|
|
|
internet.TCPServer(webport, site).setServiceParent(self)
|
|
|
|
|
|
|
|
def set_root_dirnode(self, dirnode):
|
2006-12-04 12:15:36 +00:00
|
|
|
self.root.putChild("vdrive", Directory(dirnode, "/", self.parent))
|
2006-12-04 11:06:09 +00:00
|
|
|
#print "REMEMBERING", self.site, dl, IDownloader
|
|
|
|
#self.site.remember(dl, IDownloader)
|
|
|
|
|
|
|
|
|
|
|
|
class Welcome(rend.Page):
|
|
|
|
addSlash = True
|
|
|
|
docFactory = getxmlfile("welcome.xhtml")
|
|
|
|
|
2006-12-04 19:03:29 +00:00
|
|
|
class IDirectoryEditor(annotate.TypedInterface):
|
2006-12-04 12:15:36 +00:00
|
|
|
def upload(contents=annotate.FileUpload(label="Choose a file to upload: ",
|
|
|
|
required=True,
|
|
|
|
requiredFailMessage="Do iT!"),
|
|
|
|
ctx=annotate.Context(),
|
|
|
|
):
|
2006-12-04 19:03:29 +00:00
|
|
|
# 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.
|
2006-12-04 12:15:36 +00:00
|
|
|
#"""Upload a file"""
|
|
|
|
pass
|
|
|
|
upload = annotate.autocallable(upload, action="Upload file")
|
|
|
|
|
2006-12-04 19:03:29 +00:00
|
|
|
def mkdir(name=annotate.String("Create a new directory named: ",
|
|
|
|
required=True,
|
|
|
|
requiredFailMessage="You must choose a directory"),
|
|
|
|
):
|
|
|
|
#"""Create a directory."""
|
|
|
|
pass
|
|
|
|
mkdir = annotate.autocallable(mkdir, action="Make directory")
|
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
class Directory(rend.Page):
|
|
|
|
addSlash = True
|
|
|
|
docFactory = getxmlfile("directory.xhtml")
|
|
|
|
|
2006-12-04 12:15:36 +00:00
|
|
|
def __init__(self, dirnode, dirname, client):
|
2006-12-04 11:06:09 +00:00
|
|
|
self._dirnode = dirnode
|
|
|
|
self._dirname = dirname
|
2006-12-04 12:15:36 +00:00
|
|
|
self._client = client
|
2006-12-04 11:06:09 +00:00
|
|
|
|
|
|
|
def childFactory(self, ctx, name):
|
|
|
|
if name.startswith("freeform"): # ick
|
|
|
|
return None
|
|
|
|
if name == "_download":
|
|
|
|
args = inevow.IRequest(ctx).args
|
|
|
|
filename = args["filename"][0]
|
|
|
|
verifierid = args["verifierid"][0]
|
2006-12-04 12:15:36 +00:00
|
|
|
return Downloader(self._client.getServiceNamed("downloader"),
|
2006-12-04 11:06:09 +00:00
|
|
|
self._dirname, filename, idlib.a2b(verifierid))
|
|
|
|
if self._dirname == "/":
|
|
|
|
dirname = "/" + name
|
|
|
|
else:
|
|
|
|
dirname = self._dirname + "/" + name
|
|
|
|
d = self._dirnode.callRemote("get", name)
|
|
|
|
d.addCallback(lambda newnode:
|
2006-12-04 12:15:36 +00:00
|
|
|
Directory(newnode, dirname, self._client))
|
2006-12-04 11:06:09 +00:00
|
|
|
return d
|
|
|
|
|
|
|
|
def render_title(self, ctx, data):
|
|
|
|
return ctx.tag["Directory of '%s':" % self._dirname]
|
|
|
|
|
|
|
|
def render_header(self, ctx, data):
|
|
|
|
return "Directory of '%s':" % self._dirname
|
|
|
|
|
|
|
|
def data_children(self, ctx, data):
|
|
|
|
d = self._dirnode.callRemote("list")
|
|
|
|
return d
|
|
|
|
|
|
|
|
def render_row(self, ctx, data):
|
|
|
|
name, target = data
|
|
|
|
if isinstance(target, str):
|
|
|
|
# file
|
|
|
|
args = {'verifierid': idlib.b2a(target),
|
|
|
|
'filename': name,
|
|
|
|
}
|
|
|
|
dlurl = "_download?%s" % urllib.urlencode(args)
|
|
|
|
ctx.fillSlots("filename", T.a(href=dlurl)[name])
|
|
|
|
ctx.fillSlots("type", "FILE")
|
|
|
|
ctx.fillSlots("fileid", idlib.b2a(target))
|
|
|
|
else:
|
|
|
|
# directory
|
|
|
|
ctx.fillSlots("filename", T.a(href=name)[name])
|
|
|
|
ctx.fillSlots("type", "DIR")
|
|
|
|
ctx.fillSlots("fileid", "-")
|
|
|
|
return ctx.tag
|
|
|
|
|
2006-12-04 12:15:36 +00:00
|
|
|
# this tells formless about what functions can be invoked, giving it
|
|
|
|
# enough information to construct form contents
|
2006-12-04 19:03:29 +00:00
|
|
|
implements(IDirectoryEditor)
|
2006-12-04 12:15:36 +00:00
|
|
|
|
|
|
|
child_webform_css = webform.defaultCSS
|
|
|
|
def render_forms(self, ctx, data):
|
|
|
|
return webform.renderForms()
|
|
|
|
|
|
|
|
def upload(self, contents, ctx):
|
|
|
|
# contents is a cgi.FieldStorage instance
|
|
|
|
log.msg("starting webish upload")
|
|
|
|
|
|
|
|
uploader = self._client.getServiceNamed("uploader")
|
|
|
|
d = uploader.upload(upload.Data(contents.value))
|
|
|
|
name = contents.filename
|
|
|
|
d.addCallback(lambda vid:
|
|
|
|
self._dirnode.callRemote("add_file", name, vid))
|
|
|
|
def _done(res):
|
|
|
|
log.msg("webish upload complete")
|
|
|
|
return res
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
|
|
|
return url.here.add("results",
|
|
|
|
"upload of '%s' complete!" % contents.filename)
|
|
|
|
|
2006-12-04 19:03:29 +00:00
|
|
|
def mkdir(self, name):
|
|
|
|
log.msg("making new webish directory")
|
|
|
|
d = self._dirnode.callRemote("add_directory", name)
|
|
|
|
def _done(res):
|
|
|
|
log.msg("webish mkdir complete")
|
|
|
|
return res
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
|
|
|
|
2006-12-04 11:06:09 +00:00
|
|
|
class WebDownloadTarget:
|
|
|
|
implements(IDownloadTarget)
|
|
|
|
def __init__(self, req):
|
|
|
|
self._req = req
|
|
|
|
def open(self):
|
|
|
|
pass
|
|
|
|
def write(self, data):
|
|
|
|
self._req.write(data)
|
|
|
|
def close(self):
|
|
|
|
self._req.finish()
|
|
|
|
def fail(self):
|
|
|
|
self._req.finish()
|
|
|
|
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):
|
|
|
|
def __init__(self, downloader, dirname, name, verifierid):
|
|
|
|
self._downloader = downloader
|
|
|
|
self._dirname = dirname
|
|
|
|
self._name = name
|
|
|
|
self._verifierid = verifierid
|
|
|
|
|
|
|
|
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")
|
|
|
|
req.setHeader("content-type", type)
|
|
|
|
if encoding:
|
|
|
|
req.setHeader('content-encoding', encoding)
|
|
|
|
|
|
|
|
t = WebDownloadTarget(req)
|
|
|
|
#dl = IDownloader(ctx)
|
|
|
|
dl = self._downloader
|
|
|
|
dl.download(self._verifierid, t)
|
|
|
|
return server.NOT_DONE_YET
|
2006-12-04 12:15:36 +00:00
|
|
|
|
|
|
|
|