2 """This is the client-side facility to manipulate virtual drives."""
4 from twisted.application import service
5 from twisted.internet import defer
6 from twisted.python import log
7 from allmydata import upload, download
9 class VDrive(service.MultiService):
12 def set_root(self, root):
15 def dirpath(self, dir_or_path):
16 if isinstance(dir_or_path, str):
17 return self.get_dir(dir_or_path)
18 return defer.succeed(dir_or_path)
20 def get_dir(self, path):
21 """Return a Deferred that fires with a RemoteReference to a
22 MutableDirectoryNode at the given /-delimited path."""
23 d = defer.succeed(self.gvd_root)
24 if path.startswith("/"):
28 for piece in path.split("/"):
29 d.addCallback(lambda parent: parent.callRemote("list"))
30 def _find(table, subdir):
31 for name,target in table:
35 raise KeyError("no such directory '%s' in '%s'" %
36 (subdir, [t[0] for t in table]))
37 d.addCallback(_find, piece)
39 assert not isinstance(subdir, str), "Hey, %s shouldn't be a string" % subdir
44 def get_verifierid_from_parent(self, parent, filename):
45 assert not isinstance(parent, str), "'%s' isn't a directory node" % (parent,)
46 d = parent.callRemote("list")
48 for name,target in table:
50 assert isinstance(target, str), "Hey, %s isn't a file" % filename
53 raise KeyError("no such file '%s' in '%s'" %
54 (filename, [t[0] for t in table]))
61 def listdir(self, dir_or_path):
62 d = self.dirpath(dir_or_path)
63 d.addCallback(lambda parent: parent.callRemote("list"))
65 return [t[0] for t in table]
69 def put_file(self, dir_or_path, name, uploadable):
70 """Upload an IUploadable and add it to the virtual drive (as an entry
71 called 'name', in 'dir_or_path') 'dir_or_path' must either be a
72 string like 'root/subdir1/subdir2', or a directory node (either the
73 root directory node returned by get_root(), or a subdirectory
76 The uploadable can be an instance of allmydata.upload.Data,
77 FileHandle, or FileName.
79 I return a deferred that will fire when the operation is complete.
82 log.msg("putting file to '%s'" % name)
83 ul = self.parent.getServiceNamed("uploader")
84 d = self.dirpath(dir_or_path)
85 def _got_dir(dirnode):
86 d1 = ul.upload(uploadable)
87 d1.addCallback(lambda vid:
88 dirnode.callRemote("add_file", name, vid))
90 d.addCallback(_got_dir)
92 log.msg("finished putting file to '%s'" % name)
97 def put_file_by_filename(self, dir_or_path, name, filename):
98 return self.put_file(dir_or_path, name, upload.FileName(filename))
99 def put_file_by_data(self, dir_or_path, name, data):
100 return self.put_file(dir_or_path, name, upload.Data(data))
101 def put_file_by_filehandle(self, dir_or_path, name, filehandle):
102 return self.put_file(dir_or_path, name, upload.FileHandle(filehandle))
104 def make_directory(self, dir_or_path, name):
105 d = self.dirpath(dir_or_path)
106 d.addCallback(lambda parent: parent.callRemote("add_directory", name))
109 def remove(self, parent, name):
110 assert not isinstance(parent, str)
111 log.msg("vdrive removing %s" % name)
112 # first find the verifierid
113 d = self.get_verifierid_from_parent(parent, name)
114 def _got_verifierid(vid):
115 # TODO: delete the file's shares using this
117 d.addCallback(_got_verifierid)
118 def _delete_from_parent(res):
119 return parent.callRemote("remove", name)
120 d.addCallback(_delete_from_parent)
122 log.msg("vdrive done removing %s" % name)
127 def get_file(self, dir_and_name_or_path, download_target):
128 """Retrieve a file from the virtual drive and put it somewhere.
130 The file to be retrieved may either be specified as a (dir, name)
131 tuple or as a full /-delimited pathname. In the former case, 'dir'
132 can be either a DirectoryNode or a pathname.
134 The download target must be an IDownloadTarget instance like
135 allmydata.download.Data, .FileName, or .FileHandle .
138 log.msg("getting file from %s" % (dir_and_name_or_path,))
139 dl = self.parent.getServiceNamed("downloader")
141 if isinstance(dir_and_name_or_path, tuple):
142 dir_or_path, name = dir_and_name_or_path
143 d = self.dirpath(dir_or_path)
144 def _got_dir(dirnode):
145 return self.get_verifierid_from_parent(dirnode, name)
146 d.addCallback(_got_dir)
148 rslash = dir_and_name_or_path.rfind("/")
150 # we're looking for a file in the root directory
152 name = dir_and_name_or_path
153 d = self.get_verifierid_from_parent(dir, name)
155 dirpath = dir_and_name_or_path[:rslash]
156 name = dir_and_name_or_path[rslash+1:]
157 d = self.dirpath(dirpath)
158 d.addCallback(lambda dir:
159 self.get_verifierid_from_parent(dir, name))
161 def _got_verifierid(verifierid):
162 return dl.download(verifierid, download_target)
163 d.addCallback(_got_verifierid)
165 log.msg("finished getting file")
170 def get_file_to_filename(self, from_where, filename):
171 return self.get_file(from_where, download.FileName(filename))
172 def get_file_to_data(self, from_where):
173 return self.get_file(from_where, download.Data())
174 def get_file_to_filehandle(self, from_where, filehandle):
175 return self.get_file(from_where, download.FileHandle(filehandle))