]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/nodemaker.py
fb69ea585d7916bd17c5e04ba250f807d277e3be
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / nodemaker.py
1 import weakref
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
13
14 class NodeMaker:
15     implements(INodeMaker)
16
17     def __init__(self, storage_broker, secret_holder, history,
18                  uploader, terminator,
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
27
28         self._node_cache = weakref.WeakValueDictionary() # uri -> node
29
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,
41                             self.history)
42         return n.init_from_cap(cap)
43     def _create_dirnode(self, filenode):
44         return DirectoryNode(filenode, self, self.uploader)
45
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)
50
51         bigcap = writecap or readcap
52         if not bigcap:
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
55             # something.
56             return UnknownNode(None, None)  # deep_immutable and name not needed
57
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.
60         if deep_immutable:
61             memokey = "I" + bigcap
62         else:
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)
68         if node:
69             self._node_cache[memokey] = node  # note: WeakValueDictionary
70         else:
71             # don't cache UnknownNode
72             node = UnknownNode(writecap, readcap, deep_immutable=deep_immutable, name=name)
73         return node
74
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,
89                             uri.MDMFDirectoryURI,
90                             uri.ReadonlyMDMFDirectoryURI)):
91             filenode = self._create_from_single_cap(cap.get_filenode_cap())
92             return self._create_dirnode(filenode)
93         return None
94
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)
102         return d
103
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)
110             node.raise_error()
111         d = self.create_mutable_file(lambda n:
112                                      MutableData(pack_children(initial_children,
113                                                     n.get_writekey())),
114                                      version=version)
115         d.addCallback(self._create_dirnode)
116         return d
117
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)
126         return d