update URI format, include codec name

This commit is contained in:
Brian Warner 2007-01-16 21:29:59 -07:00
parent 9c6d190190
commit 4101bcf218
6 changed files with 52 additions and 22 deletions

View File

@ -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()

View File

@ -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

View File

@ -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():

View File

@ -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))

View File

@ -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])

25
src/allmydata/uri.py Normal file
View File

@ -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