ICHKDirectoryNode, ISSKDirectoryNode,
NoSuchChildError,
)
-from allmydata.filetree.basenode import BaseURINode
+from allmydata.filetree.basenode import BaseDataNode
from allmydata import download
from allmydata.util import bencode
# # then self.child_specifications["foo.jpg"] = ("CHKFILE","fooURI")
# self.child_specifications = {}
- def is_directory(self):
- return True
-
def list(self):
return sorted(self.children.keys())
break
return (found_path, node, remaining_path)
-class CHKDirectorySubTreeNode(BaseURINode):
+class CHKDirectorySubTreeNode(BaseDataNode):
implements(ICHKDirectoryNode)
prefix = "CHKDirectory"
+ def get_base_data(self):
+ return self.uri
+ def set_base_data(self, data):
+ self.uri = data
+
def get_uri(self):
return self.uri
class CHKDirectorySubTree(_DirectorySubTree):
# maybe mutable, maybe not
- def mutation_affects_parent(self):
- return True
-
def set_uri(self, uri):
self.old_uri = uri
self.serialize_to_file(f)
f.close()
boxname = work_queue.create_boxname()
+ # mutation affects our parent
work_queue.add_upload_chk(filename, boxname)
work_queue.add_delete_tempfile(filename)
work_queue.add_retain_uri_from_box(boxname)
implements(INode, ISSKDirectoryNode)
prefix = "SSKDirectory"
- def is_directory(self):
- return False
def serialize_node(self):
data = (self.read_cap, self.write_cap)
return "%s:%s" % (self.prefix, bencode.bencode(data))
self.version = 0
# TODO: populate
- def mutation_affects_parent(self):
- return False
-
def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
node = ISSKDirectoryNode(node)
self.read_capability = node.get_read_capability()
f, filename = work_queue.create_tempfile(".sskdir")
self.serialize_to_file(f)
f.close()
+ # mutation does not affect our parent
work_queue.add_upload_ssk(filename, self.write_capability,
self.version)
self.version = self.version + 1
+from cStringIO import StringIO
+from zope.interface import implements
+from twisted.internet import defer
+
+from allmydata.filetree.interfaces import ISubTree
+from allmydata.filetree.basenode import BaseDataNode
from allmydata.util import bencode
-class LocalFileRedirection(object):
+class LocalFileRedirectionNode(BaseDataNode):
+ prefix = "LocalFileRedirection"
+
+ def new(self, handle):
+ self.handle = handle
+
+ def get_base_data(self):
+ return self.handle
+ def set_base_data(self, data):
+ self.handle = data
+
+class _BaseRedirection(object):
+ implements(ISubTree)
+
+ def new(self, child_node):
+ self.child_node = child_node
+
+ def get_node_for_path(self, path):
+ return ([], self.child_node, path)
+
+ def serialize_subtree_to_file(self, f):
+ return self.child_node.serialize_node()
+
+ def _populate_from_data(self, data, node_maker):
+ self.child_node = node_maker(data)
+ return self
+
+class LocalFileRedirection(_BaseRedirection):
stype = "LocalFileRedirection"
- def populate_from_specification(self, spec, parent_is_mutable, downloader):
+ def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
# return a Deferred that fires (with self) when this node is ready
# for use
- (stype, filename) = spec
- assert stype == self.stype
- #filename = spec.get_filename()
- # there is a local file which contains a bencoded serialized
- # subtree specification.
-
- # TODO: will this enable outsiders to cause us to read from
- # arbitrary files? Think about this.
- f = open(filename, "rb")
+ assert isinstance(node, LocalFileRedirectionNode)
+ self.filename = node.handle
+ # there is a local file which contains a bencoded serialized subtree
+ # specification.
+
+ # TODO: will this enable outsiders to cause us to read from arbitrary
+ # files? Think about this. It is probably a good idea to restrict the
+ # filename to be a single component, and to always put them in a
+ # well-known directory that contains nothing else, and maybe make
+ # them unguessable.
+ f = open(self.filename, "rb")
data = f.read()
f.close()
# note: we don't cache the contents of the file. TODO: consider
# doing this based upon mtime. It is important that we be able to
# notice if the file has been changed.
+ return defer.succeed(self._populate_from_data(data, node_maker))
- return self.populate_from_data(data)
+ def is_mutable(self):
+ return True
- def populate_from_data(self, data):
- # data is a subtree specification for our one child
- self.child_spec = bencode.bdecode(data)
- return self
+ def update(self, prepath, workqueue):
+ f = open(self.filename, "wb")
+ self.serialize_subtree_to_file(f)
+ f.close()
+
+
+class QueenRedirectionNode(LocalFileRedirectionNode):
+ prefix = "QueenRedirection"
-class QueenRedirection(object):
- stype = "QueenRedirection"
+class QueenRedirection(_BaseRedirection):
+ style = "QueenRedirection"
- def populate_from_specification(self, spec, parent_is_mutable, downloader):
- # this specifies a handle for which the Queen maintains a
- # serialized subtree specification.
- (stype, handle) = spec
+ def new(self, handle):
+ self.handle = handle
+
+ def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
+ # this specifies a handle for which the Queen maintains a serialized
+ # subtree specification.
+ assert isinstance(node, QueenRedirectionNode)
+ self.handle = node.handle
# TODO: queen?
- d = self._queen.callRemote("lookup_handle", handle)
- d.addCallback(self.populate_from_data)
+ d = self._queen.callRemote("lookup_handle", self.handle)
+ d.addCallback(self._populate_from_data, node_maker)
return d
- def populate_from_data(self, data):
- self.child_spec = bencode.bdecode(data)
- return self
+ def is_mutable(self):
+ return True # TODO: maybe, maybe not
+
+ def update(self, prepath, workqueue):
+ f = StringIO()
+ self.serialize_subtree_to_file(f)
+ d = self._queen.callRemote("set_handle", self.handle, f.getvalue())
+ return d
+
+class QueenOrLocalFileRedirectionNode(LocalFileRedirectionNode):
+ prefix = "QueenOrLocalFileRedirection"
-class QueenOrLocalFileRedirection(object):
+class QueenOrLocalFileRedirection(_BaseRedirection):
stype = "QueenOrLocalFileRedirection"
- def populate_from_specification(self, spec, parent_is_mutable, downloader):
+ def new(self, handle, child_node):
+ self.handle = handle
+ self.version = 0
+ self.child_node = child_node
+ # TODO
+
+ def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
# there is a local file which contains a bencoded serialized
# subtree specification. The queen also has a copy. Whomever has
# the higher version number wins.
- (stype, filename, handle) = spec
+ assert isinstance(node, QueenOrLocalFileRedirectionNode)
+ self.filename = self.handle = node.handle
- f = open(filename, "rb")
+ f = open(self.filename, "rb")
#local_version, local_data = bencode.bdecode(f.read())
local_version_and_data = f.read()
f.close()
# TODO: queen?
# TODO: pubsub so we can cache the queen's results
- d = self._queen.callRemote("lookup_handle", handle)
- d.addCallback(self._choose_winner, local_version_and_data)
+ d = self._queen.callRemote("lookup_handle", self.handle)
+ d.addCallback(self._choose_winner, local_version_and_data, node_maker)
return d
- def _choose_winner(self, queen_version_and_data, local_version_and_data):
+ def _choose_winner(self, queen_version_and_data, local_version_and_data, node_maker):
queen_version, queen_data = bencode.bdecode(queen_version_and_data)
local_version, local_data = bencode.bdecode(local_version_and_data)
if queen_version > local_version:
data = queen_data
+ self.version = queen_version
else:
data = local_data
- return self.populate_from_data(data)
-
- def populate_from_data(self, data):
+ self.version = local_version
# NOTE: two layers of bencoding here, TODO
- self.child_spec = bencode.bdecode(data)
- return self
+ return self._populate_from_data(data, node_maker)
+
+ def is_mutable(self):
+ return True
+
+ def update(self, prepath, workqueue):
+ self.version += 1
+ f = StringIO()
+ self.serialize_subtree_to_file(f)
+ version_and_data = bencode.bencode((self.version, f.getvalue()))
+ f = open(self.filename, "wb")
+ f.write(version_and_data)
+ f.close()
+ d = self._queen.callRemote("set_handle", self.handle, version_and_data)
+ return d
+
+class HTTPRedirectionNode(BaseDataNode):
+ prefix = "HTTPRedirection"
-class HTTPRedirection(object):
+ def new(self, url):
+ self.url = url
+
+ def get_base_data(self):
+ return self.url
+ def set_base_data(self, data):
+ self.url = data
+
+class HTTPRedirection(_BaseRedirection):
stype = "HTTPRedirection"
- def populate_from_specification(self, spec, parent_is_mutable, downloader):
+ def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
# this specifies a URL at which there is a bencoded serialized
# subtree specification.
- (stype, url) = spec
+ assert isinstance(node, HTTPRedirectionNode)
from twisted.web import client
- d = client.getPage(url)
- d.addCallback(self.populate_from_data)
+ d = client.getPage(node.url)
+ d.addCallback(self._populate_from_data, node_maker)
return d
- def populate_from_data(self, data):
- self.child_spec = bencode.bdecode(data)
- return self
+ def is_mutable(self):
+ return False
+
+ def update(self, prepath, workqueue):
+ raise RuntimeError("HTTPRedirection is not mutable")