fix(backend): APK-Download nutzt den erreichbaren Gitea-Host statt der ROOT_URL
Gitea baut browser_download_url aus seiner eigenen ROOT_URL (hier 192.168.178.153:3000), die vom Backend-Container nicht erreichbar ist. Der API-Call gelang, der Asset-Download nicht — der stille Fallback auf die nicht vorhandene lokale Datei meldete dann "Keine APK hinterlegt". Asset- und Redirect-URLs werden jetzt auf GITEA_URL umgeschrieben; scheitert der Weg trotzdem, sagen Log und Fehlermeldung welcher der beiden Wege fehlt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
043ec3a108
commit
3e8897b551
2 files changed
+35
-6
No files matched your search
+4
-1
@@ -18,7 +18,10 @@ TICKETMASTER_API_KEY=
|
||||
|
||||
# ── Android APK download button + in-app updater ─────────────────────────────
|
||||
# The backend proxies the fixed Gitea release ("apk-latest") over the LAN, so Gitea can stay internal.
|
||||
GITEA_URL=http://192.168.2.51:3000 # internal Gitea base reachable from the backend container
|
||||
GITEA_URL=http://192.168.2.51:3000 # Gitea-Basis, die der BACKEND-CONTAINER erreicht.
|
||||
# Muss nicht Giteas eigene ROOT_URL sein — das Backend baut
|
||||
# die Asset-URL auf diesen Host um (Test aus dem Container:
|
||||
# curl -sI $GITEA_URL/api/v1/version).
|
||||
GITEA_REPO=Docker/NovaSonic
|
||||
GITEA_TOKEN= # read token (only needed for a private repo)
|
||||
GITEA_APK_TAG=apk-latest
|
||||
|
||||
@@ -503,6 +503,19 @@ function _giteaApiJson(pathAndQuery) {
|
||||
});
|
||||
}
|
||||
|
||||
// Gitea baut seine browser_download_url aus der eigenen ROOT_URL — die kann eine ganz andere Adresse
|
||||
// sein als die, unter der das Backend Gitea erreicht (interne IP vs. Reverse-Proxy-Domain). Deshalb
|
||||
// Schema+Host+Port immer durch GITEA_URL ersetzen und nur den Pfad übernehmen.
|
||||
function _viaGiteaHost(urlStr) {
|
||||
if (!urlStr || !GITEA_URL) return urlStr;
|
||||
try {
|
||||
const base = new URL(GITEA_URL);
|
||||
const u = new URL(urlStr);
|
||||
if (u.origin === base.origin) return urlStr;
|
||||
return new URL(u.pathname + u.search, base).toString();
|
||||
} catch { return urlStr; }
|
||||
}
|
||||
|
||||
// The .apk asset of the fixed release, or null if unavailable.
|
||||
async function _giteaApkAsset() {
|
||||
const rel = await _giteaApiJson(`/releases/tags/${encodeURIComponent(GITEA_APK_TAG)}`);
|
||||
@@ -513,7 +526,7 @@ async function _giteaApkAsset() {
|
||||
const vcMatch = /versionCode\s*[=:]\s*(\d+)/i.exec(rel.body || '');
|
||||
return {
|
||||
size: asset.size,
|
||||
url: asset.browser_download_url,
|
||||
url: _viaGiteaHost(asset.browser_download_url),
|
||||
version: rel.name || rel.tag_name || null,
|
||||
versionCode: vcMatch ? parseInt(vcMatch[1], 10) : null,
|
||||
updatedAt: new Date(asset.created_at || rel.published_at || Date.now()).getTime(),
|
||||
@@ -523,7 +536,13 @@ async function _giteaApkAsset() {
|
||||
function _serveLocalApk(res) {
|
||||
if (res.headersSent) return;
|
||||
fs.stat(APK_PATH, (err) => {
|
||||
if (err) return res.status(404).json({ error: 'Keine APK hinterlegt' });
|
||||
// Ohne lokale Datei UND ohne erreichbares Gitea-Asset: sagen, welcher der beiden Wege fehlt,
|
||||
// sonst sucht man die APK an der falschen Stelle (die Logs oben nennen den Grund).
|
||||
if (err) return res.status(404).json({
|
||||
error: (GITEA_URL && GITEA_REPO)
|
||||
? `APK-Release nicht erreichbar (${GITEA_URL}, Tag ${GITEA_APK_TAG}) und keine lokale Datei unter ${APK_PATH}`
|
||||
: 'Keine APK hinterlegt',
|
||||
});
|
||||
res.setHeader('Content-Type', 'application/vnd.android.package-archive');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="NovaSonic.apk"');
|
||||
res.sendFile(APK_PATH);
|
||||
@@ -539,14 +558,21 @@ function _streamApkFromUrl(urlStr, res, redirectsLeft = 3) {
|
||||
lib.get(u, { headers }, up => {
|
||||
if ([301, 302, 303, 307, 308].includes(up.statusCode) && up.headers.location && redirectsLeft > 0) {
|
||||
up.resume();
|
||||
return _streamApkFromUrl(new URL(up.headers.location, u).toString(), res, redirectsLeft - 1);
|
||||
return _streamApkFromUrl(_viaGiteaHost(new URL(up.headers.location, u).toString()), res, redirectsLeft - 1);
|
||||
}
|
||||
if (up.statusCode !== 200) {
|
||||
up.resume();
|
||||
console.warn(`[apk] Gitea-Asset lieferte HTTP ${up.statusCode} (${u.origin}) — fallback auf ${APK_PATH}`);
|
||||
return _serveLocalApk(res);
|
||||
}
|
||||
if (up.statusCode !== 200) { up.resume(); return _serveLocalApk(res); }
|
||||
res.setHeader('Content-Type', 'application/vnd.android.package-archive');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="NovaSonic.apk"');
|
||||
if (up.headers['content-length']) res.setHeader('Content-Length', up.headers['content-length']);
|
||||
up.pipe(res);
|
||||
}).on('error', () => _serveLocalApk(res));
|
||||
}).on('error', (e) => {
|
||||
console.warn(`[apk] Gitea-Asset nicht erreichbar (${u.origin}): ${e.message} — fallback auf ${APK_PATH}`);
|
||||
_serveLocalApk(res);
|
||||
});
|
||||
}
|
||||
|
||||
app.get('/api/apk/info', async (req, res) => {
|
||||
|
||||
Reference in new issue
Block a user