From: Brian Warner Date: Wed, 6 Feb 2008 04:01:38 +0000 (-0700) Subject: upload: return an UploadResults instance (with .uri) instead of just a URI X-Git-Tag: allmydata-tahoe-0.8.0~139 X-Git-Url: https://git.rkrishnan.org/architecture.txt?a=commitdiff_plain;h=66f33ee5049fb939ccd4b155a50f0f7adfab859c;p=tahoe-lafs%2Ftahoe-lafs.git upload: return an UploadResults instance (with .uri) instead of just a URI --- diff --git a/src/allmydata/control.py b/src/allmydata/control.py index 6e7fb910..8c99f005 100644 --- a/src/allmydata/control.py +++ b/src/allmydata/control.py @@ -46,6 +46,7 @@ class ControlServer(Referenceable, service.Service, testutil.PollMixin): uploader = self.parent.getServiceNamed("uploader") u = upload.FileName(filename) d = uploader.upload(u) + d.addCallback(lambda results: results.uri) return d def remote_download_from_uri_to_file(self, uri, filename): @@ -162,6 +163,7 @@ class SpeedTest: else: up = upload.FileName(fn) d1 = self.parent.upload(up) + d1.addCallback(lambda results: results.uri) d1.addCallback(_record_uri, i) d1.addCallback(_upload_one_file, i+1) return d1 diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py index 392ab041..569dc768 100644 --- a/src/allmydata/dirnode.py +++ b/src/allmydata/dirnode.py @@ -279,6 +279,7 @@ class NewDirectoryNode: if self.is_readonly(): return defer.fail(NotMutableError()) d = self._client.upload(uploadable) + d.addCallback(lambda results: results.uri) d.addCallback(self._client.create_node_from_uri) d.addCallback(lambda node: self.set_node(name, node)) return d diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py index 1c7276ce..ae1fc65c 100644 --- a/src/allmydata/interfaces.py +++ b/src/allmydata/interfaces.py @@ -1207,10 +1207,19 @@ class IUploadable(Interface): """The upload is finished, and whatever filehandle was in use may be closed.""" +class IUploadResults(Interface): + """I am returned by upload() methods. I contain a number of public + attributes which can be read to determine the results of the upload:: + + .uri : the CHK read-cap for the file + + """ + class IUploader(Interface): def upload(uploadable): """Upload the file. 'uploadable' must impement IUploadable. This - returns a Deferred which fires with the URI of the file.""" + returns a Deferred which fires with an UploadResults instance, from + which the URI of the file can be obtained as results.uri .""" def upload_ssk(write_capability, new_version, uploadable): """TODO: how should this work?""" @@ -1278,9 +1287,10 @@ class IChecker(Interface): class IClient(Interface): def upload(uploadable): - """Upload some data into a CHK, get back the URI string for it. + """Upload some data into a CHK, get back the UploadResults for it. @param uploadable: something that implements IUploadable - @return: a Deferred that fires with the (string) URI for this file. + @return: a Deferred that fires with the UploadResults instance. + To get the URI for this file, use results.uri . """ def create_mutable_file(contents=""): diff --git a/src/allmydata/test/check_memory.py b/src/allmydata/test/check_memory.py index 6987bcea..de65de51 100644 --- a/src/allmydata/test/check_memory.py +++ b/src/allmydata/test/check_memory.py @@ -392,6 +392,7 @@ this file are ignored. u = self.nodes[0].getServiceNamed("uploader") d = self.nodes[0].debug_wait_for_client_connections(self.numnodes+1) d.addCallback(lambda res: u.upload(upload.FileName(files[name]))) + d.addCallback(lambda results: results.uri) else: raise RuntimeError("unknown mode=%s" % self.mode) def _complete(uri): diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py index 0880ad6f..ae7aacac 100644 --- a/src/allmydata/test/test_dirnode.py +++ b/src/allmydata/test/test_dirnode.py @@ -44,7 +44,9 @@ class FakeClient: def _got_data(datav): data = "".join(datav) n = create_chk_filenode(self, data) - return n.get_uri() + results = upload.UploadResults() + results.uri = n.get_uri() + return results d.addCallback(_got_data) return d diff --git a/src/allmydata/test/test_helper.py b/src/allmydata/test/test_helper.py index 0d80c60f..481664e9 100644 --- a/src/allmydata/test/test_helper.py +++ b/src/allmydata/test/test_helper.py @@ -98,7 +98,8 @@ class AssistedUpload(unittest.TestCase): DATA = "I need help\n" * 1000 return upload_data(u, DATA) d.addCallback(_ready) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri assert "CHK" in uri d.addCallback(_uploaded) @@ -141,7 +142,8 @@ class AssistedUpload(unittest.TestCase): assert u._helper return upload_data(u, DATA) d.addCallback(_ready) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri assert "CHK" in uri d.addCallback(_uploaded) @@ -172,7 +174,8 @@ class AssistedUpload(unittest.TestCase): DATA = "I need help\n" * 1000 return upload_data(u, DATA) d.addCallback(_ready) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri assert "CHK" in uri d.addCallback(_uploaded) diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py index 3834696b..04b69eab 100644 --- a/src/allmydata/test/test_system.py +++ b/src/allmydata/test/test_system.py @@ -214,7 +214,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase): d1 = u.upload(up) return d1 d.addCallback(_do_upload) - def _upload_done(uri): + def _upload_done(results): + uri = results.uri log.msg("upload finished: uri is %s" % (uri,)) self.uri = uri dl = self.clients[1].getServiceNamed("downloader") @@ -295,7 +296,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase): def _upload_with_helper(res): u = upload.Data(HELPER_DATA, contenthashkey=contenthashkey) d = self.extra_node.upload(u) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri return self.downloader.download_to_data(uri) d.addCallback(_uploaded) def _check(newdata): @@ -308,7 +310,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase): u = upload.Data(HELPER_DATA, contenthashkey=contenthashkey) u.debug_stash_RemoteEncryptedUploadable = True d = self.extra_node.upload(u) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri return self.downloader.download_to_data(uri) d.addCallback(_uploaded) def _check(newdata): @@ -392,7 +395,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, unittest.TestCase): return self.extra_node.upload(u2) d.addCallbacks(_upload_again) - def _uploaded(uri): + def _uploaded(results): + uri = results.uri log.msg("Second upload complete", level=log.NOISY, facility="tahoe.test.test_system") reu = u2.debug_RemoteEncryptedUploadable diff --git a/src/allmydata/test/test_upload.py b/src/allmydata/test/test_upload.py index 88670c21..1e135811 100644 --- a/src/allmydata/test/test_upload.py +++ b/src/allmydata/test/test_upload.py @@ -12,6 +12,9 @@ from foolscap import eventual MiB = 1024*1024 +def extract_uri(results): + return results.uri + class Uploadable(unittest.TestCase): def shouldEqual(self, data, expected): self.failUnless(isinstance(data, list)) @@ -209,18 +212,21 @@ class GoodServer(unittest.TestCase): def test_data_zero(self): data = self.get_data(SIZE_ZERO) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_ZERO) return d def test_data_small(self): data = self.get_data(SIZE_SMALL) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_SMALL) return d def test_data_large(self): data = self.get_data(SIZE_LARGE) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) return d @@ -230,24 +236,28 @@ class GoodServer(unittest.TestCase): # we want 3 segments, since that's not a power of two self.set_encoding_parameters(25, 75, 100, segsize) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) return d def test_filehandle_zero(self): data = self.get_data(SIZE_ZERO) d = upload_filehandle(self.u, StringIO(data)) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_ZERO) return d def test_filehandle_small(self): data = self.get_data(SIZE_SMALL) d = upload_filehandle(self.u, StringIO(data)) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_SMALL) return d def test_filehandle_large(self): data = self.get_data(SIZE_LARGE) d = upload_filehandle(self.u, StringIO(data)) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) return d @@ -258,6 +268,7 @@ class GoodServer(unittest.TestCase): f.write(data) f.close() d = upload_filename(self.u, fn) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_ZERO) return d @@ -268,6 +279,7 @@ class GoodServer(unittest.TestCase): f.write(data) f.close() d = upload_filename(self.u, fn) + d.addCallback(extract_uri) d.addCallback(self._check_small, SIZE_SMALL) return d @@ -278,6 +290,7 @@ class GoodServer(unittest.TestCase): f.write(data) f.close() d = upload_filename(self.u, fn) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) return d @@ -333,6 +346,7 @@ class PeerSelection(unittest.TestCase): data = self.get_data(SIZE_LARGE) self.set_encoding_parameters(25, 30, 50) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) def _check(res): for p in self.node.last_peers: @@ -350,6 +364,7 @@ class PeerSelection(unittest.TestCase): data = self.get_data(SIZE_LARGE) self.set_encoding_parameters(50, 75, 100) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) def _check(res): for p in self.node.last_peers: @@ -367,6 +382,7 @@ class PeerSelection(unittest.TestCase): data = self.get_data(SIZE_LARGE) self.set_encoding_parameters(24, 41, 51) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) def _check(res): got_one = [] @@ -394,6 +410,7 @@ class PeerSelection(unittest.TestCase): data = self.get_data(SIZE_LARGE) self.set_encoding_parameters(100, 150, 200) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) def _check(res): for p in self.node.last_peers: @@ -411,6 +428,7 @@ class PeerSelection(unittest.TestCase): data = self.get_data(SIZE_LARGE) self.set_encoding_parameters(3, 5, 10) d = upload_data(self.u, data) + d.addCallback(extract_uri) d.addCallback(self._check_large, SIZE_LARGE) def _check(res): counts = {} diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 374d336a..fa5ed141 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -5,7 +5,7 @@ from twisted.trial import unittest from twisted.internet import defer from twisted.web import client, error, http from twisted.python import failure, log -from allmydata import interfaces, provisioning, uri, webish +from allmydata import interfaces, provisioning, uri, webish, upload from allmydata.util import fileutil from allmydata.test.common import NonGridDirectoryNode, FakeCHKFileNode, FakeMutableFileNode, create_chk_filenode from allmydata.interfaces import IURI, INewDirectoryURI, IReadonlyNewDirectoryURI, IFileURI, IMutableFileURI, IMutableFileNode @@ -61,7 +61,9 @@ class FakeClient(service.MultiService): def _got_data(datav): data = "".join(datav) n = create_chk_filenode(self, data) - return n.get_uri() + results = upload.UploadResults() + results.uri = n.get_uri() + return results d.addCallback(_got_data) return d diff --git a/src/allmydata/upload.py b/src/allmydata/upload.py index 22b85c6e..659fb1b2 100644 --- a/src/allmydata/upload.py +++ b/src/allmydata/upload.py @@ -15,7 +15,7 @@ from allmydata.util.hashutil import file_renewal_secret_hash, \ from allmydata import encode, storage, hashtree, uri from allmydata.util import idlib, mathutil from allmydata.util.assertutil import precondition -from allmydata.interfaces import IUploadable, IUploader, \ +from allmydata.interfaces import IUploadable, IUploader, IUploadResults, \ IEncryptedUploadable, RIEncryptedUploadable from pycryptopp.cipher.aes import AES @@ -36,6 +36,9 @@ class HaveAllPeersError(Exception): class TooFullError(Exception): pass +class UploadResults: + implements(IUploadResults) + # our current uri_extension is 846 bytes for small files, a few bytes # more for larger ones (since the filesize is encoded in decimal in a # few places). Ask for a little bit more just in case we need it. If @@ -632,7 +635,9 @@ class CHKUploader: total_shares=total_shares, size=size, ) - return u.to_string() + results = UploadResults() + results.uri = u.to_string() + return results def read_this_many_bytes(uploadable, size, prepend_data=[]): @@ -666,8 +671,14 @@ class LiteralUploader: d.addCallback(lambda size: read_this_many_bytes(uploadable, size)) d.addCallback(lambda data: uri.LiteralFileURI("".join(data))) d.addCallback(lambda u: u.to_string()) + d.addCallback(self._build_results) return d + def _build_results(self, uri): + results = UploadResults() + results.uri = uri + return results + def close(self): pass @@ -838,7 +849,9 @@ class AssistedUploader: total_shares=self._total_shares, size=self._size, ) - return u.to_string() + results = UploadResults() + results.uri = u.to_string() + return results class NoParameterPreferencesMixin: max_segment_size = None diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py index bdfe2d61..f7989a80 100644 --- a/src/allmydata/webish.py +++ b/src/allmydata/webish.py @@ -797,7 +797,7 @@ class POSTHandler(rend.Page): # SDMF: files are small, and we can only upload data. contents.file.seek(0) data = contents.file.read() - uploadable = FileHandle(contents.file) + #uploadable = FileHandle(contents.file) d = self._check_replacement(name) d.addCallback(lambda res: self._node.has_child(name)) def _checked(present): @@ -1205,6 +1205,7 @@ class URIPUTHandler(rend.Page): # without the associated set_uri. uploadable = FileHandle(req.content) d = IClient(ctx).upload(uploadable) + d.addCallback(lambda results: results.uri) # that fires with the URI of the new file return d @@ -1231,6 +1232,7 @@ class URIPOSTHandler(rend.Page): fileobj = req.fields["file"].file uploadable = FileHandle(fileobj) d = IClient(ctx).upload(uploadable) + d.addCallback(lambda results: results.uri) # that fires with the URI of the new file return d