Skip to content

Upload to Cloudflare R2 #937

Upload to Cloudflare R2

Upload to Cloudflare R2 #937

Workflow file for this run

name: Upload to Cloudflare R2
on:
push:
paths:
- 'launcher/Flarial.Launcher.exe'
- 'launcher/NewSupported.txt'
- 'launcher/Supported.json'
- 'launcher/Versions.json'
- 'launcher/Promotions.json'
- 'blacklist_dll_names.txt'
- 'blacklist_dll_hashes.txt'
- '.github/workflows/r2-upload.yml'
# Android APK uploads are intentionally not triggered directly by
# Android/Flarial.apk pushes. The Android hash workflow commits
# AndroidHash.json immediately after the APK changes; uploading on the
# APK push creates a race where R2 can serve a new APK with the old hash.
# Let the workflow_run from "make android hashbrowns" publish the
# validated APK+hash pair atomically instead.
workflow_run:
workflows: ["make hashbrowns", "make android hashbrowns"]
types:
- completed
workflow_dispatch:
jobs:
upload-to-r2:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Configure AWS CLI for R2
run: |
aws configure set aws_access_key_id ${{ secrets.R2_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }}
aws configure set region auto
- name: Upload files to R2
env:
R2_ENDPOINT: https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com
R2_BUCKET: ${{ secrets.R2_BUCKET_NAME }}
run: |
# Upload Flarial Launcher version metadata.
if [ -f "launcher/launcherVersion.txt" ]; then
aws s3 cp launcher/launcherVersion.txt s3://${R2_BUCKET}/launcher/launcherVersion.txt \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded launcherVersion.txt"
fi
# Upload Flarial Launcher executable.
if [ -f "launcher/Flarial.Launcher.exe" ]; then
aws s3 cp launcher/Flarial.Launcher.exe s3://${R2_BUCKET}/launcher/Flarial.Launcher.exe \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Flarial.Launcher.exe"
fi
# Upload DLL hashes metadata.
if [ -f "dll_hashes.json" ]; then
aws s3 cp dll_hashes.json s3://${R2_BUCKET}/dll_hashes.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded dll_hashes.json"
fi
# Upload third-party DLL deny lists.
if [ -f "blacklist_dll_names.txt" ]; then
aws s3 cp blacklist_dll_names.txt s3://${R2_BUCKET}/blacklist_dll_names.txt \
--content-type text/plain \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded blacklist_dll_names.txt"
fi
if [ -f "blacklist_dll_hashes.txt" ]; then
aws s3 cp blacklist_dll_hashes.txt s3://${R2_BUCKET}/blacklist_dll_hashes.txt \
--content-type text/plain \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded blacklist_dll_hashes.txt"
fi
# Upload supported versions metadata.
if [ -f "launcher/NewSupported.txt" ]; then
aws s3 cp launcher/NewSupported.txt s3://${R2_BUCKET}/launcher/NewSupported.txt \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded NewSupported.txt"
fi
if [ -f "launcher/Supported.json" ]; then
aws s3 cp launcher/Supported.json s3://${R2_BUCKET}/launcher/Supported.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Supported.json"
fi
if [ -f "launcher/Versions.json" ]; then
aws s3 cp launcher/Versions.json s3://${R2_BUCKET}/launcher/Versions.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Versions.json"
fi
if [ -f "launcher/Promotions.json" ]; then
aws s3 cp launcher/Promotions.json s3://${R2_BUCKET}/launcher/Promotions.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Promotions.json"
fi
if [ -f "launcher/Flarial.Bootstrapper.exe" ]; then
aws s3 cp launcher/Flarial.Bootstrapper.exe s3://${R2_BUCKET}/launcher/Flarial.Bootstrapper.exe \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Flarial.Bootstrapper.exe"
fi
if [ -f "launcher/Flarial.Version.Changer.exe" ]; then
aws s3 cp launcher/Flarial.Version.Changer.exe s3://${R2_BUCKET}/launcher/Flarial.Version.Changer.exe \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Flarial.Version.Changer.exe"
fi
# Upload release build of the client.
if [ -f "dll/latest.dll" ]; then
aws s3 cp dll/latest.dll s3://${R2_BUCKET}/dll/latest.dll \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded latest.dll"
fi
# Upload beta build of the client.
if [ -f "dll/beta.dll" ]; then
aws s3 cp dll/beta.dll s3://${R2_BUCKET}/dll/beta.dll \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded beta.dll"
fi
if [ -f "202.txt" ]; then
aws s3 cp 202.txt s3://${R2_BUCKET}/202.txt \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded 202.txt"
fi
# Upload latest Android APK and hash metadata.
# Guard against publishing mismatched APK/hash pairs; Android clients
# treat that as a corrupt APK.
if [ -f "Android/Flarial.apk" ] || [ -f "Android/AndroidHash.json" ]; then
if [ ! -f "Android/Flarial.apk" ] || [ ! -f "Android/AndroidHash.json" ]; then
echo "Android APK/hash must be uploaded together" >&2
exit 1
fi
actual_android_hash=$(sha256sum Android/Flarial.apk | awk '{ print $1 }')
expected_android_hash=$(python3 -c 'import json; print(json.load(open("Android/AndroidHash.json"))["Android"])')
if [ "${actual_android_hash}" != "${expected_android_hash}" ]; then
echo "Android hash mismatch; refusing to publish corrupt CDN state" >&2
echo " APK: ${actual_android_hash}" >&2
echo " JSON: ${expected_android_hash}" >&2
exit 1
fi
android_backup_dir=$(mktemp -d)
android_have_backup=0
if aws s3 cp s3://${R2_BUCKET}/Android/Flarial.apk "${android_backup_dir}/Flarial.apk" \
--endpoint-url ${R2_ENDPOINT} && \
aws s3 cp s3://${R2_BUCKET}/Android/AndroidHash.json "${android_backup_dir}/AndroidHash.json" \
--endpoint-url ${R2_ENDPOINT}; then
android_have_backup=1
else
echo "No complete existing Android CDN pair to back up; continuing"
fi
android_publish_started=0
restore_android_pair() {
rc=$?
if [ "${rc}" -ne 0 ] && [ "${android_publish_started}" = "1" ] && [ "${android_have_backup}" = "1" ]; then
echo "Android publish failed; restoring previous APK/hash pair" >&2
aws s3 cp "${android_backup_dir}/Flarial.apk" s3://${R2_BUCKET}/Android/Flarial.apk \
--endpoint-url ${R2_ENDPOINT} || true
aws s3 cp "${android_backup_dir}/Flarial.apk" s3://${R2_BUCKET}/android/Flarial.apk \
--endpoint-url ${R2_ENDPOINT} || true
aws s3 cp "${android_backup_dir}/AndroidHash.json" s3://${R2_BUCKET}/Android/AndroidHash.json \
--endpoint-url ${R2_ENDPOINT} || true
aws s3 cp "${android_backup_dir}/AndroidHash.json" s3://${R2_BUCKET}/android/AndroidHash.json \
--endpoint-url ${R2_ENDPOINT} || true
fi
exit "${rc}"
}
trap restore_android_pair EXIT
android_publish_started=1
aws s3 cp Android/Flarial.apk s3://${R2_BUCKET}/Android/Flarial.apk \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Android/Flarial.apk"
# Keep the legacy lowercase CDN path in sync for older clients/tools.
aws s3 cp Android/Flarial.apk s3://${R2_BUCKET}/android/Flarial.apk \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded android/Flarial.apk"
aws s3 cp Android/AndroidHash.json s3://${R2_BUCKET}/Android/AndroidHash.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded Android/AndroidHash.json"
# Keep the legacy lowercase hash path in sync too.
aws s3 cp Android/AndroidHash.json s3://${R2_BUCKET}/android/AndroidHash.json \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded android/AndroidHash.json"
trap - EXIT
fi
# Fetch latest version of Pyroclastic for the launcher to use.
curl -L "https://github.com/Aetopia/Pyroclastic/releases/latest/download/gamelaunchhelper.dll" -o "launcher/gamelaunchhelper.dll"
if [ -f "launcher/gamelaunchhelper.dll" ]; then
aws s3 cp launcher/gamelaunchhelper.dll s3://${R2_BUCKET}/launcher/gamelaunchhelper.dll \
--endpoint-url ${R2_ENDPOINT}
echo "✓ Uploaded gamelaunchhelper.dll"
fi
- name: Verify uploads
env:
R2_ENDPOINT: https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com
R2_BUCKET: ${{ secrets.R2_BUCKET_NAME }}
run: |
echo "Files in R2 bucket:"
aws s3 ls s3://${R2_BUCKET}/ --recursive --endpoint-url ${R2_ENDPOINT}