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
|
2008-01-10 04:25:47 +00:00
|
|
|
from twisted.internet import defer
|
|
|
|
from foolscap import Referenceable
|
|
|
|
from allmydata import upload, interfaces
|
2008-01-15 04:24:26 +00:00
|
|
|
from allmydata.util import idlib
|
2008-01-09 04:18:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-10 04:25:47 +00:00
|
|
|
class CHKUploadHelper(Referenceable, upload.CHKUploader):
|
2008-01-10 03:25:05 +00:00
|
|
|
"""I am the helper-server -side counterpart to AssistedUploader. I handle
|
|
|
|
peer selection, encoding, and share pushing. I read ciphertext from the
|
|
|
|
remote AssistedUploader.
|
|
|
|
"""
|
2008-01-11 11:53:37 +00:00
|
|
|
implements(interfaces.RICHKUploadHelper)
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
def __init__(self, storage_index, helper, log_number, options={}):
|
2008-01-10 03:25:05 +00:00
|
|
|
self._finished = False
|
|
|
|
self._storage_index = storage_index
|
|
|
|
self._helper = helper
|
2008-01-15 04:24:26 +00:00
|
|
|
upload_id = idlib.b2a(storage_index)[:6]
|
|
|
|
self._log_number = log_number
|
|
|
|
self._helper.log("CHKUploadHelper starting for SI %s" % upload_id,
|
|
|
|
parent=log_number)
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-10 04:25:47 +00:00
|
|
|
self._client = helper.parent
|
2008-01-15 04:24:26 +00:00
|
|
|
self._options = options
|
|
|
|
self._readers = []
|
2008-01-10 04:25:47 +00:00
|
|
|
|
|
|
|
self.set_params( (3,7,10) ) # GACK
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
def log(self, *args, **kwargs):
|
|
|
|
if 'facility' not in kwargs:
|
|
|
|
kwargs['facility'] = "tahoe.helper"
|
|
|
|
return upload.CHKUploader.log(self, *args, **kwargs)
|
|
|
|
|
2008-01-10 03:25:05 +00:00
|
|
|
def start(self):
|
|
|
|
# determine if we need to upload the file. If so, return ({},self) .
|
|
|
|
# If not, return (UploadResults,None) .
|
2008-01-11 11:53:37 +00:00
|
|
|
#return ({'uri_extension_hash': hashutil.uri_extension_hash("")},self)
|
|
|
|
return ({}, self)
|
2008-01-10 03:25:05 +00:00
|
|
|
|
|
|
|
def remote_upload(self, reader):
|
|
|
|
# reader is an RIEncryptedUploadable. I am specified to return an
|
|
|
|
# UploadResults dictionary.
|
2008-01-10 04:25:47 +00:00
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
self._readers.append(reader)
|
|
|
|
reader.notifyOnDisconnect(self._remove_reader, reader)
|
2008-01-10 04:25:47 +00:00
|
|
|
eu = CiphertextReader(reader, self._storage_index)
|
|
|
|
d = self.start_encrypted(eu)
|
|
|
|
def _done(res):
|
2008-01-11 11:53:37 +00:00
|
|
|
self.finished(self._storage_index)
|
2008-01-10 04:25:47 +00:00
|
|
|
(uri_extension_hash, needed_shares, total_shares, size) = res
|
|
|
|
return {'uri_extension_hash': uri_extension_hash}
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
def _remove_reader(self, reader):
|
|
|
|
# NEEDS MORE
|
|
|
|
self._readers.remove(reader)
|
|
|
|
if not self._readers:
|
|
|
|
if not self._finished:
|
|
|
|
self.finished(None)
|
|
|
|
|
2008-01-10 03:25:05 +00:00
|
|
|
def finished(self, res):
|
|
|
|
self._finished = True
|
|
|
|
self._helper.upload_finished(self._storage_index)
|
|
|
|
|
2008-01-10 04:25:47 +00:00
|
|
|
class CiphertextReader:
|
|
|
|
implements(interfaces.IEncryptedUploadable)
|
|
|
|
|
|
|
|
def __init__(self, remote_reader, storage_index):
|
|
|
|
self.rr = remote_reader
|
|
|
|
self.storage_index = storage_index
|
2008-01-11 12:42:55 +00:00
|
|
|
self._offset = 0
|
2008-01-10 04:25:47 +00:00
|
|
|
|
|
|
|
def get_size(self):
|
|
|
|
return self.rr.callRemote("get_size")
|
|
|
|
def get_storage_index(self):
|
|
|
|
return defer.succeed(self.storage_index)
|
|
|
|
def set_segment_size(self, segment_size):
|
|
|
|
return self.rr.callRemote("set_segment_size", segment_size)
|
|
|
|
def set_serialized_encoding_parameters(self, params):
|
|
|
|
pass # ??
|
|
|
|
def read_encrypted(self, length):
|
2008-01-11 12:42:55 +00:00
|
|
|
d = self.rr.callRemote("read_encrypted", self._offset, length)
|
|
|
|
def _done(strings):
|
|
|
|
self._offset += sum([len(data) for data in strings])
|
|
|
|
return strings
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
2008-01-10 04:25:47 +00:00
|
|
|
def get_plaintext_hashtree_leaves(self, first, last, num_segments):
|
|
|
|
return self.rr.callRemote("get_plaintext_hashtree_leaves",
|
|
|
|
first, last, num_segments)
|
|
|
|
def get_plaintext_hash(self):
|
|
|
|
return self.rr.callRemote("get_plaintext_hash")
|
|
|
|
def close(self):
|
|
|
|
# ??
|
|
|
|
return self.rr.callRemote("close")
|
|
|
|
|
2008-01-10 03:25:05 +00:00
|
|
|
|
|
|
|
class Helper(Referenceable, service.MultiService):
|
2008-01-10 04:25:47 +00:00
|
|
|
implements(interfaces.RIHelper)
|
2008-01-10 03:25:05 +00:00
|
|
|
# this is the non-distributed version. When we need to have multiple
|
2008-01-11 11:53:37 +00:00
|
|
|
# helpers, this object will become the HelperCoordinator, and will query
|
|
|
|
# the farm of Helpers to see if anyone has the storage_index of interest,
|
|
|
|
# and send the request off to them. If nobody has it, we'll choose a
|
|
|
|
# helper at random.
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
name = "helper"
|
2008-01-10 03:25:05 +00:00
|
|
|
chk_upload_helper_class = CHKUploadHelper
|
|
|
|
|
|
|
|
def __init__(self, basedir):
|
|
|
|
self._basedir = basedir
|
2008-01-15 04:24:26 +00:00
|
|
|
self._chk_options = {}
|
2008-01-10 03:25:05 +00:00
|
|
|
self._active_uploads = {}
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
|
2008-01-15 04:24:26 +00:00
|
|
|
def log(self, *args, **kwargs):
|
2008-01-10 03:25:05 +00:00
|
|
|
if 'facility' not in kwargs:
|
2008-01-15 04:24:26 +00:00
|
|
|
kwargs['facility'] = "tahoe.helper"
|
|
|
|
return self.parent.log(*args, **kwargs)
|
2008-01-10 03:25:05 +00:00
|
|
|
|
2008-01-11 11:53:37 +00:00
|
|
|
def remote_upload_chk(self, storage_index):
|
2008-01-15 04:24:26 +00:00
|
|
|
lp = self.log(format="helper: upload_chk query for SI %(si)s",
|
|
|
|
si=idlib.b2a(storage_index))
|
2008-01-10 03:25:05 +00:00
|
|
|
# TODO: look on disk
|
|
|
|
if storage_index in self._active_uploads:
|
2008-01-15 04:24:26 +00:00
|
|
|
self.log("upload is currently active", parent=lp)
|
2008-01-10 03:25:05 +00:00
|
|
|
uh = self._active_uploads[storage_index]
|
|
|
|
else:
|
2008-01-15 04:24:26 +00:00
|
|
|
self.log("creating new upload helper", parent=lp)
|
|
|
|
uh = self.chk_upload_helper_class(storage_index, self, lp,
|
|
|
|
self._chk_options)
|
2008-01-10 03:25:05 +00:00
|
|
|
self._active_uploads[storage_index] = uh
|
|
|
|
return uh.start()
|
|
|
|
|
|
|
|
def upload_finished(self, storage_index):
|
|
|
|
del self._active_uploads[storage_index]
|