mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 16:56:33 +00:00
feat(ota): add RAUC OS update foundation
This commit is contained in:
parent
444bb4c116
commit
87cde93316
13 changed files with 559 additions and 7 deletions
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
|
|
@ -168,6 +168,12 @@ jobs:
|
||||||
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
cp deploy/systemd/betterframe-firmware-rollback.sh \
|
cp deploy/systemd/betterframe-firmware-rollback.sh \
|
||||||
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/systemd/betterframe-rauc-mark-good.service \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/systemd/betterframe-rauc-mark-good.sh \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/tmpfiles/betterframe-kiosk.conf \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
cp deploy/pam.d/cage \
|
cp deploy/pam.d/cage \
|
||||||
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/cage.pam
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/cage.pam
|
||||||
cp deploy/plymouth/betterframe/betterframe.plymouth \
|
cp deploy/plymouth/betterframe/betterframe.plymouth \
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,12 @@ install -m 644 /tmp/bf-files/betterframe-kiosk.service /etc/systemd/system/bette
|
||||||
install -m 644 /tmp/bf-files/cage.pam /etc/pam.d/cage
|
install -m 644 /tmp/bf-files/cage.pam /etc/pam.d/cage
|
||||||
install -m 755 /tmp/bf-files/betterframe-firmware-rollback.sh \
|
install -m 755 /tmp/bf-files/betterframe-firmware-rollback.sh \
|
||||||
/usr/local/sbin/betterframe-firmware-rollback.sh
|
/usr/local/sbin/betterframe-firmware-rollback.sh
|
||||||
|
install -m 644 /tmp/bf-files/betterframe-rauc-mark-good.service \
|
||||||
|
/etc/systemd/system/betterframe-rauc-mark-good.service
|
||||||
|
install -m 755 /tmp/bf-files/betterframe-rauc-mark-good.sh \
|
||||||
|
/usr/local/sbin/betterframe-rauc-mark-good.sh
|
||||||
|
install -d -m 755 /etc/tmpfiles.d
|
||||||
|
install -m 644 /tmp/bf-files/betterframe-kiosk.conf /etc/tmpfiles.d/betterframe-kiosk.conf
|
||||||
|
|
||||||
# Default env file — operator may edit on first boot to point at their server.
|
# Default env file — operator may edit on first boot to point at their server.
|
||||||
cat > /etc/default/betterframe-kiosk <<'EOF'
|
cat > /etc/default/betterframe-kiosk <<'EOF'
|
||||||
|
|
@ -41,6 +47,7 @@ plymouth-set-default-theme betterframe || true
|
||||||
# --- Enable services, disable noise ---
|
# --- Enable services, disable noise ---
|
||||||
systemctl enable seatd
|
systemctl enable seatd
|
||||||
systemctl enable betterframe-kiosk.service
|
systemctl enable betterframe-kiosk.service
|
||||||
|
systemctl enable betterframe-rauc-mark-good.service
|
||||||
|
|
||||||
# Boot to multi-user, no display manager, no welcome wizard, no getty on tty1.
|
# Boot to multi-user, no display manager, no welcome wizard, no getty on tty1.
|
||||||
systemctl set-default multi-user.target
|
systemctl set-default multi-user.target
|
||||||
|
|
|
||||||
127
deploy/rauc/betterframe-rauc-boot.sh
Normal file
127
deploy/rauc/betterframe-rauc-boot.sh
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SELECTOR_DEV="${BF_RAUC_SELECTOR_DEV:-/dev/disk/by-partlabel/BF_BOOTSEL}"
|
||||||
|
STATE_DIR="${BF_RAUC_STATE_DIR:-/var/lib/rauc/betterframe}"
|
||||||
|
STATE_FILE="${STATE_DIR}/slot-state"
|
||||||
|
|
||||||
|
slot_to_part() {
|
||||||
|
case "$1" in
|
||||||
|
A) printf '2' ;;
|
||||||
|
B) printf '3' ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
part_to_slot() {
|
||||||
|
case "$1" in
|
||||||
|
2) printf 'A' ;;
|
||||||
|
3) printf 'B' ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
other_slot() {
|
||||||
|
case "$1" in
|
||||||
|
A) printf 'B' ;;
|
||||||
|
B) printf 'A' ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
read_current_slot() {
|
||||||
|
local part_file="/proc/device-tree/chosen/bootloader/partition"
|
||||||
|
if [ -r "$part_file" ]; then
|
||||||
|
local part
|
||||||
|
part="$(tr -d '\000\n\r ' < "$part_file")"
|
||||||
|
case "$part" in
|
||||||
|
2|3) printf '%s' "$part"; return ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
with_selector_mounted() {
|
||||||
|
local fn="$1"
|
||||||
|
shift
|
||||||
|
local mountpoint
|
||||||
|
mountpoint="$(mktemp -d)"
|
||||||
|
mount "$SELECTOR_DEV" "$mountpoint"
|
||||||
|
set +e
|
||||||
|
"$fn" "$mountpoint" "$@"
|
||||||
|
local rc=$?
|
||||||
|
set -e
|
||||||
|
umount "$mountpoint"
|
||||||
|
rmdir "$mountpoint"
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_primary_from_mount() {
|
||||||
|
local mountpoint="$1"
|
||||||
|
awk '
|
||||||
|
/^\[all\]$/ { in_all=1; next }
|
||||||
|
/^\[/ { in_all=0; next }
|
||||||
|
in_all && /^boot_partition=/ { sub(/^boot_partition=/, ""); print; exit }
|
||||||
|
' "${mountpoint}/autoboot.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_primary_to_mount() {
|
||||||
|
local mountpoint="$1"
|
||||||
|
local primary_slot="$2"
|
||||||
|
local primary_part try_part
|
||||||
|
primary_part="$(slot_to_part "$primary_slot")"
|
||||||
|
try_part="$(slot_to_part "$(other_slot "$primary_slot")")"
|
||||||
|
cat > "${mountpoint}/autoboot.txt" <<EOF
|
||||||
|
[all]
|
||||||
|
tryboot_a_b=1
|
||||||
|
PARTITION_WALK=1
|
||||||
|
boot_partition=${primary_part}
|
||||||
|
|
||||||
|
[tryboot]
|
||||||
|
boot_partition=${try_part}
|
||||||
|
EOF
|
||||||
|
sync -f "${mountpoint}/autoboot.txt" 2>/dev/null || sync
|
||||||
|
}
|
||||||
|
|
||||||
|
get_primary() {
|
||||||
|
local part
|
||||||
|
part="$(with_selector_mounted get_primary_from_mount)"
|
||||||
|
part_to_slot "$part"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_primary() {
|
||||||
|
with_selector_mounted write_primary_to_mount "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_state() {
|
||||||
|
local slot="$1"
|
||||||
|
if [ -f "$STATE_FILE" ] && grep -qx "${slot}=bad" "$STATE_FILE"; then
|
||||||
|
printf 'bad\n'
|
||||||
|
else
|
||||||
|
printf 'good\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
set_state() {
|
||||||
|
local slot="$1"
|
||||||
|
local state="$2"
|
||||||
|
mkdir -p "$STATE_DIR"
|
||||||
|
if [ "$state" = "bad" ]; then
|
||||||
|
grep -vx "${slot}=good" "$STATE_FILE" 2>/dev/null | grep -vx "${slot}=bad" > "${STATE_FILE}.tmp" || true
|
||||||
|
printf '%s=bad\n' "$slot" >> "${STATE_FILE}.tmp"
|
||||||
|
mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
||||||
|
else
|
||||||
|
grep -vx "${slot}=bad" "$STATE_FILE" 2>/dev/null > "${STATE_FILE}.tmp" || true
|
||||||
|
mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
get-primary) get_primary ;;
|
||||||
|
set-primary) set_primary "${2:?slot required}" ;;
|
||||||
|
get-state) get_state "${2:?slot required}" ;;
|
||||||
|
set-state) set_state "${2:?slot required}" "${3:?state required}" ;;
|
||||||
|
get-current) part_to_slot "$(read_current_slot)" ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
16
deploy/rauc/manifest.raucm.in
Normal file
16
deploy/rauc/manifest.raucm.in
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
[update]
|
||||||
|
compatible=betterframe-rpi5-aarch64
|
||||||
|
version=@VERSION@
|
||||||
|
description=BetterFrame OS @VERSION@
|
||||||
|
build=@GIT_SHA@
|
||||||
|
|
||||||
|
[bundle]
|
||||||
|
format=verity
|
||||||
|
|
||||||
|
[image.bootfs]
|
||||||
|
filename=bootfs.vfat
|
||||||
|
type=image
|
||||||
|
|
||||||
|
[image.rootfs]
|
||||||
|
filename=rootfs.ext4
|
||||||
|
type=image
|
||||||
33
deploy/rauc/system.conf
Normal file
33
deploy/rauc/system.conf
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
[system]
|
||||||
|
compatible=betterframe-rpi5-aarch64
|
||||||
|
bootloader=custom
|
||||||
|
data-directory=/var/lib/rauc
|
||||||
|
bundle-formats=verity
|
||||||
|
boot-attempts=3
|
||||||
|
boot-attempts-primary=3
|
||||||
|
|
||||||
|
[keyring]
|
||||||
|
path=/etc/rauc/keyring.pem
|
||||||
|
|
||||||
|
[handlers]
|
||||||
|
bootloader-custom-backend=/usr/local/sbin/betterframe-rauc-boot.sh
|
||||||
|
|
||||||
|
[slot.bootfs.0]
|
||||||
|
device=/dev/disk/by-partlabel/BF_BOOT_A
|
||||||
|
type=vfat
|
||||||
|
bootname=A
|
||||||
|
|
||||||
|
[slot.rootfs.0]
|
||||||
|
device=/dev/disk/by-partlabel/BF_ROOT_A
|
||||||
|
type=ext4
|
||||||
|
parent=bootfs.0
|
||||||
|
|
||||||
|
[slot.bootfs.1]
|
||||||
|
device=/dev/disk/by-partlabel/BF_BOOT_B
|
||||||
|
type=vfat
|
||||||
|
bootname=B
|
||||||
|
|
||||||
|
[slot.rootfs.1]
|
||||||
|
device=/dev/disk/by-partlabel/BF_ROOT_B
|
||||||
|
type=ext4
|
||||||
|
parent=bootfs.1
|
||||||
|
|
@ -235,6 +235,13 @@ if [ "${INSTALL_KIOSK}" = "1" ]; then
|
||||||
/etc/systemd/system/betterframe-kiosk.service
|
/etc/systemd/system/betterframe-kiosk.service
|
||||||
install -m 755 "${REPO_ROOT}/deploy/systemd/betterframe-firmware-rollback.sh" \
|
install -m 755 "${REPO_ROOT}/deploy/systemd/betterframe-firmware-rollback.sh" \
|
||||||
/usr/local/sbin/betterframe-firmware-rollback.sh
|
/usr/local/sbin/betterframe-firmware-rollback.sh
|
||||||
|
install -m 644 "${REPO_ROOT}/deploy/systemd/betterframe-rauc-mark-good.service" \
|
||||||
|
/etc/systemd/system/betterframe-rauc-mark-good.service
|
||||||
|
install -m 755 "${REPO_ROOT}/deploy/systemd/betterframe-rauc-mark-good.sh" \
|
||||||
|
/usr/local/sbin/betterframe-rauc-mark-good.sh
|
||||||
|
install -d -m 755 /etc/tmpfiles.d
|
||||||
|
install -m 644 "${REPO_ROOT}/deploy/tmpfiles/betterframe-kiosk.conf" \
|
||||||
|
/etc/tmpfiles.d/betterframe-kiosk.conf
|
||||||
|
|
||||||
if [ ! -e /etc/default/betterframe-kiosk ]; then
|
if [ ! -e /etc/default/betterframe-kiosk ]; then
|
||||||
cat > /etc/default/betterframe-kiosk <<'EOF'
|
cat > /etc/default/betterframe-kiosk <<'EOF'
|
||||||
|
|
@ -245,6 +252,7 @@ EOF
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable betterframe-kiosk.service
|
systemctl enable betterframe-kiosk.service
|
||||||
|
systemctl enable betterframe-rauc-mark-good.service
|
||||||
# Restart picks up new binary on re-run.
|
# Restart picks up new binary on re-run.
|
||||||
systemctl restart betterframe-kiosk.service || true
|
systemctl restart betterframe-kiosk.service || true
|
||||||
|
|
||||||
|
|
|
||||||
15
deploy/systemd/betterframe-rauc-mark-good.service
Normal file
15
deploy/systemd/betterframe-rauc-mark-good.service
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Mark BetterFrame RAUC slot good after kiosk heartbeat
|
||||||
|
Documentation=https://github.com/BetterCorp/BetterFrame
|
||||||
|
After=betterframe-kiosk.service network-online.target
|
||||||
|
Wants=betterframe-kiosk.service network-online.target
|
||||||
|
ConditionPathExists=/etc/rauc/system.conf
|
||||||
|
ConditionPathExists=/usr/bin/rauc
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/sbin/betterframe-rauc-mark-good.sh
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
20
deploy/systemd/betterframe-rauc-mark-good.sh
Normal file
20
deploy/systemd/betterframe-rauc-mark-good.sh
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MARKER="/run/betterframe/kiosk-healthy"
|
||||||
|
TIMEOUT="${BF_RAUC_MARK_GOOD_TIMEOUT:-300}"
|
||||||
|
|
||||||
|
if ! command -v rauc >/dev/null 2>&1; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
deadline=$(($(date +%s) + TIMEOUT))
|
||||||
|
while [ "$(date +%s)" -lt "$deadline" ]; do
|
||||||
|
if [ -s "$MARKER" ]; then
|
||||||
|
exec rauc status mark-good
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[betterframe-rauc-mark-good] kiosk health marker did not appear within ${TIMEOUT}s" >&2
|
||||||
|
exit 1
|
||||||
1
deploy/tmpfiles/betterframe-kiosk.conf
Normal file
1
deploy/tmpfiles/betterframe-kiosk.conf
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
d /run/betterframe 0755 bfkiosk bfkiosk -
|
||||||
71
docs/full-os-ota.md
Normal file
71
docs/full-os-ota.md
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# BetterFrame Full OS OTA
|
||||||
|
|
||||||
|
BetterFrame field devices must use full-image A/B OTA for OS, package,
|
||||||
|
kernel, firmware, GTK/WebKit/GStreamer, and kiosk runtime changes. App-only
|
||||||
|
binary replacement is not sufficient for production field deployments.
|
||||||
|
The legacy kiosk binary updater is gated behind `BF_ENABLE_APP_OTA=1` and
|
||||||
|
should stay disabled in production.
|
||||||
|
|
||||||
|
## Target Design
|
||||||
|
|
||||||
|
- Update engine: RAUC.
|
||||||
|
- Boot selection: Raspberry Pi firmware `autoboot.txt` / `tryboot` via a
|
||||||
|
BetterFrame RAUC custom bootloader backend.
|
||||||
|
- Bundle format: RAUC `verity`.
|
||||||
|
- Device compatibility: `betterframe-rpi5-aarch64`.
|
||||||
|
- Slot layout:
|
||||||
|
- `BF_BOOTSEL`: small FAT partition containing only `autoboot.txt`.
|
||||||
|
- `BF_BOOT_A`: FAT boot files for slot A.
|
||||||
|
- `BF_ROOT_A`: ext4 root filesystem for slot A.
|
||||||
|
- `BF_BOOT_B`: FAT boot files for slot B.
|
||||||
|
- `BF_ROOT_B`: ext4 root filesystem for slot B.
|
||||||
|
- `BF_DATA`: persistent ext4 data partition for pairing state, logs,
|
||||||
|
RAUC state, and local kiosk cache.
|
||||||
|
|
||||||
|
## Safety Flow
|
||||||
|
|
||||||
|
1. Kiosk checks the BetterFrame server for an OS bundle matching channel,
|
||||||
|
rollout, architecture, and current OS version.
|
||||||
|
2. Device installs the signed RAUC bundle to the inactive slot.
|
||||||
|
3. RAUC marks the inactive slot as primary.
|
||||||
|
4. Device reboots using Pi `tryboot`.
|
||||||
|
5. If the new slot fails to boot, Pi firmware falls back to the previous
|
||||||
|
normal slot.
|
||||||
|
6. If the new slot boots and the kiosk successfully heartbeats to the server,
|
||||||
|
`betterframe-rauc-mark-good.service` runs `rauc status mark-good`.
|
||||||
|
|
||||||
|
## Signing
|
||||||
|
|
||||||
|
RAUC uses X.509 bundle signing. The public certificate must be baked into the
|
||||||
|
image as `/etc/rauc/keyring.pem`. The private key is a CI secret used only to
|
||||||
|
produce `.raucb` bundles.
|
||||||
|
|
||||||
|
Generate a production keypair:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl req -x509 -newkey rsa:4096 -nodes \
|
||||||
|
-keyout betterframe-rauc.key.pem \
|
||||||
|
-out betterframe-rauc.cert.pem \
|
||||||
|
-days 3650 \
|
||||||
|
-subj "/CN=BetterFrame RAUC Production/"
|
||||||
|
```
|
||||||
|
|
||||||
|
Required CI/Coolify secrets for full OS OTA:
|
||||||
|
|
||||||
|
- `BF_RAUC_CERT_PEM`: public certificate, baked into the client image.
|
||||||
|
- `BF_RAUC_KEY_PEM`: private signing key, used only by GitHub Actions.
|
||||||
|
- `BF_AUTOIMPORT_URL`: BetterFrame server public base URL.
|
||||||
|
- `BF_AUTOIMPORT_API_KEY`: import token matching server
|
||||||
|
`BF_FIRMWARE_IMPORT_API_KEY`.
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
This repository now contains the RAUC target config and boot backend
|
||||||
|
scaffolding. The remaining production work is:
|
||||||
|
|
||||||
|
1. Replace the single-root pi-gen output with a GPT A/B image layout.
|
||||||
|
2. Generate `.raucb` bundles from the same boot/root artifacts used for the
|
||||||
|
flashable image.
|
||||||
|
3. Add server-side OS release metadata separate from app-binary firmware.
|
||||||
|
4. Add kiosk-side OS update polling/install orchestration.
|
||||||
|
5. Lock down local input devices and mutable OS paths.
|
||||||
234
kiosk/Cargo.lock
generated
234
kiosk/Cargo.lock
generated
|
|
@ -38,6 +38,17 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
|
@ -56,29 +67,97 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.7.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"itoa",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "betterframe-kiosk"
|
name = "betterframe-kiosk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"base64",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"ed25519-dalek",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"gpiod",
|
"gpiod",
|
||||||
"gst-plugin-gtk4",
|
"gst-plugin-gtk4",
|
||||||
"gstreamer",
|
"gstreamer",
|
||||||
"gstreamer-video",
|
"gstreamer-video",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
|
"hex",
|
||||||
"hostname",
|
"hostname",
|
||||||
|
"rand",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite",
|
"tokio-tungstenite",
|
||||||
|
"tower",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"url",
|
"url",
|
||||||
|
|
@ -193,6 +272,12 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-oid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -244,12 +329,50 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"curve25519-dalek-derive",
|
||||||
|
"digest",
|
||||||
|
"fiat-crypto",
|
||||||
|
"rustc_version",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek-derive"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-encoding"
|
name = "data-encoding"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
|
@ -292,6 +415,30 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
|
dependencies = [
|
||||||
|
"pkcs8",
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519-dalek"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"ed25519",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
@ -350,6 +497,12 @@ version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fiat-crypto"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "field-offset"
|
name = "field-offset"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
@ -992,6 +1145,12 @@ version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hostname"
|
name = "hostname"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
@ -1042,6 +1201,12 @@ version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|
@ -1056,6 +1221,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|
@ -1374,6 +1540,12 @@ dependencies = [
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
|
|
@ -1577,6 +1749,15 @@ version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem-rfc7468"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
|
@ -1589,6 +1770,16 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs8"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.33"
|
version = "0.3.33"
|
||||||
|
|
@ -1918,6 +2109,17 @@ dependencies = [
|
||||||
"zmij",
|
"zmij",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_path_to_error"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
@ -1950,6 +2152,17 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
@ -1965,6 +2178,15 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
@ -2013,6 +2235,16 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spki"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"der",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
@ -2326,6 +2558,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2364,6 +2597,7 @@ version = "0.1.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ pub fn heartbeat(
|
||||||
key: &str,
|
key: &str,
|
||||||
displays: &[(String, u32, u32)],
|
displays: &[(String, u32, u32)],
|
||||||
hw: &crate::hwmon::HwInfo,
|
hw: &crate::hwmon::HwInfo,
|
||||||
) {
|
) -> bool {
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let display_info: Vec<_> = displays.iter().enumerate().map(|(index, (name, w, h))| {
|
let display_info: Vec<_> = displays.iter().enumerate().map(|(index, (name, w, h))| {
|
||||||
serde_json::json!({ "index": index, "name": name, "width_px": w, "height_px": h })
|
serde_json::json!({ "index": index, "name": name, "width_px": w, "height_px": h })
|
||||||
|
|
@ -256,7 +256,7 @@ pub fn heartbeat(
|
||||||
let local_key = load_or_create_local_key();
|
let local_key = load_or_create_local_key();
|
||||||
let local_port: u16 = std::env::var("BF_KIOSK_LOCAL_PORT")
|
let local_port: u16 = std::env::var("BF_KIOSK_LOCAL_PORT")
|
||||||
.ok().and_then(|s| s.parse().ok()).unwrap_or(18090);
|
.ok().and_then(|s| s.parse().ok()).unwrap_or(18090);
|
||||||
let _ = client
|
client
|
||||||
.post(format!("{server}/api/kiosk/heartbeat"))
|
.post(format!("{server}/api/kiosk/heartbeat"))
|
||||||
.header("Authorization", format!("Bearer {key}"))
|
.header("Authorization", format!("Bearer {key}"))
|
||||||
.json(&serde_json::json!({
|
.json(&serde_json::json!({
|
||||||
|
|
@ -269,5 +269,7 @@ pub fn heartbeat(
|
||||||
"local_port": local_port,
|
"local_port": local_port,
|
||||||
}))
|
}))
|
||||||
.timeout(Duration::from_secs(5))
|
.timeout(Duration::from_secs(5))
|
||||||
.send();
|
.send()
|
||||||
|
.map(|r| r.status().is_success())
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
@ -254,12 +255,13 @@ fn activate(app: &Application) {
|
||||||
// firmware updates so kiosks pick up new builds without admin push.
|
// firmware updates so kiosks pick up new builds without admin push.
|
||||||
let mut first_iter = true;
|
let mut first_iter = true;
|
||||||
loop {
|
loop {
|
||||||
send_heartbeat_now(&server, &key);
|
let heartbeat_ok = send_heartbeat_now(&server, &key);
|
||||||
if first_iter {
|
if first_iter && heartbeat_ok {
|
||||||
// Successfully heart-beat at least once → consider this boot a
|
// Successfully heart-beat at least once → consider this boot a
|
||||||
// healthy one. Clears the rollback-pending marker so the next
|
// healthy one. Clears the rollback-pending marker so the next
|
||||||
// start doesn't try to roll back a healthy install.
|
// start doesn't try to roll back a healthy install.
|
||||||
firmware::mark_firmware_applied();
|
firmware::mark_firmware_applied();
|
||||||
|
mark_kiosk_healthy();
|
||||||
first_iter = false;
|
first_iter = false;
|
||||||
}
|
}
|
||||||
maybe_apply_firmware_update(&server, &key);
|
maybe_apply_firmware_update(&server, &key);
|
||||||
|
|
@ -317,16 +319,26 @@ fn mark_activity(display_id: u32) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_heartbeat_now(server_url: &str, kiosk_key: &str) {
|
fn send_heartbeat_now(server_url: &str, kiosk_key: &str) -> bool {
|
||||||
let displays = query_displays();
|
let displays = query_displays();
|
||||||
let hw = hwmon::read();
|
let hw = hwmon::read();
|
||||||
server::heartbeat(server_url, kiosk_key, &displays, &hw);
|
server::heartbeat(server_url, kiosk_key, &displays, &hw)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_kiosk_healthy() {
|
||||||
|
let _ = fs::create_dir_all("/run/betterframe");
|
||||||
|
if let Err(err) = fs::write("/run/betterframe/kiosk-healthy", b"ok\n") {
|
||||||
|
warn!("failed to write health marker: {err}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the server whether an update is available. On hit, download + verify
|
/// Ask the server whether an update is available. On hit, download + verify
|
||||||
/// + swap + report + exit (systemd brings up the new binary). On miss or
|
/// + swap + report + exit (systemd brings up the new binary). On miss or
|
||||||
/// error: log + keep running. Designed to be safe to call from any thread.
|
/// error: log + keep running. Designed to be safe to call from any thread.
|
||||||
fn maybe_apply_firmware_update(server_url: &str, kiosk_key: &str) {
|
fn maybe_apply_firmware_update(server_url: &str, kiosk_key: &str) {
|
||||||
|
if std::env::var("BF_ENABLE_APP_OTA").as_deref() != Ok("1") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let current = env!("CARGO_PKG_VERSION");
|
let current = env!("CARGO_PKG_VERSION");
|
||||||
let Some(info) = firmware::check(server_url, kiosk_key, current) else { return };
|
let Some(info) = firmware::check(server_url, kiosk_key, current) else { return };
|
||||||
info!("firmware: update {} → {} available", current, info.version);
|
info!("firmware: update {} → {} available", current, info.version);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue