Convert media repo's FileInfo to attrs. (#10785)

This is mostly an internal change, but improves type hints in the
media code.
This commit is contained in:
Patrick Cloke 2021-09-14 07:09:38 -04:00 committed by GitHub
parent 319b8b6bef
commit b996782df5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 138 additions and 106 deletions

1
changelog.d/10785.misc Normal file
View file

@ -0,0 +1 @@
Convert the internal `FileInfo` class to attrs and add type hints.

View file

@ -18,6 +18,8 @@ import os
import urllib import urllib
from typing import Awaitable, Dict, Generator, List, Optional, Tuple from typing import Awaitable, Dict, Generator, List, Optional, Tuple
import attr
from twisted.internet.interfaces import IConsumer from twisted.internet.interfaces import IConsumer
from twisted.protocols.basic import FileSender from twisted.protocols.basic import FileSender
from twisted.web.server import Request from twisted.web.server import Request
@ -287,44 +289,62 @@ class Responder:
pass pass
@attr.s(slots=True, frozen=True, auto_attribs=True)
class ThumbnailInfo:
"""Details about a generated thumbnail."""
width: int
height: int
method: str
# Content type of thumbnail, e.g. image/png
type: str
# The size of the media file, in bytes.
length: Optional[int] = None
@attr.s(slots=True, frozen=True, auto_attribs=True)
class FileInfo: class FileInfo:
"""Details about a requested/uploaded file. """Details about a requested/uploaded file."""
Attributes: # The server name where the media originated from, or None if local.
server_name (str): The server name where the media originated from, server_name: Optional[str]
or None if local. # The local ID of the file. For local files this is the same as the media_id
file_id (str): The local ID of the file. For local files this is the file_id: str
same as the media_id # If the file is for the url preview cache
url_cache (bool): If the file is for the url preview cache url_cache: bool = False
thumbnail (bool): Whether the file is a thumbnail or not. # Whether the file is a thumbnail or not.
thumbnail_width (int) thumbnail: Optional[ThumbnailInfo] = None
thumbnail_height (int)
thumbnail_method (str)
thumbnail_type (str): Content type of thumbnail, e.g. image/png
thumbnail_length (int): The size of the media file, in bytes.
"""
def __init__( # The below properties exist to maintain compatibility with third-party modules.
self, @property
server_name, def thumbnail_width(self):
file_id, if not self.thumbnail:
url_cache=False, return None
thumbnail=False, return self.thumbnail.width
thumbnail_width=None,
thumbnail_height=None, @property
thumbnail_method=None, def thumbnail_height(self):
thumbnail_type=None, if not self.thumbnail:
thumbnail_length=None, return None
): return self.thumbnail.height
self.server_name = server_name
self.file_id = file_id @property
self.url_cache = url_cache def thumbnail_method(self):
self.thumbnail = thumbnail if not self.thumbnail:
self.thumbnail_width = thumbnail_width return None
self.thumbnail_height = thumbnail_height return self.thumbnail.method
self.thumbnail_method = thumbnail_method
self.thumbnail_type = thumbnail_type @property
self.thumbnail_length = thumbnail_length def thumbnail_type(self):
if not self.thumbnail:
return None
return self.thumbnail.type
@property
def thumbnail_length(self):
if not self.thumbnail:
return None
return self.thumbnail.length
def get_filename_from_headers(headers: Dict[bytes, List[bytes]]) -> Optional[str]: def get_filename_from_headers(headers: Dict[bytes, List[bytes]]) -> Optional[str]:

View file

