64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
import os
|
|
from blobsend.client_base import BaseChunkClient
|
|
from blobsend import CHUNK_SIZE, hash_chunk
|
|
|
|
|
|
class FileChunkClient(BaseChunkClient):
|
|
def __init__(self, fpath, chunk_size=CHUNK_SIZE):
|
|
super().__init__(chunk_size)
|
|
self.fpath = fpath
|
|
self.file = open(self.fpath, "ab+") # for get chunk operations, this generic file is used instead of doing lots of open/close
|
|
self.file.seek(0)
|
|
|
|
def get_hashes(self):
|
|
i = 0
|
|
with open(self.fpath, "rb+") as f:
|
|
while True:
|
|
data = f.read(self.chunk_size)
|
|
if not data:
|
|
break
|
|
yield (i, hash_chunk(data))
|
|
i += 1
|
|
|
|
def get_chunk(self, chunk_number):
|
|
"""
|
|
return a file handle from which CHUNK_SIZE bytes of data can be read
|
|
"""
|
|
position = chunk_number * self.chunk_size
|
|
if position > os.path.getsize(self.fpath):#TODO not sure if > or >=
|
|
raise Exception("requested chunk {} is beyond EOF".format(chunk_number))
|
|
self.file.seek(position)#TODO not thread safe
|
|
return self.file.read(self.chunk_size)
|
|
|
|
def put_chunk(self, chunk_number, contents):
|
|
"""
|
|
insert the data for chunk_number's position within the file, the content given by contents (which is a file-like object) lol not actually
|
|
"""
|
|
position = chunk_number * self.chunk_size
|
|
with open(self.fpath, "rb+") as f:
|
|
f.seek(position)
|
|
f.write(contents)
|
|
|
|
def get_length(self):
|
|
"""
|
|
get the file size
|
|
"""
|
|
self.file.seek(0, 2) # seek to end
|
|
return self.file.tell()
|
|
|
|
def set_length(self, length):
|
|
if length < self.get_length():
|
|
self.file.truncate(length)
|
|
# do nothing for the case of extending the file
|
|
# put_chunk handles it
|
|
|
|
def close(self):
|
|
self.file.close()
|
|
|
|
@staticmethod
|
|
def from_uri(uri, is_src):
|
|
"""
|
|
instantiate a client from the given uri
|
|
"""
|
|
return FileChunkClient(uri.path)
|