1
0
mirror of https://github.com/enpaul/kodak.git synced 2024-11-23 06:56:58 +00:00

Implement trivial functionality for image source endpoint

This commit is contained in:
Ethan Paul 2021-11-13 00:55:33 -05:00
parent 25b61a612c
commit d5267e51d9
No known key found for this signature in database
GPG Key ID: D0E2CBF1245E92BF
4 changed files with 33 additions and 6 deletions

View File

@ -31,6 +31,17 @@ class Checksum(NamedTuple):
"""Construct from a hashlib object"""
return cls(algorithm=data.name, digest=data.hexdigest())
def as_header(self) -> str:
"""Format the checksum for the Content-Digest HTTP header"""
if self.algorithm.startswith("sha"):
alg = f"sha-{self.algorithm[3:]}"
elif self.algorithm.startswith("id"):
alg = f"id-sha-{self.algorithm[3:]}"
else:
alg = self.algorithm
return f"{alg}={self.digest}"
class EnumField(peewee.CharField):
"""Custom field for storing enums"""

View File

@ -38,7 +38,7 @@ class ImageRecord(KodakModel):
hasher = hashlib.sha256()
view = memoryview(bytearray(1024 * 1024))
with path.open("rb", buffering=0) as infile:
for chunk in iter(lambda: infile.readinto(view), 0):
for chunk in iter(lambda: infile.readinto(view), 0): # type: ignore
hasher.update(view[:chunk])
name = path.stem

View File

@ -1,3 +1,8 @@
import datetime
import flask
from kodak import database
from kodak.resources._shared import authenticated
from kodak.resources._shared import KodakResource
from kodak.resources._shared import ResponseTuple
@ -9,9 +14,20 @@ class Image(KodakResource):
routes = ("/image/<string:image_name>",)
@authenticated
def get(self, image_name: str) -> ResponseTuple:
def get(self, image_name: str) -> flask.Response: # pylint: disable=no-self-use
"""Retrieve an original source image"""
raise NotImplementedError
with database.interface.atomic():
image = database.ImageRecord.get(database.ImageRecord.name == image_name)
resp = flask.send_file(
image.source,
cache_timeout=int(datetime.timedelta(days=365).total_seconds()),
add_etags=False,
)
resp.headers["Content-Digest"] = image.checksum.as_header()
return resp
def head(self, image_name: str) -> ResponseTuple:
"""Alias HEAD to GET"""

View File

@ -127,12 +127,12 @@ def build(config: Optional[configuration.KodakConfig] = None) -> None:
with database.interface.atomic():
for image in database.ImageRecord.select().where(
database.ImageRecord.deleted
== False # pylint: disable=singleton-comparison
database.ImageRecord.deleted # pylint: disable=singleton-comparison
== False
):
if config.expose_source:
logger.debug(f"Creating source link to {image.source}")
image.create_link(config)
else:
logger.debug(f"Removing source link to {image.source}")
image.delete_link(config)
image.remove_link(config)