@ -42,6 +42,7 @@ from synapse.util.stringutils import random_string
from ._base import ( from ._base import (
FileInfo, FileInfo,
Responder, Responder,
ThumbnailInfo,
get_filename_from_headers, get_filename_from_headers,
respond_404, respond_404,
respond_with_responder, respond_with_responder,
@ -210,7 +211,7 @@ class MediaRepository:
upload_name = name if name else media_info["upload_name"] upload_name = name if name else media_info["upload_name"]
url_cache = media_info["url_cache"] url_cache = media_info["url_cache"]
file_info = FileInfo(None, media_id, url_cache=url_cache) file_info = FileInfo(None, media_id, url_cache=bool(url_cache))
responder = await self.media_storage.fetch_media(file_info) responder = await self.media_storage.fetch_media(file_info)
await respond_with_responder( await respond_with_responder(
@ -514,7 +515,7 @@ class MediaRepository:
t_height: int, t_height: int,
t_method: str, t_method: str,
t_type: str, t_type: str,
url_cache: Optional[str], url_cache: bool,
) -> Optional[str]: ) -> Optional[str]:
input_path = await self.media_storage.ensure_media_is_in_local_cache( input_path = await self.media_storage.ensure_media_is_in_local_cache(
FileInfo(None, media_id, url_cache=url_cache) FileInfo(None, media_id, url_cache=url_cache)
@ -548,11 +549,12 @@ class MediaRepository:
server_name=None, server_name=None,
file_id=media_id, file_id=media_id,
url_cache=url_cache, url_cache=url_cache,
thumbnail=True, thumbnail=ThumbnailInfo(
thumbnail_width=t_width, width=t_width,
thumbnail_height=t_height, height=t_height,
thumbnail_method=t_method, method=t_method,
thumbnail_type=t_type, type=t_type,
),
) )
output_path = await self.media_storage.store_file( output_path = await self.media_storage.store_file(
@ -585,7 +587,7 @@ class MediaRepository:
t_type: str, t_type: str,
) -> Optional[str]: ) -> Optional[str]:
input_path = await self.media_storage.ensure_media_is_in_local_cache( input_path = await self.media_storage.ensure_media_is_in_local_cache(
FileInfo(server_name, file_id, url_cache=False) FileInfo(server_name, file_id)
) )
try: try:
@ -616,11 +618,12 @@ class MediaRepository:
file_info = FileInfo( file_info = FileInfo(
server_name=server_name, server_name=server_name,
file_id=file_id, file_id=file_id,
thumbnail=True, thumbnail=ThumbnailInfo(
thumbnail_width=t_width, width=t_width,
thumbnail_height=t_height, height=t_height,
thumbnail_method=t_method, method=t_method,
thumbnail_type=t_type, type=t_type,
),
) )
output_path = await self.media_storage.store_file( output_path = await self.media_storage.store_file(
@ -742,12 +745,13 @@ class MediaRepository:
file_info = FileInfo( file_info = FileInfo(
server_name=server_name, server_name=server_name,
file_id=file_id, file_id=file_id,
thumbnail=True,
thumbnail_width=t_width,
thumbnail_height=t_height,
thumbnail_method=t_method,
thumbnail_type=t_type,
url_cache=url_cache, url_cache=url_cache,
thumbnail=ThumbnailInfo(
width=t_width,
height=t_height,
method=t_method,
type=t_type,
),
) )
with self.media_storage.store_into_file(file_info) as (f, fname, finish): with self.media_storage.store_into_file(file_info) as (f, fname, finish):

View file

@ -176,9 +176,9 @@ class MediaStorage:
self.filepaths.remote_media_thumbnail_rel_legacy( self.filepaths.remote_media_thumbnail_rel_legacy(
server_name=file_info.server_name, server_name=file_info.server_name,
file_id=file_info.file_id, file_id=file_info.file_id,
width=file_info.thumbnail_width, width=file_info.thumbnail.width,
height=file_info.thumbnail_height, height=file_info.thumbnail.height,
content_type=file_info.thumbnail_type, content_type=file_info.thumbnail.type,
) )
) )
@ -220,9 +220,9 @@ class MediaStorage:
legacy_path = self.filepaths.remote_media_thumbnail_rel_legacy( legacy_path = self.filepaths.remote_media_thumbnail_rel_legacy(
server_name=file_info.server_name, server_name=file_info.server_name,
file_id=file_info.file_id, file_id=file_info.file_id,
width=file_info.thumbnail_width, width=file_info.thumbnail.width,
height=file_info.thumbnail_height, height=file_info.thumbnail.height,
content_type=file_info.thumbnail_type, content_type=file_info.thumbnail.type,
) )
legacy_local_path = os.path.join(self.local_media_directory, legacy_path) legacy_local_path = os.path.join(self.local_media_directory, legacy_path)
if os.path.exists(legacy_local_path): if os.path.exists(legacy_local_path):
@ -255,10 +255,10 @@ class MediaStorage:
if file_info.thumbnail: if file_info.thumbnail:
return self.filepaths.url_cache_thumbnail_rel( return self.filepaths.url_cache_thumbnail_rel(
media_id=file_info.file_id, media_id=file_info.file_id,
width=file_info.thumbnail_width, width=file_info.thumbnail.width,
height=file_info.thumbnail_height, height=file_info.thumbnail.height,
content_type=file_info.thumbnail_type, content_type=file_info.thumbnail.type,
method=file_info.thumbnail_method, method=file_info.thumbnail.method,
) )
return self.filepaths.url_cache_filepath_rel(file_info.file_id) return self.filepaths.url_cache_filepath_rel(file_info.file_id)
@ -267,10 +267,10 @@ class MediaStorage:
return self.filepaths.remote_media_thumbnail_rel( return self.filepaths.remote_media_thumbnail_rel(
server_name=file_info.server_name, server_name=file_info.server_name,
file_id=file_info.file_id, file_id=file_info.file_id,
width=file_info.thumbnail_width, width=file_info.thumbnail.width,
height=file_info.thumbnail_height, height=file_info.thumbnail.height,
content_type=file_info.thumbnail_type, content_type=file_info.thumbnail.type,
method=file_info.thumbnail_method, method=file_info.thumbnail.method,
) )
return self.filepaths.remote_media_filepath_rel( return self.filepaths.remote_media_filepath_rel(
file_info.server_name, file_info.file_id file_info.server_name, file_info.file_id
@ -279,10 +279,10 @@ class MediaStorage:
if file_info.thumbnail: if file_info.thumbnail:
return self.filepaths.local_media_thumbnail_rel( return self.filepaths.local_media_thumbnail_rel(
media_id=file_info.file_id, media_id=file_info.file_id,
width=file_info.thumbnail_width, width=file_info.thumbnail.width,
height=file_info.thumbnail_height, height=file_info.thumbnail.height,
content_type=file_info.thumbnail_type, content_type=file_info.thumbnail.type,
method=file_info.thumbnail_method, method=file_info.thumbnail.method,
) )
return self.filepaths.local_media_filepath_rel(file_info.file_id) return self.filepaths.local_media_filepath_rel(file_info.file_id)

View file

@ -26,6 +26,7 @@ from synapse.rest.media.v1.media_storage import MediaStorage
from ._base import ( from ._base import (
FileInfo, FileInfo,
ThumbnailInfo,
parse_media_id, parse_media_id,
respond_404, respond_404,
respond_with_file, respond_with_file,
@ -114,7 +115,7 @@ class ThumbnailResource(DirectServeJsonResource):
thumbnail_infos, thumbnail_infos,
media_id, media_id,
media_id, media_id,
url_cache=media_info["url_cache"], url_cache=bool(media_info["url_cache"]),
server_name=None, server_name=None,
) )
@ -149,11 +150,12 @@ class ThumbnailResource(DirectServeJsonResource):
server_name=None, server_name=None,
file_id=media_id, file_id=media_id,
url_cache=media_info["url_cache"], url_cache=media_info["url_cache"],
thumbnail=True, thumbnail=ThumbnailInfo(
thumbnail_width=info["thumbnail_width"], width=info["thumbnail_width"],
thumbnail_height=info["thumbnail_height"], height=info["thumbnail_height"],
thumbnail_type=info["thumbnail_type"], type=info["thumbnail_type"],
thumbnail_method=info["thumbnail_method"], method=info["thumbnail_method"],
),
) )
t_type = file_info.thumbnail_type t_type = file_info.thumbnail_type
@ -173,7 +175,7 @@ class ThumbnailResource(DirectServeJsonResource):
desired_height, desired_height,
desired_method, desired_method,
desired_type, desired_type,
url_cache=media_info["url_cache"], url_cache=bool(media_info["url_cache"]),
) )
if file_path: if file_path:
@ -210,11 +212,12 @@ class ThumbnailResource(DirectServeJsonResource):
file_info = FileInfo( file_info = FileInfo(
server_name=server_name, server_name=server_name,
file_id=media_info["filesystem_id"], file_id=media_info["filesystem_id"],
thumbnail=True, thumbnail=ThumbnailInfo(
thumbnail_width=info["thumbnail_width"], width=info["thumbnail_width"],
thumbnail_height=info["thumbnail_height"], height=info["thumbnail_height"],
thumbnail_type=info["thumbnail_type"], type=info["thumbnail_type"],
thumbnail_method=info["thumbnail_method"], method=info["thumbnail_method"],
),
) )
t_type = file_info.thumbnail_type t_type = file_info.thumbnail_type
@ -271,7 +274,7 @@ class ThumbnailResource(DirectServeJsonResource):
thumbnail_infos, thumbnail_infos,
media_id, media_id,
media_info["filesystem_id"], media_info["filesystem_id"],
url_cache=None, url_cache=False,
server_name=server_name, server_name=server_name,
) )
@ -285,7 +288,7 @@ class ThumbnailResource(DirectServeJsonResource):
thumbnail_infos: List[Dict[str, Any]], thumbnail_infos: List[Dict[str, Any]],
media_id: str, media_id: str,
file_id: str, file_id: str,
url_cache: Optional[str] = None, url_cache: bool,
server_name: Optional[str] = None, server_name: Optional[str] = None,
) -> None: ) -> None:
""" """
@ -299,7 +302,7 @@ class ThumbnailResource(DirectServeJsonResource):
desired_type: The desired content-type of the thumbnail. desired_type: The desired content-type of the thumbnail.
thumbnail_infos: A list of dictionaries of candidate thumbnails. thumbnail_infos: A list of dictionaries of candidate thumbnails.
file_id: The ID of the media that a thumbnail is being requested for. file_id: The ID of the media that a thumbnail is being requested for.
url_cache: The URL cache value. url_cache: True if this is from a URL cache.
server_name: The server name, if this is a remote thumbnail. server_name: The server name, if this is a remote thumbnail.
""" """
if thumbnail_infos: if thumbnail_infos:
@ -318,13 +321,16 @@ class ThumbnailResource(DirectServeJsonResource):
respond_404(request) respond_404(request)
return return
# The thumbnail property must exist.
assert file_info.thumbnail is not None
responder = await self.media_storage.fetch_media(file_info) responder = await self.media_storage.fetch_media(file_info)
if responder: if responder:
await respond_with_responder( await respond_with_responder(
request, request,
responder, responder,
file_info.thumbnail_type, file_info.thumbnail.type,
file_info.thumbnail_length, file_info.thumbnail.length,
) )
return return
@ -351,18 +357,18 @@ class ThumbnailResource(DirectServeJsonResource):
server_name, server_name,
file_id=file_id, file_id=file_id,
media_id=media_id, media_id=media_id,
t_width=file_info.thumbnail_width, t_width=file_info.thumbnail.width,
t_height=file_info.thumbnail_height, t_height=file_info.thumbnail.height,
t_method=file_info.thumbnail_method, t_method=file_info.thumbnail.method,
t_type=file_info.thumbnail_type, t_type=file_info.thumbnail.type,
) )
else: else:
await self.media_repo.generate_local_exact_thumbnail( await self.media_repo.generate_local_exact_thumbnail(
media_id=media_id, media_id=media_id,
t_width=file_info.thumbnail_width, t_width=file_info.thumbnail.width,
t_height=file_info.thumbnail_height, t_height=file_info.thumbnail.height,
t_method=file_info.thumbnail_method, t_method=file_info.thumbnail.method,
t_type=file_info.thumbnail_type, t_type=file_info.thumbnail.type,
url_cache=url_cache, url_cache=url_cache,
) )
@ -370,8 +376,8 @@ class ThumbnailResource(DirectServeJsonResource):
await respond_with_responder( await respond_with_responder(
request, request,
responder, responder,
file_info.thumbnail_type, file_info.thumbnail.type,
file_info.thumbnail_length, file_info.thumbnail.length,
) )
else: else:
logger.info("Failed to find any generated thumbnails") logger.info("Failed to find any generated thumbnails")
@ -385,7 +391,7 @@ class ThumbnailResource(DirectServeJsonResource):
desired_type: str, desired_type: str,
thumbnail_infos: List[Dict[str, Any]], thumbnail_infos: List[Dict[str, Any]],
file_id: str, file_id: str,
url_cache: Optional[str], url_cache: bool,
server_name: Optional[str], server_name: Optional[str],
) -> Optional[FileInfo]: ) -> Optional[FileInfo]:
""" """
@ -398,7 +404,7 @@ class ThumbnailResource(DirectServeJsonResource):
desired_type: The desired content-type of the thumbnail. desired_type: The desired content-type of the thumbnail.
thumbnail_infos: A list of dictionaries of candidate thumbnails. thumbnail_infos: A list of dictionaries of candidate thumbnails.
file_id: The ID of the media that a thumbnail is being requested for. file_id: The ID of the media that a thumbnail is being requested for.
url_cache: The URL cache value. url_cache: True if this is from a URL cache.
server_name: The server name, if this is a remote thumbnail. server_name: The server name, if this is a remote thumbnail.
Returns: Returns:
@ -495,12 +501,13 @@ class ThumbnailResource(DirectServeJsonResource):
file_id=file_id, file_id=file_id,
url_cache=url_cache, url_cache=url_cache,
server_name=server_name, server_name=server_name,
thumbnail=True, thumbnail=ThumbnailInfo(
thumbnail_width=thumbnail_info["thumbnail_width"], width=thumbnail_info["thumbnail_width"],
thumbnail_height=thumbnail_info["thumbnail_height"], height=thumbnail_info["thumbnail_height"],
thumbnail_type=thumbnail_info["thumbnail_type"], type=thumbnail_info["thumbnail_type"],
thumbnail_method=thumbnail_info["thumbnail_method"], method=thumbnail_info["thumbnail_method"],
thumbnail_length=thumbnail_info["thumbnail_length"], length=thumbnail_info["thumbnail_length"],
),
) )
# No matching thumbnail was found. # No matching thumbnail was found.