diff options
author | Andrew Godwin | 2022-12-10 12:16:08 -0700 |
---|---|---|
committer | Andrew Godwin | 2022-12-10 12:16:08 -0700 |
commit | 3595af7bd239f3843aff3ae06df8932cff23173d (patch) | |
tree | 84b8a0432fb89f253808be11275e2f78fc57bf42 /mediaproxy | |
parent | 9a978786d4eac0139b5606e22c605450adbe7a12 (diff) | |
download | takahe-3595af7bd239f3843aff3ae06df8932cff23173d.tar.gz takahe-3595af7bd239f3843aff3ae06df8932cff23173d.tar.bz2 takahe-3595af7bd239f3843aff3ae06df8932cff23173d.zip |
Media proxy, caching and tuning docs
Fixes #67
Diffstat (limited to 'mediaproxy')
-rw-r--r-- | mediaproxy/__init__.py | 0 | ||||
-rw-r--r-- | mediaproxy/apps.py | 6 | ||||
-rw-r--r-- | mediaproxy/views.py | 101 |
3 files changed, 107 insertions, 0 deletions
diff --git a/mediaproxy/__init__.py b/mediaproxy/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mediaproxy/__init__.py diff --git a/mediaproxy/apps.py b/mediaproxy/apps.py new file mode 100644 index 0000000..6b87719 --- /dev/null +++ b/mediaproxy/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MediaproxyConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "mediaproxy" diff --git a/mediaproxy/views.py b/mediaproxy/views.py new file mode 100644 index 0000000..e799e8b --- /dev/null +++ b/mediaproxy/views.py @@ -0,0 +1,101 @@ +import httpx +from django.conf import settings +from django.core.cache import caches +from django.http import Http404, HttpResponse +from django.shortcuts import get_object_or_404 +from django.views.generic import View + +from activities.models import PostAttachment +from users.models import Identity + + +class BaseCacheView(View): + """ + Base class for caching remote content. + """ + + cache_name = "media" + item_timeout: int | None = None + + def get(self, request, **kwargs): + self.kwargs = kwargs + remote_url = self.get_remote_url() + cache = caches[self.cache_name] + cache_key = "proxy_" + remote_url + # See if it's already cached + cached_content = cache.get(cache_key) + if not cached_content: + # OK, fetch and cache it + try: + remote_response = httpx.get( + remote_url, + headers={"User-Agent": settings.TAKAHE_USER_AGENT}, + follow_redirects=True, + timeout=settings.SETUP.REMOTE_TIMEOUT, + ) + except (httpx.ConnectError, httpx.RequestError): + return HttpResponse(status=502) + if remote_response.status_code >= 400: + return HttpResponse(status=502) + # We got it - shove it into the cache + cached_content = { + "content": remote_response.content, + "mimetype": remote_response.headers.get( + "Content-Type", "application/octet-stream" + ), + } + cache.set(cache_key, cached_content, timeout=self.item_timeout) + return HttpResponse( + cached_content["content"], + headers={ + "Content-Type": cached_content["mimetype"], + }, + ) + + def get_remote_url(self): + raise NotImplementedError() + + +class IdentityIconCacheView(BaseCacheView): + """ + Caches identity icons (avatars) + """ + + cache_name = "avatars" + item_timeout = 86400 * 7 # One week + + def get_remote_url(self): + self.identity = get_object_or_404(Identity, pk=self.kwargs["identity_id"]) + if self.identity.local or not self.identity.image_uri: + raise Http404() + return self.identity.icon_uri + + +class IdentityImageCacheView(BaseCacheView): + """ + Caches identity profile header images + """ + + item_timeout = 86400 * 7 # One week + + def get_remote_url(self): + self.identity = get_object_or_404(Identity, pk=self.kwargs["identity_id"]) + if self.identity.local or not self.identity.image_uri: + raise Http404() + return self.identity.image_uri + + +class PostAttachmentCacheView(BaseCacheView): + """ + Caches post media (images only, videos should always be offloaded to remote) + """ + + item_timeout = 86400 * 7 # One week + + def get_remote_url(self): + self.post_attachment = get_object_or_404( + PostAttachment, pk=self.kwargs["attachment_id"] + ) + if not self.post_attachment.is_image(): + raise Http404() + return self.post_attachment.remote_url |