Update the pieces to use base64 encoded binary
This commit is contained in:
parent
5c6e033d21
commit
ce8fcbeaae
4 changed files with 32 additions and 30 deletions
|
@ -9,7 +9,7 @@ from random import SystemRandom
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from peewee import *
|
from peewee import *
|
||||||
from data.read_slave import ReadSlaveModel
|
from data.read_slave import ReadSlaveModel
|
||||||
from data.fields import ResumableSHA256Field, ResumableSHA1Field, JSONField
|
from data.fields import ResumableSHA256Field, ResumableSHA1Field, JSONField, Base64BinaryField
|
||||||
from sqlalchemy.engine.url import make_url
|
from sqlalchemy.engine.url import make_url
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
@ -810,7 +810,7 @@ class BlobUpload(BaseModel):
|
||||||
uncompressed_byte_count = IntegerField(null=True)
|
uncompressed_byte_count = IntegerField(null=True)
|
||||||
created = DateTimeField(default=datetime.now, index=True)
|
created = DateTimeField(default=datetime.now, index=True)
|
||||||
piece_sha_state = ResumableSHA1Field(null=True, default=resumablehashlib.sha1)
|
piece_sha_state = ResumableSHA1Field(null=True, default=resumablehashlib.sha1)
|
||||||
piece_hashes = TextField(default='')
|
piece_hashes = Base64BinaryField(default='')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
database = db
|
database = db
|
||||||
|
@ -851,7 +851,7 @@ class QuayRelease(BaseModel):
|
||||||
class TorrentInfo(BaseModel):
|
class TorrentInfo(BaseModel):
|
||||||
storage = ForeignKeyField(ImageStorage)
|
storage = ForeignKeyField(ImageStorage)
|
||||||
piece_length = IntegerField()
|
piece_length = IntegerField()
|
||||||
pieces = TextField()
|
pieces = Base64BinaryField()
|
||||||
|
|
||||||
indexes = (
|
indexes = (
|
||||||
(('storage', 'piece_length'), True),
|
(('storage', 'piece_length'), True),
|
||||||
|
|
|
@ -5,7 +5,10 @@ import json
|
||||||
from peewee import TextField
|
from peewee import TextField
|
||||||
|
|
||||||
|
|
||||||
class ResumableSHA256Field(TextField):
|
class _ResumableSHAField(TextField):
|
||||||
|
def _create_sha(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def db_value(self, value):
|
def db_value(self, value):
|
||||||
sha_state = value.state()
|
sha_state = value.state()
|
||||||
|
|
||||||
|
@ -16,7 +19,7 @@ class ResumableSHA256Field(TextField):
|
||||||
return json.dumps(sha_state)
|
return json.dumps(sha_state)
|
||||||
|
|
||||||
def python_value(self, value):
|
def python_value(self, value):
|
||||||
to_resume = resumablehashlib.sha256()
|
to_resume = self._create_sha()
|
||||||
if value is None:
|
if value is None:
|
||||||
return to_resume
|
return to_resume
|
||||||
|
|
||||||
|
@ -28,27 +31,14 @@ class ResumableSHA256Field(TextField):
|
||||||
return to_resume
|
return to_resume
|
||||||
|
|
||||||
|
|
||||||
class ResumableSHA1Field(TextField):
|
class ResumableSHA256Field(_ResumableSHAField):
|
||||||
def db_value(self, value):
|
def _create_sha(self):
|
||||||
sha_state = value.state()
|
return resumablehashlib.sha256()
|
||||||
|
|
||||||
# One of the fields is a byte string, let's base64 encode it to make sure
|
|
||||||
# we can store and fetch it regardless of default collocation.
|
|
||||||
sha_state[3] = base64.b64encode(sha_state[3])
|
|
||||||
|
|
||||||
return json.dumps(sha_state)
|
class ResumableSHA1Field(_ResumableSHAField):
|
||||||
|
def _create_sha(self):
|
||||||
def python_value(self, value):
|
return resumablehashlib.sha1()
|
||||||
to_resume = resumablehashlib.sha1()
|
|
||||||
if value is None:
|
|
||||||
return to_resume
|
|
||||||
|
|
||||||
sha_state = json.loads(value)
|
|
||||||
|
|
||||||
# We need to base64 decode the data bytestring.
|
|
||||||
sha_state[3] = base64.b64decode(sha_state[3])
|
|
||||||
to_resume.set_state(sha_state)
|
|
||||||
return to_resume
|
|
||||||
|
|
||||||
|
|
||||||
class JSONField(TextField):
|
class JSONField(TextField):
|
||||||
|
@ -59,3 +49,15 @@ class JSONField(TextField):
|
||||||
if value is None or value == "":
|
if value is None or value == "":
|
||||||
return {}
|
return {}
|
||||||
return json.loads(value)
|
return json.loads(value)
|
||||||
|
|
||||||
|
|
||||||
|
class Base64BinaryField(TextField):
|
||||||
|
def db_value(self, value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return base64.b64encode(value)
|
||||||
|
|
||||||
|
def python_value(self, value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return base64.b64decode(value)
|
||||||
|
|
|
@ -294,8 +294,8 @@ def _finish_upload(namespace, repo_name, upload_obj, expected_digest):
|
||||||
upload_obj.uncompressed_byte_count)
|
upload_obj.uncompressed_byte_count)
|
||||||
|
|
||||||
if upload_obj.piece_sha_state is not None:
|
if upload_obj.piece_sha_state is not None:
|
||||||
piece_string = upload_obj.piece_hashes + upload_obj.piece_sha_state.hexdigest()
|
piece_bytes = upload_obj.piece_hashes + upload_obj.piece_sha_state.digest()
|
||||||
model.storage.save_torrent_info(blob_storage, app.config['TORRENT_PIECE_SIZE'], piece_string)
|
model.storage.save_torrent_info(blob_storage, app.config['TORRENT_PIECE_SIZE'], piece_bytes)
|
||||||
|
|
||||||
# Delete the upload tracking row.
|
# Delete the upload tracking row.
|
||||||
upload_obj.delete_instance()
|
upload_obj.delete_instance()
|
||||||
|
|
|
@ -2,7 +2,7 @@ import resumablehashlib
|
||||||
|
|
||||||
|
|
||||||
class PieceHasher(object):
|
class PieceHasher(object):
|
||||||
def __init__(self, piece_size, starting_offset, starting_piece_hash_str, hash_fragment_to_resume):
|
def __init__(self, piece_size, starting_offset, starting_piece_hash_bytes, hash_fragment_to_resume):
|
||||||
if not isinstance(starting_offset, (int, long)):
|
if not isinstance(starting_offset, (int, long)):
|
||||||
raise TypeError('starting_offset must be an integer')
|
raise TypeError('starting_offset must be an integer')
|
||||||
elif not isinstance(piece_size, (int, long)):
|
elif not isinstance(piece_size, (int, long)):
|
||||||
|
@ -11,7 +11,7 @@ class PieceHasher(object):
|
||||||
self._current_offset = starting_offset
|
self._current_offset = starting_offset
|
||||||
self._piece_size = piece_size
|
self._piece_size = piece_size
|
||||||
self._hash_fragment = hash_fragment_to_resume
|
self._hash_fragment = hash_fragment_to_resume
|
||||||
self._piece_hashes = [starting_piece_hash_str]
|
self._piece_hashes = bytearray(starting_piece_hash_bytes)
|
||||||
|
|
||||||
def update(self, buf):
|
def update(self, buf):
|
||||||
buf_offset = 0
|
buf_offset = 0
|
||||||
|
@ -21,7 +21,7 @@ class PieceHasher(object):
|
||||||
|
|
||||||
if self._piece_offset() == 0 and to_hash_len > 0 and self._current_offset > 0:
|
if self._piece_offset() == 0 and to_hash_len > 0 and self._current_offset > 0:
|
||||||
# We are opening a new piece
|
# We are opening a new piece
|
||||||
self._piece_hashes.append(self._hash_fragment.hexdigest())
|
self._piece_hashes.extend(self._hash_fragment.digest())
|
||||||
self._hash_fragment = resumablehashlib.sha1()
|
self._hash_fragment = resumablehashlib.sha1()
|
||||||
|
|
||||||
self._hash_fragment.update(buf_bytes_to_hash)
|
self._hash_fragment.update(buf_bytes_to_hash)
|
||||||
|
@ -36,7 +36,7 @@ class PieceHasher(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def piece_hashes(self):
|
def piece_hashes(self):
|
||||||
return ''.join(self._piece_hashes)
|
return self._piece_hashes
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hash_fragment(self):
|
def hash_fragment(self):
|
||||||
|
|
Reference in a new issue