2008-01-09 04:18:54 +00:00
|
|
|
|
2008-01-10 03:25:05 +00:00
|
|
|
from zope.interface import implements
|
|
|
|
from twisted.application import service
|
|
|
|
from foolscap import RemoteInterface, Referenceable
|
2008-01-10 00:58:47 +00:00
|
|
|
from foolscap.schema import DictOf, ChoiceOf, ListOf
|
2008-01-09 04:18:54 +00:00
|
|
|
from allmydata.interfaces import StorageIndex, Hash
|
2008-01-10 03:25:05 +00:00
|
|
|
from allmydata.util import hashutil
|
2008-01-09 04:18:54 +00:00
|
|
|
|
|
|
|
UploadResults = DictOf(str, str)
|
|
|
|
|
|
|
|
class RIEncryptedUploadable(RemoteInterface):
|
|
|
|
__remote_name__ = "RIEncryptedUploadable.tahoe.allmydata.com"
|
|
|
|
|
|
|
|
def get_size():
|
|
|
|
return int
|
|
|
|
|
|
|
|
def set_segment_size(segment_size=long):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def read_encrypted(offset=long, length=long):
|
|
|
|
return str
|
|
|
|
|
|
|
|
def get_plaintext_hashtree_leaves(first=int, last=int):
|
|
|
|
return ListOf(Hash)
|
|
|
|
|
|
|
|
def get_plaintext_hash():
|
|
|
|
return Hash
|
|
|
|
|
|
|
|
|
|
|
|
class RIUploadHelper(RemoteInterface):
|
|
|
|
__remote_name__ = "RIUploadHelper.tahoe.allmydata.com"
|
|
|
|
|
|
|
|
def upload(reader=RIEncryptedUploadable):
|
|
|
|
return UploadResults
|
|
|
|
|
|
|
|
|
|
|
|
class RIHelper(RemoteInterface):
|
|
|
|
__remote_name__ = "RIHelper.tahoe.allmydata.com"
|
|
|
|
|
|
|
|
def upload(si=StorageIndex):
|
|
|
|
"""See if a file with a given storage index needs uploading. The
|
|
|
|
helper will ask the appropriate storage servers to see if the file
|
|
|
|
has already been uploaded. If so, the helper will return a set of
|
|
|
|
'upload results' that includes whatever hashes are needed to build
|
|
|
|
the read-cap, and perhaps a truncated sharemap.
|
|
|
|
|
|
|
|
If the file has not yet been uploaded (or if it was only partially
|
|
|
|
uploaded), the helper will return an empty upload-results dictionary
|
|
|
|
and also an RIUploadHelper object that will take care of the upload
|
|
|
|
process. The client should call upload() on this object and pass it a
|
|
|
|
reference to an RIEncryptedUploadable object that will provide
|
|
|
|
ciphertext. When the upload is finished, the upload() method will
|
|
|
|
finish and return the upload results.
|
|
|
|
"""
|
|
|
|
return (UploadResults, ChoiceOf(RIUploadHelper, None))
|
|
|
|
|
2008-01-10 03:25:05 +00:00
|
|
|
|
|
|
|
class CHKUploadHelper(Referenceable):
|
|
|
|
"""I am the helper-server -side counterpart to AssistedUploader. I handle
|
|
|
|
peer selection, encoding, and share pushing. I read ciphertext from the
|
|
|
|
remote AssistedUploader.
|
|
|
|
"""
|
|
|
|
implements(RIUploadHelper)
|
|
|
|
|
|
|
|
def __init__(self, storage_index, helper):
|
|
|
|
self._finished = False
|
|
|
|
self._storage_index = storage_index
|
|
|
|
self._helper = helper
|
|
|
|
self._log_number = self._helper.log("CHKUploadHelper starting")
|
|
|
|
|
|
|
|
def log(self, msg, parent=None):
|
|
|
|
if parent is None:
|
|
|
|
parent = self._log_number
|
|
|
|
return self._client.log(msg, parent=parent)
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
# determine if we need to upload the file. If so, return ({},self) .
|
|
|
|
# If not, return (UploadResults,None) .
|
|
|
|
return ({'uri_extension_hash': hashutil.uri_extension_hash("")},self)
|
|
|
|
|
|
|
|
def remote_upload(self, reader):
|
|
|
|
# reader is an RIEncryptedUploadable. I am specified to return an
|
|
|
|
# UploadResults dictionary.
|
|
|
|
return {'uri_extension_hash': hashutil.uri_extension_hash("")}
|
|
|
|
|
|
|
|
def finished(self, res):
|
|
|
|
self._finished = True
|
|
|
|
self._helper.upload_finished(self._storage_index)
|
|
|
|
|
|
|
|
|
|
|
|
class Helper(Referenceable, service.MultiService):
|
|
|
|
implements(RIHelper)
|
|
|
|
# this is the non-distributed version. When we need to have multiple
|
|
|
|
# helpers, this object will query the farm to see if anyone has the
|
|
|
|
# storage_index of interest, and send the request off to them.
|
|
|
|
|
|
|
|
chk_upload_helper_class = CHKUploadHelper
|
|
|
|
|
|
|
|
def __init__(self, basedir):
|
|
|
|
self._basedir = basedir
|
|
|
|
self._active_uploads = {}
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
|
|
|
|
def log(self, msg, **kwargs):
|
|
|
|
if 'facility' not in kwargs:
|
|
|
|
kwargs['facility'] = "helper"
|
|
|
|
return self.parent.log(msg, **kwargs)
|
|
|
|
|
|
|
|
def remote_upload(self, storage_index):
|
|
|
|
# TODO: look on disk
|
|
|
|
if storage_index in self._active_uploads:
|
|
|
|
uh = self._active_uploads[storage_index]
|
|
|
|
else:
|
|
|
|
uh = CHKUploadHelper(storage_index, self)
|
|
|
|
self._active_uploads[storage_index] = uh
|
|
|
|
return uh.start()
|
|
|
|
|
|
|
|
def upload_finished(self, storage_index):
|
|
|
|
del self._active_uploads[storage_index]
|