Step 1 in progress: the settings page server, probes, teaching pages and UI (not deployed yet)
- settings/server.py: read-only routes (overview, keys, computers, gear, companion, logs, history, help facts, key guide / cheat sheet / where things are), the editing-code check with a lockout, LAN-only binding with a per-minute rebind - settings/probes.py: fixed read-only probes per computer; whole lists fetched and matched locally - settings/keyguide.py: the generated teaching pages - settings/ui: the page, every screen read-only - status_panel.py: snapshot.json every 5 s for the page; the Companion database lookup prefers the running build's folder and skips a database that will not open (a stale v5.1 folder was breaking it) - config.json: every computer's record (what runs there, network ports, done-by-hand ticks), the editing code (kept in the repo, the user's choice), an empty gear list - install.sh: the settings page as a second LaunchAgent; settings/ and schema.py deployed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+49
-8
@@ -12,11 +12,12 @@
|
||||
set -e
|
||||
SRC=${0:A:h}
|
||||
LABEL=org.waterschurch.status-panel
|
||||
SETTINGS_LABEL=org.waterschurch.status-settings
|
||||
# App Support, not ~/Documents: launchd-run python3 cannot read ~/Documents.
|
||||
DEST="$HOME/Library/Application Support/status-panel"
|
||||
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
||||
DOMAIN="gui/$(id -u)"
|
||||
CODE=(status_panel.py coremidi.py netgear.py make_page.py push_page.py nav_keys.py atem_watch.js atem_state.js nav_templates.json)
|
||||
CODE=(status_panel.py coremidi.py netgear.py schema.py make_page.py push_page.py nav_keys.py atem_watch.js atem_state.js nav_templates.json)
|
||||
KEEP_CONFIG=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
@@ -26,17 +27,45 @@ for arg in "$@"; do
|
||||
esac
|
||||
done
|
||||
|
||||
restart_agent() {
|
||||
launchctl bootout "$DOMAIN/$LABEL" 2>/dev/null || true
|
||||
restart_agent() { # $1 = label, $2 = plist
|
||||
local label=${1:-$LABEL} plist=${2:-$PLIST}
|
||||
launchctl bootout "$DOMAIN/$label" 2>/dev/null || true
|
||||
# bootout returns before the old job is gone; bootstrapping too early fails with "5: Input/output error".
|
||||
for i in {1..50}; do launchctl print "$DOMAIN/$LABEL" >/dev/null 2>&1 || break; sleep 0.2; done
|
||||
for i in {1..50}; do launchctl print "$DOMAIN/$label" >/dev/null 2>&1 || break; sleep 0.2; done
|
||||
for attempt in 1 2 3; do
|
||||
launchctl bootstrap "$DOMAIN" "$PLIST" && break
|
||||
[[ $attempt == 3 ]] && { echo "launchctl bootstrap failed" >&2; exit 1; }
|
||||
launchctl bootstrap "$DOMAIN" "$plist" && break
|
||||
[[ $attempt == 3 ]] && { echo "launchctl bootstrap failed for $label" >&2; exit 1; }
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
SETTINGS_PLIST="$HOME/Library/LaunchAgents/$SETTINGS_LABEL.plist"
|
||||
write_settings_plist() {
|
||||
cat > "$SETTINGS_PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key><string>$SETTINGS_LABEL</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/bin/python3</string>
|
||||
<string>-m</string>
|
||||
<string>settings.server</string>
|
||||
<string>--data-dir</string>
|
||||
<string>$DEST</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key><string>$DEST</string>
|
||||
<key>RunAtLoad</key><true/>
|
||||
<key>KeepAlive</key><true/>
|
||||
<key>ThrottleInterval</key><integer>10</integer>
|
||||
<key>AbandonProcessGroup</key><true/>
|
||||
<key>StandardErrorPath</key><string>$HOME/Library/Logs/status-settings.err.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
}
|
||||
|
||||
write_plist() { # $1 = exit timeout in seconds
|
||||
cat > "$PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -80,8 +109,9 @@ PY
|
||||
|
||||
if [[ "$1" == "--remove" ]]; then
|
||||
launchctl bootout "$DOMAIN/$LABEL" 2>/dev/null || true
|
||||
rm -f "$PLIST"
|
||||
echo "removed $LABEL (files left in $DEST)"
|
||||
launchctl bootout "$DOMAIN/$SETTINGS_LABEL" 2>/dev/null || true
|
||||
rm -f "$PLIST" "$SETTINGS_PLIST"
|
||||
echo "removed $LABEL and $SETTINGS_LABEL (files left in $DEST)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -121,6 +151,11 @@ if [[ $KEEP_CONFIG == 0 ]]; then
|
||||
fi
|
||||
for f in $CODE; do [[ -f "$SRC/$f" ]] && cp "$SRC/$f" "$DEST/"; done
|
||||
[[ -f "$SRC/atem-reference.xml" ]] && cp "$SRC/atem-reference.xml" "$DEST/"
|
||||
# The settings page (its own LaunchAgent) and the record of coloured page-number keys (site-owned: never overwritten).
|
||||
if [[ -d "$SRC/settings" ]]; then
|
||||
rm -rf "$DEST/settings" && cp -R "$SRC/settings" "$DEST/" && find "$DEST/settings" -name "__pycache__" -prune -exec rm -rf {} + 2>/dev/null
|
||||
fi
|
||||
[[ -f "$SRC/nav_locations.json" && ! -f "$DEST/nav_locations.json" ]] && cp "$SRC/nav_locations.json" "$DEST/"
|
||||
if [[ -d "$SRC/companion-objects" ]]; then
|
||||
rm -rf "$DEST/companion-objects" && cp -R "$SRC/companion-objects" "$DEST/"
|
||||
fi
|
||||
@@ -132,3 +167,9 @@ restart_agent
|
||||
echo "installed $LABEL -> $DEST (exit timeout ${EXIT_TIMEOUT}s)"
|
||||
echo "log: ~/Library/Logs/status-panel.log"
|
||||
wait_for_start "$T" || true
|
||||
if [[ -d "$DEST/settings" ]]; then
|
||||
write_settings_plist
|
||||
restart_agent "$SETTINGS_LABEL" "$SETTINGS_PLIST"
|
||||
PORT=$(/usr/bin/python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("site",{}).get("settings_port",8020))' "$DEST/config.json")
|
||||
echo "settings page: http://$(hostname -s).local:$PORT/ (log: ~/Library/Logs/status-settings.log)"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user