fix: timeout on spa manifest requests
The previous behaviour had a loop of requests between the front app and the api when querying the pwa manifest. This reduce the coupling around the pwa manifest file between the api and the front app, by uplicating the files so each "service" has a copy of it, while keeping them in sync and having the front pwa manifest as single source of truth. Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale/-/merge_requests/2291>
This commit is contained in:
parent
6abecfc904
commit
b359bb6498
|
@ -62,3 +62,13 @@ repos:
|
|||
rev: v0.8.0.4
|
||||
hooks:
|
||||
- id: shellcheck
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: pwa-manifest.json
|
||||
name: pwa-manifest.json
|
||||
description: Sync pwa-manifest.json
|
||||
entry: scripts/sync-pwa-manifest.sh
|
||||
pass_filenames: false
|
||||
language: script
|
||||
files: pwa-manifest.json$
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "Funkwhale",
|
||||
"categories": ["music", "entertainment"],
|
||||
"short_name": "Funkwhale",
|
||||
"description": "Your free and federated audio platform",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"url": "https://play.google.com/store/apps/details?id=audio.funkwhale.ffa",
|
||||
"id": "audio.funkwhale.ffa"
|
||||
},
|
||||
{
|
||||
"platform": "f-droid",
|
||||
"url": "https://f-droid.org/en/packages/audio.funkwhale.ffa/",
|
||||
"id": "audio.funkwhale.ffa"
|
||||
}
|
||||
],
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Search",
|
||||
"url": "/search",
|
||||
"icons": []
|
||||
},
|
||||
{
|
||||
"name": "Library",
|
||||
"url": "/library",
|
||||
"icons": []
|
||||
},
|
||||
{
|
||||
"name": "Channels",
|
||||
"url": "/subscriptions",
|
||||
"icons": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from cache_memoize import cache_memoize
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
|
@ -14,7 +14,7 @@ from rest_framework import generics, views
|
|||
from rest_framework.response import Response
|
||||
|
||||
from funkwhale_api import __version__ as funkwhale_version
|
||||
from funkwhale_api.common import middleware, preferences
|
||||
from funkwhale_api.common import preferences
|
||||
from funkwhale_api.common.renderers import ActivityStreamRenderer
|
||||
from funkwhale_api.federation.actors import get_service_actor
|
||||
from funkwhale_api.federation.models import Domain
|
||||
|
@ -118,6 +118,10 @@ class NodeInfo(views.APIView):
|
|||
)
|
||||
|
||||
|
||||
PWA_MANIFEST_PATH = Path(__file__).parent / "pwa-manifest.json"
|
||||
PWA_MANIFEST: dict = json.loads(PWA_MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
class SpaManifest(generics.GenericAPIView):
|
||||
permission_classes = []
|
||||
authentication_classes = []
|
||||
|
@ -126,18 +130,15 @@ class SpaManifest(generics.GenericAPIView):
|
|||
|
||||
@extend_schema(operation_id="get_spa_manifest")
|
||||
def get(self, request):
|
||||
existing_manifest = middleware.get_spa_file(
|
||||
settings.FUNKWHALE_SPA_HTML_ROOT, "manifest.json"
|
||||
)
|
||||
parsed_manifest = json.loads(existing_manifest)
|
||||
manifest = PWA_MANIFEST.copy()
|
||||
instance_name = preferences.get("instance__name")
|
||||
if instance_name:
|
||||
parsed_manifest["short_name"] = instance_name
|
||||
parsed_manifest["name"] = instance_name
|
||||
manifest["short_name"] = instance_name
|
||||
manifest["name"] = instance_name
|
||||
instance_description = preferences.get("instance__short_description")
|
||||
if instance_description:
|
||||
parsed_manifest["description"] = instance_description
|
||||
serializer = self.get_serializer(parsed_manifest)
|
||||
manifest["description"] = instance_description
|
||||
serializer = self.get_serializer(manifest)
|
||||
return Response(
|
||||
serializer.data, status=200, content_type="application/manifest+json"
|
||||
)
|
||||
|
|
|
@ -14,9 +14,10 @@ packages = [
|
|||
{ include = "config" },
|
||||
]
|
||||
include = [
|
||||
{ path = "*.txt" },
|
||||
{ path = "*.png" },
|
||||
{ path = "*.html" },
|
||||
{ path = "*.html" },
|
||||
{ path = "*.json" },
|
||||
{ path = "*.png" },
|
||||
{ path = "*.txt" },
|
||||
]
|
||||
exclude = ["tests"]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import json
|
||||
from unittest import mock
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
|
@ -38,20 +38,21 @@ def test_admin_settings_correct_permission(db, logged_in_api_client, preferences
|
|||
assert len(response.data) == len(preferences.all())
|
||||
|
||||
|
||||
def test_manifest_endpoint(api_client, mocker, preferences, tmp_path, settings):
|
||||
settings.FUNKWHALE_SPA_HTML_ROOT = str(tmp_path / "index.html")
|
||||
preferences["instance__name"] = "Test pod"
|
||||
preferences["instance__short_description"] = "Test description"
|
||||
base_payload = {}
|
||||
manifest = tmp_path / "manifest.json"
|
||||
expected = {
|
||||
"name": "Test pod",
|
||||
"short_name": "Test pod",
|
||||
"description": "Test description",
|
||||
}
|
||||
manifest.write_bytes(json.dumps(base_payload).encode())
|
||||
def test_manifest_endpoint(api_client, preferences):
|
||||
with mock.patch(
|
||||
"funkwhale_api.instance.views.PWA_MANIFEST",
|
||||
{"lang": "unchanged"},
|
||||
):
|
||||
preferences["instance__name"] = "Test pod"
|
||||
preferences["instance__short_description"] = "Test description"
|
||||
expected = {
|
||||
"lang": "unchanged",
|
||||
"name": "Test pod",
|
||||
"short_name": "Test pod",
|
||||
"description": "Test description",
|
||||
}
|
||||
|
||||
url = reverse("api:v1:instance:spa-manifest")
|
||||
response = api_client.get(url)
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
url = reverse("api:v1:instance:spa-manifest")
|
||||
response = api_client.get(url)
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix timeout on spa manifest requests
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "Funkwhale",
|
||||
"categories": ["music", "entertainment"],
|
||||
"short_name": "Funkwhale",
|
||||
"description": "Your free and federated audio platform",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"url": "https://play.google.com/store/apps/details?id=audio.funkwhale.ffa",
|
||||
"id": "audio.funkwhale.ffa"
|
||||
},
|
||||
{
|
||||
"platform": "f-droid",
|
||||
"url": "https://f-droid.org/en/packages/audio.funkwhale.ffa/",
|
||||
"id": "audio.funkwhale.ffa"
|
||||
}
|
||||
],
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Search",
|
||||
"url": "/search",
|
||||
"icons": []
|
||||
},
|
||||
{
|
||||
"name": "Library",
|
||||
"url": "/library",
|
||||
"icons": []
|
||||
},
|
||||
{
|
||||
"name": "Channels",
|
||||
"url": "/subscriptions",
|
||||
"icons": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -5,6 +5,8 @@ import VueI18n from '@intlify/vite-plugin-vue-i18n'
|
|||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
import { resolve } from 'path'
|
||||
|
||||
import manifest from './pwa-manifest.json'
|
||||
|
||||
const port = +(process.env.VUE_PORT ?? 8080)
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
|
@ -35,56 +37,7 @@ export default defineConfig(({ mode }) => ({
|
|||
type: 'module',
|
||||
navigateFallback: 'index.html'
|
||||
},
|
||||
manifest: {
|
||||
name: 'Funkwhale',
|
||||
categories: ['music', 'entertainment'],
|
||||
start_url: undefined,
|
||||
scope: undefined,
|
||||
short_name: 'Funkwhale',
|
||||
description: 'Your free and federated audio platform',
|
||||
icons: [
|
||||
{
|
||||
src: 'android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: 'android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png'
|
||||
}
|
||||
],
|
||||
prefer_related_applications: true,
|
||||
related_applications: [
|
||||
{
|
||||
platform: 'play',
|
||||
url: 'https://play.google.com/store/apps/details?id=audio.funkwhale.ffa',
|
||||
id: 'audio.funkwhale.ffa'
|
||||
},
|
||||
{
|
||||
platform: 'f-droid',
|
||||
url: 'https://f-droid.org/en/packages/audio.funkwhale.ffa/',
|
||||
id: 'audio.funkwhale.ffa'
|
||||
}
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
name: 'Search',
|
||||
url: '/search',
|
||||
icons: []
|
||||
},
|
||||
{
|
||||
name: 'Library',
|
||||
url: '/library',
|
||||
icons: []
|
||||
},
|
||||
{
|
||||
name: 'Channels',
|
||||
url: '/subscriptions',
|
||||
icons: []
|
||||
}
|
||||
]
|
||||
}
|
||||
manifest
|
||||
})
|
||||
],
|
||||
server: {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
SRC="front/pwa-manifest.json"
|
||||
DEST="api/funkwhale_api/instance/pwa-manifest.json"
|
||||
|
||||
cp "$SRC" "$DEST"
|
Loading…
Reference in New Issue