Preserve Flutter mirror-os codebase
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# OTA Update Server
|
||||
|
||||
Static file server for hosting Mirror OS remote APK updates. Runs on the homelab alongside workout-player on port 9091.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Path | Description |
|
||||
|------|-------------|
|
||||
| `GET /api/mirror-os/version` | Version manifest (JSON) |
|
||||
| `GET /mirror-os-remote.apk` | APK download |
|
||||
| `GET /health` | Health check |
|
||||
|
||||
## Deploy on Homelab
|
||||
|
||||
```bash
|
||||
# Copy files to homelab
|
||||
rsync -avz deploy/ota-server/ homelab:~/ota-server/
|
||||
|
||||
# Start the server
|
||||
ssh homelab 'cd ~/ota-server && docker compose up -d'
|
||||
```
|
||||
|
||||
The server runs nginx on port 9091 serving static files from `public/`.
|
||||
|
||||
## Publish an Update
|
||||
|
||||
From the repo root:
|
||||
|
||||
```bash
|
||||
# Build APK, bump version, copy to public/
|
||||
./deploy/publish-apk.sh "Added new feature X"
|
||||
|
||||
# Then sync to homelab
|
||||
rsync -avz deploy/ota-server/public/ homelab:~/ota-server/public/
|
||||
```
|
||||
|
||||
The script:
|
||||
1. Builds the release APK via `flutter build apk --release`
|
||||
2. Copies the APK to `deploy/ota-server/public/mirror-os-remote.apk`
|
||||
3. Increments the version number in `version.json`
|
||||
4. Sets the changelog from the argument (or defaults to "Bug fixes and improvements")
|
||||
|
||||
## How the App Checks for Updates
|
||||
|
||||
The remote app (`apps/remote`) has an `update_provider.dart` that:
|
||||
1. Fetches `http://192.168.86.172:9091/api/mirror-os/version`
|
||||
2. Compares the returned `version` number against the locally installed version
|
||||
3. If newer, shows a prompt to download and install the APK from `downloadUrl`
|
||||
|
||||
## Version Manifest Format
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"downloadUrl": "http://192.168.86.172:9091/mirror-os-remote.apk",
|
||||
"changelog": "Initial release"
|
||||
}
|
||||
```
|
||||
|
||||
The `version` field is a simple incrementing integer.
|
||||
@@ -0,0 +1,12 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
ota-server:
|
||||
image: nginx:alpine
|
||||
container_name: mirror-os-ota
|
||||
ports:
|
||||
- "9091:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./public:/usr/share/nginx/html:ro
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,27 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# Serve version manifest as JSON
|
||||
location = /api/mirror-os/version {
|
||||
alias /usr/share/nginx/html/version.json;
|
||||
default_type application/json;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
}
|
||||
|
||||
# Serve APK with correct content type
|
||||
location = /mirror-os-remote.apk {
|
||||
default_type application/vnd.android.package-archive;
|
||||
add_header Content-Disposition 'attachment; filename="mirror-os-remote.apk"';
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
}
|
||||
|
||||
# Health check
|
||||
location = /health {
|
||||
return 200 '{"status":"ok"}';
|
||||
default_type application/json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"downloadUrl": "http://192.168.86.172:9091/mirror-os-remote.apk",
|
||||
"changelog": "Initial release"
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# publish-apk.sh — Build release APK and update OTA server files.
|
||||
# Usage: ./deploy/publish-apk.sh [changelog message]
|
||||
# Make executable: chmod +x deploy/publish-apk.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
OTA_DIR="$REPO_ROOT/deploy/ota-server/public"
|
||||
VERSION_FILE="$OTA_DIR/version.json"
|
||||
APK_SOURCE="$REPO_ROOT/apps/remote/build/app/outputs/flutter-apk/app-release.apk"
|
||||
APK_DEST="$OTA_DIR/mirror-os-remote.apk"
|
||||
|
||||
CHANGELOG="${1:-Bug fixes and improvements}"
|
||||
|
||||
# --- Build the release APK ---
|
||||
echo "Building release APK..."
|
||||
cd "$REPO_ROOT/apps/remote"
|
||||
flutter build apk --release
|
||||
|
||||
if [ ! -f "$APK_SOURCE" ]; then
|
||||
echo "ERROR: APK not found at $APK_SOURCE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Copy APK to OTA public directory ---
|
||||
echo "Copying APK to OTA server..."
|
||||
cp "$APK_SOURCE" "$APK_DEST"
|
||||
|
||||
# --- Increment version in version.json ---
|
||||
CURRENT_VERSION=$(python3 -c "import json; print(json.load(open('$VERSION_FILE'))['version'])")
|
||||
NEW_VERSION=$((CURRENT_VERSION + 1))
|
||||
|
||||
python3 -c "
|
||||
import json
|
||||
|
||||
data = {
|
||||
'version': $NEW_VERSION,
|
||||
'downloadUrl': 'http://192.168.86.172:9091/mirror-os-remote.apk',
|
||||
'changelog': '''$CHANGELOG'''
|
||||
}
|
||||
|
||||
with open('$VERSION_FILE', 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
f.write('\n')
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "Published version $NEW_VERSION"
|
||||
echo " Changelog: $CHANGELOG"
|
||||
echo " APK size: $(du -h "$APK_DEST" | cut -f1)"
|
||||
echo ""
|
||||
echo "--- Deploy instructions ---"
|
||||
echo ""
|
||||
echo "If running locally:"
|
||||
echo " cd deploy/ota-server && docker compose up -d"
|
||||
echo ""
|
||||
echo "If deploying to homelab (192.168.86.172):"
|
||||
echo " rsync -avz deploy/ota-server/ homelab:~/ota-server/"
|
||||
echo " ssh homelab 'cd ~/ota-server && docker compose up -d'"
|
||||
Reference in New Issue
Block a user