2 from zope.interface import implements
3 from allmydata.util.assertutil import precondition
4 from allmydata.interfaces import INodeMaker, SDMF_VERSION
5 from allmydata.immutable.literal import LiteralFileNode
6 from allmydata.immutable.filenode import ImmutableFileNode, CiphertextFileNode
7 from allmydata.immutable.upload import Data
8 from allmydata.mutable.filenode import MutableFileNode
9 from allmydata.mutable.publish import MutableData
10 from allmydata.dirnode import DirectoryNode, pack_children
11 from allmydata.unknown import UnknownNode
12 from allmydata import uri
15 implements(INodeMaker)
17 def __init__(self, storage_broker, secret_holder, history,
19 default_encoding_parameters, key_generator):
20 self.storage_broker = storage_broker
21 self.secret_holder = secret_holder
22 self.history = history
23 self.uploader = uploader
24 self.terminator = terminator
25 self.default_encoding_parameters = default_encoding_parameters
26 self.key_generator = key_generator
28 self._node_cache = weakref.WeakValueDictionary() # uri -> node
30 def _create_lit(self, cap):
31 return LiteralFileNode(cap)
32 def _create_immutable(self, cap):
33 return ImmutableFileNode(cap, self.storage_broker, self.secret_holder,
34 self.terminator, self.history)
35 def _create_immutable_verifier(self, cap):
36 return CiphertextFileNode(cap, self.storage_broker, self.secret_holder,
37 self.terminator, self.history)
38 def _create_mutable(self, cap):
39 n = MutableFileNode(self.storage_broker, self.secret_holder,
40 self.default_encoding_parameters,
42 return n.init_from_cap(cap)
43 def _create_dirnode(self, filenode):
44 return DirectoryNode(filenode, self, self.uploader)
46 def create_from_cap(self, writecap, readcap=None, deep_immutable=False, name=u"<unknown name>"):
47 # this returns synchronously. It starts with a "cap string".
48 assert isinstance(writecap, (str, type(None))), type(writecap)
49 assert isinstance(readcap, (str, type(None))), type(readcap)
51 bigcap = writecap or readcap
53 # maybe the writecap was hidden because we're in a readonly
54 # directory, and the future cap format doesn't have a readcap, or
56 return UnknownNode(None, None) # deep_immutable and name not needed
58 # The name doesn't matter for caching since it's only used in the error
59 # attribute of an UnknownNode, and we don't cache those.
61 memokey = "I" + bigcap
63 memokey = "M" + bigcap
64 if memokey in self._node_cache:
65 return self._node_cache[memokey]
66 cap = uri.from_string(bigcap, deep_immutable=deep_immutable, name=name)
67 node = self._create_from_single_cap(cap)
69 self._node_cache[memokey] = node # note: WeakValueDictionary
71 # don't cache UnknownNode
72 node = UnknownNode(writecap, readcap, deep_immutable=deep_immutable, name=name)
75 def _create_from_single_cap(self, cap):
76 if isinstance(cap, uri.LiteralFileURI):
77 return self._create_lit(cap)
78 if isinstance(cap, uri.CHKFileURI):
79 return self._create_immutable(cap)
80 if isinstance(cap, uri.CHKFileVerifierURI):
81 return self._create_immutable_verifier(cap)
82 if isinstance(cap, (uri.ReadonlySSKFileURI, uri.WriteableSSKFileURI,
83 uri.WritableMDMFFileURI, uri.ReadonlyMDMFFileURI)):
84 return self._create_mutable(cap)
85 if isinstance(cap, (uri.DirectoryURI,
86 uri.ReadonlyDirectoryURI,
87 uri.ImmutableDirectoryURI,
88 uri.LiteralDirectoryURI,
90 uri.ReadonlyMDMFDirectoryURI)):
91 filenode = self._create_from_single_cap(cap.get_filenode_cap())
92 return self._create_dirnode(filenode)
95 def create_mutable_file(self, contents=None, keysize=None,
96 version=SDMF_VERSION):
97 n = MutableFileNode(self.storage_broker, self.secret_holder,
98 self.default_encoding_parameters, self.history)
99 d = self.key_generator.generate(keysize)
100 d.addCallback(n.create_with_keys, contents, version=version)
101 d.addCallback(lambda res: n)
104 def create_new_mutable_directory(self, initial_children={},
105 version=SDMF_VERSION):
106 # initial_children must have metadata (i.e. {} instead of None)
107 for (name, (node, metadata)) in initial_children.iteritems():
108 precondition(isinstance(metadata, dict),
109 "create_new_mutable_directory requires metadata to be a dict, not None", metadata)
111 d = self.create_mutable_file(lambda n:
112 MutableData(pack_children(initial_children,
115 d.addCallback(self._create_dirnode)
118 def create_immutable_directory(self, children, convergence=None):
119 if convergence is None:
120 convergence = self.secret_holder.get_convergence_secret()
121 packed = pack_children(children, None, deep_immutable=True)
122 uploadable = Data(packed, convergence)
123 d = self.uploader.upload(uploadable, history=self.history)
124 d.addCallback(lambda results: self.create_from_cap(None, results.uri))
125 d.addCallback(self._create_dirnode)