update URI format, include codec name
This commit is contained in:
parent
9c6d190190
commit
4101bcf218
|
@ -12,7 +12,7 @@ def netstring(s):
|
||||||
|
|
||||||
class ReplicatingEncoder(object):
|
class ReplicatingEncoder(object):
|
||||||
implements(ICodecEncoder)
|
implements(ICodecEncoder)
|
||||||
ENCODER_TYPE = 0
|
ENCODER_TYPE = "rep"
|
||||||
|
|
||||||
def set_params(self, data_size, required_shares, max_shares):
|
def set_params(self, data_size, required_shares, max_shares):
|
||||||
self.data_size = data_size
|
self.data_size = data_size
|
||||||
|
@ -96,7 +96,7 @@ class Decoder(object):
|
||||||
|
|
||||||
class PyRSEncoder(object):
|
class PyRSEncoder(object):
|
||||||
implements(ICodecEncoder)
|
implements(ICodecEncoder)
|
||||||
ENCODER_TYPE = 1
|
ENCODER_TYPE = "pyrs"
|
||||||
|
|
||||||
# we will break the data into vectors in which each element is a single
|
# we will break the data into vectors in which each element is a single
|
||||||
# byte (i.e. a single number from 0 to 255), and the length of the vector
|
# byte (i.e. a single number from 0 to 255), and the length of the vector
|
||||||
|
@ -138,7 +138,7 @@ class PyRSEncoder(object):
|
||||||
return self.ENCODER_TYPE
|
return self.ENCODER_TYPE
|
||||||
|
|
||||||
def get_serialized_params(self):
|
def get_serialized_params(self):
|
||||||
return "%d:%d:%d" % (self.data_size, self.required_shares,
|
return "%d-%d-%d" % (self.data_size, self.required_shares,
|
||||||
self.max_shares)
|
self.max_shares)
|
||||||
|
|
||||||
def get_share_size(self):
|
def get_share_size(self):
|
||||||
|
@ -179,7 +179,7 @@ class PyRSDecoder(object):
|
||||||
implements(ICodecDecoder)
|
implements(ICodecDecoder)
|
||||||
|
|
||||||
def set_serialized_params(self, params):
|
def set_serialized_params(self, params):
|
||||||
pieces = params.split(":")
|
pieces = params.split("-")
|
||||||
self.data_size = int(pieces[0])
|
self.data_size = int(pieces[0])
|
||||||
self.required_shares = int(pieces[1])
|
self.required_shares = int(pieces[1])
|
||||||
self.max_shares = int(pieces[2])
|
self.max_shares = int(pieces[2])
|
||||||
|
@ -234,3 +234,8 @@ all_encoders = {
|
||||||
ReplicatingEncoder.ENCODER_TYPE: (ReplicatingEncoder, ReplicatingDecoder),
|
ReplicatingEncoder.ENCODER_TYPE: (ReplicatingEncoder, ReplicatingDecoder),
|
||||||
PyRSEncoder.ENCODER_TYPE: (PyRSEncoder, PyRSDecoder),
|
PyRSEncoder.ENCODER_TYPE: (PyRSEncoder, PyRSDecoder),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_decoder_by_name(name):
|
||||||
|
decoder_class = all_encoders[name][1]
|
||||||
|
return decoder_class()
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from twisted.application import service
|
||||||
from allmydata.util import idlib, bencode
|
from allmydata.util import idlib, bencode
|
||||||
from allmydata.util.deferredutil import DeferredListShouldSucceed
|
from allmydata.util.deferredutil import DeferredListShouldSucceed
|
||||||
from allmydata import codec
|
from allmydata import codec
|
||||||
|
from allmydata.uri import unpack_uri
|
||||||
|
|
||||||
class NotEnoughPeersError(Exception):
|
class NotEnoughPeersError(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -16,20 +17,17 @@ class HaveAllPeersError(Exception):
|
||||||
# we use this to jump out of the loop
|
# we use this to jump out of the loop
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def unpack_uri(uri):
|
|
||||||
assert uri.startswith("URI:")
|
|
||||||
return bencode.bdecode(uri[4:])
|
|
||||||
|
|
||||||
class FileDownloader:
|
class FileDownloader:
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
def __init__(self, peer, verifierid, encoding_params):
|
def __init__(self, peer, uri):
|
||||||
self._peer = peer
|
self._peer = peer
|
||||||
|
(codec_name, codec_params, verifierid) = unpack_uri(uri)
|
||||||
assert isinstance(verifierid, str)
|
assert isinstance(verifierid, str)
|
||||||
assert len(verifierid) == 20
|
assert len(verifierid) == 20
|
||||||
self._verifierid = verifierid
|
self._verifierid = verifierid
|
||||||
self._decoder = codec.ReplicatingDecoder()
|
self._decoder = codec.get_decoder_by_name(codec_name)
|
||||||
self._decoder.set_serialized_params(encoding_params)
|
self._decoder.set_serialized_params(codec_params)
|
||||||
self.needed_shares = self._decoder.get_required_shares()
|
self.needed_shares = self._decoder.get_required_shares()
|
||||||
|
|
||||||
def set_download_target(self, target):
|
def set_download_target(self, target):
|
||||||
|
@ -236,14 +234,12 @@ class Downloader(service.MultiService):
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
def download(self, uri, t):
|
def download(self, uri, t):
|
||||||
(verifierid, params) = unpack_uri(uri)
|
|
||||||
assert self.parent
|
assert self.parent
|
||||||
assert self.running
|
assert self.running
|
||||||
assert isinstance(verifierid, str)
|
|
||||||
t = IDownloadTarget(t)
|
t = IDownloadTarget(t)
|
||||||
assert t.write
|
assert t.write
|
||||||
assert t.close
|
assert t.close
|
||||||
dl = FileDownloader(self.parent, verifierid, params)
|
dl = FileDownloader(self.parent, uri)
|
||||||
dl.set_download_target(t)
|
dl.set_download_target(t)
|
||||||
if self.debug:
|
if self.debug:
|
||||||
dl.debug = True
|
dl.debug = True
|
||||||
|
|
|
@ -83,7 +83,7 @@ class ICodecEncoder(Interface):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_encoder_type():
|
def get_encoder_type():
|
||||||
"""Return an integer that describes the type of this encoder.
|
"""Return a short string that describes the type of this encoder.
|
||||||
|
|
||||||
There must be a global table of encoder classes. This method returns
|
There must be a global table of encoder classes. This method returns
|
||||||
an index into this table; the value at this index is an encoder
|
an index into this table; the value at this index is an encoder
|
||||||
|
@ -100,10 +100,11 @@ class ICodecEncoder(Interface):
|
||||||
|
|
||||||
This string is intended to be embedded in the URI, so there are
|
This string is intended to be embedded in the URI, so there are
|
||||||
several restrictions on its contents. At the moment I'm thinking that
|
several restrictions on its contents. At the moment I'm thinking that
|
||||||
this means it may contain hex digits and colons, and nothing else.
|
this means it may contain hex digits and hyphens, and nothing else.
|
||||||
The idea is that the URI contains '%d:%s.' %
|
The idea is that the URI contains something like '%s:%s:%s' %
|
||||||
(encoder.get_encoder_type(), encoder.get_serialized_params()), and
|
(encoder.get_encoder_name(), encoder.get_serialized_params(),
|
||||||
this is enough information to construct a compatible decoder.
|
b2a(verifierid)), and this is enough information to construct a
|
||||||
|
compatible decoder.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_share_size():
|
def get_share_size():
|
||||||
|
|
|
@ -4,6 +4,7 @@ from twisted.internet import defer
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
from allmydata import upload, download
|
from allmydata import upload, download
|
||||||
|
from allmydata.uri import unpack_uri
|
||||||
|
|
||||||
class StringBucketProxy:
|
class StringBucketProxy:
|
||||||
# This is for unit tests: make a StringIO look like a RIBucketWriter.
|
# This is for unit tests: make a StringIO look like a RIBucketWriter.
|
||||||
|
@ -226,10 +227,10 @@ class Uploader(unittest.TestCase):
|
||||||
def _check(self, uri):
|
def _check(self, uri):
|
||||||
self.failUnless(isinstance(uri, str))
|
self.failUnless(isinstance(uri, str))
|
||||||
self.failUnless(uri.startswith("URI:"))
|
self.failUnless(uri.startswith("URI:"))
|
||||||
verifierid, params = download.unpack_uri(uri)
|
codec_name, codec_params, verifierid = unpack_uri(uri)
|
||||||
self.failUnless(isinstance(verifierid, str))
|
self.failUnless(isinstance(verifierid, str))
|
||||||
self.failUnlessEqual(len(verifierid), 20)
|
self.failUnlessEqual(len(verifierid), 20)
|
||||||
self.failUnless(isinstance(params, str))
|
self.failUnless(isinstance(codec_params, str))
|
||||||
peers = self.node.peers
|
peers = self.node.peers
|
||||||
self.failUnlessEqual(peers[0].allocated_size,
|
self.failUnlessEqual(peers[0].allocated_size,
|
||||||
len(peers[0].data))
|
len(peers[0].data))
|
||||||
|
|
|
@ -9,6 +9,7 @@ from allmydata.util import idlib, bencode
|
||||||
from allmydata.util.idlib import peerid_to_short_string as shortid
|
from allmydata.util.idlib import peerid_to_short_string as shortid
|
||||||
from allmydata.util.deferredutil import DeferredListShouldSucceed
|
from allmydata.util.deferredutil import DeferredListShouldSucceed
|
||||||
from allmydata import codec
|
from allmydata import codec
|
||||||
|
from allmydata.uri import pack_uri
|
||||||
|
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
import sha
|
import sha
|
||||||
|
@ -67,6 +68,7 @@ class FileUploader:
|
||||||
total_shares = self.max_shares
|
total_shares = self.max_shares
|
||||||
needed_shares = self.min_shares
|
needed_shares = self.min_shares
|
||||||
self._encoder = codec.ReplicatingEncoder()
|
self._encoder = codec.ReplicatingEncoder()
|
||||||
|
self._codec_name = self._encoder.get_encoder_type()
|
||||||
self._encoder.set_params(self._size, needed_shares, total_shares)
|
self._encoder.set_params(self._size, needed_shares, total_shares)
|
||||||
self._share_size = self._encoder.get_share_size()
|
self._share_size = self._encoder.get_share_size()
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ class FileUploader:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _compute_uri(self, params):
|
def _compute_uri(self, params):
|
||||||
return "URI:%s" % bencode.bencode((self._verifierid, params))
|
return pack_uri(self._codec_name, params, self._verifierid)
|
||||||
|
|
||||||
def _build_not_enough_peers_error(self):
|
def _build_not_enough_peers_error(self):
|
||||||
yes = ",".join([shortid(p) for p in self.peers_who_said_yes])
|
yes = ",".join([shortid(p) for p in self.peers_who_said_yes])
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
from allmydata.util import bencode, idlib
|
||||||
|
|
||||||
|
# the URI shall be an ascii representation of the file. It shall contain
|
||||||
|
# enough information to retrieve and validate the contents. It shall be
|
||||||
|
# expressed in a limited character set (namely [TODO]).
|
||||||
|
|
||||||
|
def pack_uri(codec_name, codec_params, verifierid):
|
||||||
|
assert isinstance(codec_name, str)
|
||||||
|
assert len(codec_name) < 10
|
||||||
|
assert ":" not in codec_name
|
||||||
|
assert isinstance(codec_params, str)
|
||||||
|
assert ":" not in codec_params
|
||||||
|
assert isinstance(verifierid, str)
|
||||||
|
assert len(verifierid) == 20 # sha1 hash
|
||||||
|
return "URI:%s:%s:%s" % (codec_name, codec_params, idlib.b2a(verifierid))
|
||||||
|
|
||||||
|
|
||||||
|
def unpack_uri(uri):
|
||||||
|
assert uri.startswith("URI:")
|
||||||
|
header, codec_name, codec_params, verifierid_s = uri.split(":")
|
||||||
|
verifierid = idlib.a2b(verifierid_s)
|
||||||
|
return codec_name, codec_params, verifierid
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue