add a (read-only) web frontend. Put a 'webport' file in your base directory to activate it.

This commit is contained in:
Brian Warner 2006-12-04 04:06:09 -07:00
parent faf0b13e3c
commit a3700cc582
6 changed files with 213 additions and 0 deletions

View File

@ -14,6 +14,7 @@ from allmydata.storageserver import StorageServer
from allmydata.upload import Uploader from allmydata.upload import Uploader
from allmydata.download import Downloader from allmydata.download import Downloader
from allmydata.vdrive import VDrive from allmydata.vdrive import VDrive
from allmydata.webish import WebishServer
class Client(node.Node, Referenceable): class Client(node.Node, Referenceable):
implements(RIClient) implements(RIClient)
@ -21,6 +22,7 @@ class Client(node.Node, Referenceable):
PORTNUMFILE = "client.port" PORTNUMFILE = "client.port"
STOREDIR = 'storage' STOREDIR = 'storage'
NODETYPE = "client" NODETYPE = "client"
WEBPORTFILE = "webport"
def __init__(self, basedir="."): def __init__(self, basedir="."):
node.Node.__init__(self, basedir) node.Node.__init__(self, basedir)
@ -31,6 +33,12 @@ class Client(node.Node, Referenceable):
self.add_service(Uploader()) self.add_service(Uploader())
self.add_service(Downloader()) self.add_service(Downloader())
self.add_service(VDrive()) self.add_service(VDrive())
WEBPORTFILE = os.path.join(self.basedir, self.WEBPORTFILE)
if os.path.exists(WEBPORTFILE):
f = open(WEBPORTFILE, "r")
webport = int(f.read())
f.close()
self.add_service(WebishServer(webport))
self.queen_pburl = None self.queen_pburl = None
self.queen_connector = None self.queen_connector = None
@ -73,6 +81,8 @@ class Client(node.Node, Referenceable):
def _got_vdrive_root(self, root): def _got_vdrive_root(self, root):
self.getServiceNamed("vdrive").set_root(root) self.getServiceNamed("vdrive").set_root(root)
if "webish" in self.namedServices:
self.getServiceNamed("webish").set_root_dirnode(root)
def _lost_queen(self): def _lost_queen(self):
self.log("lost connection to queen") self.log("lost connection to queen")

View File

@ -195,10 +195,14 @@ class FileHandle:
def finish(self): def finish(self):
pass pass
class IDownloader(Interface):
def download(verifierid, target):
pass
class Downloader(service.MultiService): class Downloader(service.MultiService):
"""I am a service that allows file downloading. """I am a service that allows file downloading.
""" """
implements(IDownloader)
name = "downloader" name = "downloader"
def download(self, verifierid, t): def download(self, verifierid, t):

View File

@ -0,0 +1,36 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
<head>
<title n:render="title"></title>
<link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1><p n:render="header"></p></h1>
<div><a href=".">Refresh this view</a></div>
<div><a href="..">Parent Directory</a></div>
<table n:render="sequence" n:data="children" border="1">
<tr n:pattern="header">
<td>Filename</td>
<td>Type</td>
<td>fileid</td>
</tr>
<tr n:pattern="item" n:render="row">
<td><n:slot name="filename"/></td>
<td><n:slot name="type"/></td>
<td><n:slot name="fileid"/></td>
</tr>
<tr n:pattern="empty"><td>directory is empty!</td></tr>
</table>
<!-- <div n:render="forms"/> -->
<!-- <div class="results" n:render="results"/> -->
</body>
</html>

View File

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

145
allmydata/webish.py Normal file
View File

@ -0,0 +1,145 @@
from twisted.application import service, internet
from twisted.web import static, resource, server
from twisted.python import util
from nevow import inevow, rend, loaders, appserver, tags as T
from allmydata.util import idlib
from allmydata.download import IDownloadTarget#, IDownloader
from zope.interface import implements
import urllib
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):
dl = self.parent.getServiceNamed("downloader")
self.root.putChild("vdrive", Directory(dirnode, "/", dl))
#print "REMEMBERING", self.site, dl, IDownloader
#self.site.remember(dl, IDownloader)
class Welcome(rend.Page):
addSlash = True
docFactory = getxmlfile("welcome.xhtml")
class Directory(rend.Page):
addSlash = True
docFactory = getxmlfile("directory.xhtml")
def __init__(self, dirnode, dirname, downloader):
self._dirnode = dirnode
self._dirname = dirname
self._downloader = downloader
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]
return Downloader(self._downloader,
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:
Directory(newnode, dirname, self._downloader))
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
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

View File

@ -28,6 +28,9 @@ storage: RobK
leases never expire leases never expire
v2: leases expire, delete expired data on demand, multiple owners per share v2: leases expire, delete expired data on demand, multiple owners per share
UI:
webish? webfront? PB + CLI tool? FUSE?
v1:
back pocket ideas: back pocket ideas:
when nodes are unable to reach storage servers, make a note of it, inform when nodes are unable to reach storage servers, make a note of it, inform