License the project; add root README, website, and parked release CI
- Code: GPL-3.0-or-later (LICENSE, SPDX headers on all .kt/.aidl). Specs in docs/: CC-BY-4.0 (docs/LICENSE). Rationale in build-status.md; server decided GPL (not AGPL). - Root README for the public repo. - web/: Cloudflare Worker site for echo-lot.app. /apk resolves the newest APK from the Gitea latest-release API at request time (edge-cached 5 min), so tagging a release is the only publish step. /fdroid, /source, and a manual DOWNLOAD_URL fallback are wrangler vars. - .gitea/workflows/release.yml: tag-driven (v*) signed semver APK builds for the future production app in echolot-app/. Parked; the prober is deliberately not CI-built. - Fix UserService.kt: drop the explicit secondary constructor that conflicted with the implicit primary (never compiled before — first local build caught it). Prober now builds: :app:assembleDebug OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e3840f54fe
commit
6ddf013dfe
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: 2026 Echolot contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Everything under public/ is served straight from the edge without invoking
|
||||
// this Worker. The Worker exists for the short stable URLs (/apk, /fdroid,
|
||||
// /source) — short enough for a QR code — and to resolve "/apk" to the newest
|
||||
// release asset at request time, so tagging a release in Gitea is the only
|
||||
// publish step. No site redeploy, no URL to update.
|
||||
|
||||
const STATIC_ROUTES = {
|
||||
"/fdroid": "FDROID_URL",
|
||||
"/source": "SOURCE_URL",
|
||||
};
|
||||
|
||||
// Resolve the newest APK from the Gitea "latest release" API. Cached at the
|
||||
// edge for 5 minutes so a release becomes visible quickly, while Gitea sees
|
||||
// at most one API hit per POP per 5 min regardless of download traffic.
|
||||
async function latestApkUrl(env) {
|
||||
if (!env.GITEA_REPO_API) return null;
|
||||
const res = await fetch(`${env.GITEA_REPO_API}/releases/latest`, {
|
||||
headers: { Accept: "application/json", "User-Agent": "echolot-site" },
|
||||
cf: { cacheTtl: 300, cacheEverything: true },
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
const rel = await res.json();
|
||||
const apk = rel.assets?.find((a) => a.name?.endsWith(".apk"));
|
||||
return apk?.browser_download_url ?? null;
|
||||
}
|
||||
|
||||
function redirect(location) {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: location,
|
||||
"Cache-Control": "no-store",
|
||||
"Referrer-Policy": "no-referrer",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const { pathname } = new URL(request.url);
|
||||
const path = pathname.replace(/\/$/, "");
|
||||
const fallback = new URL("/#install", request.url).toString();
|
||||
|
||||
if (path === "/apk" || path === "/download") {
|
||||
// Order: live Gitea release → manual override → install section.
|
||||
let target = null;
|
||||
try {
|
||||
target = await latestApkUrl(env);
|
||||
} catch {
|
||||
// Gitea unreachable — fall through rather than 500 on a download link.
|
||||
}
|
||||
return redirect(target || env.DOWNLOAD_URL || fallback);
|
||||
}
|
||||
|
||||
const varName = STATIC_ROUTES[path];
|
||||
if (varName) return redirect(env[varName] || fallback);
|
||||
|
||||
return env.ASSETS.fetch(request);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user