Files
Classroom_Desktop/tools/lab/parent-call-rig
T
ekklesiaandClaude Opus 5 18cf0249dd feat: give Parent Call a mark that says what it does
Three marks were put on a real panel and judged at the size the bar
actually draws them. A bell sat inches from Plasma's own notification
bell and meant something entirely different. A handset with an outgoing
arrow read as a telephone feature. Breeze has people and it has
telephones and the two never meet, so this is drawn in Breeze's language
instead: an adult, a child, and one small speech bubble, on Breeze's
22-unit grid with its ColorScheme-Text class, so it recolours with the
session and needs no second file for the light theme.

Quick Launch carries it. The Icon widget copies the entry into the user's
home so an update could never change it; a task manager reads the entry
live but also shows every running window, which filled the auxiliary
corner with the lesson's tasks.

One defect found on the way, and it affected the Wonder Ink icon that is
already shipping: gdk-pixbuf recognises an SVG by sniffing the first
bytes, and a licence-length comment above the opening tag pushes it out
of that window. Every GTK program reported "couldn't recognize the image
file format" while Qt rendered the same file happily. The comments live
inside <svg> now.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 12:47:58 -05:00

156 lines
5.2 KiB
Bash
Executable File

#!/bin/bash
# A Parent Call sanctuary that cannot reach the sanctuary.
#
# The real coordinator, from the control computer, running in the lab
# against a broker on loopback and a ProPresenter that is a mock. The
# church's own networks are rejected from inside the container first, so
# a wrong host in a config file cannot put a child's name on the real
# screen. Coordinator development has done that once already.
#
# tools/lab/parent-call-rig up [MODE] # off | approval | auto
# tools/lab/parent-call-rig mode MODE
# tools/lab/parent-call-rig approve|reject
# tools/lab/parent-call-rig watch
# tools/lab/parent-call-rig triggers
# tools/lab/parent-call-rig down
set -uo pipefail
NAME="${LAB_NAME:-classroom-v2-lab}"
SRC="${PARENT_CALL_SRC:-classroom-control:/home/media/docker/parent-call}"
ROOT=classroom/parent-call
inlab() { docker exec "$NAME" "$@"; }
guard() {
# Container-local. This netns belongs to the container alone, so
# nothing on the host or the church network is changed by it.
inlab sh -c '
iptables -C OUTPUT -d 10.30.0.0/16 -j REJECT 2>/dev/null ||
iptables -I OUTPUT -d 10.30.0.0/16 -j REJECT
iptables -C OUTPUT -d 10.40.0.0/16 -j REJECT 2>/dev/null ||
iptables -I OUTPUT -d 10.40.0.0/16 -j REJECT'
for target in 10.40.0.2/1883 10.30.0.2/1025; do
if inlab timeout 4 sh -c "exec 3<>/dev/tcp/${target}" 2>/dev/null; then
echo "REFUSING TO CONTINUE: ${target} is still reachable" >&2
exit 1
fi
done
echo " church networks unreachable from the lab"
}
case "${1:-up}" in
up)
mode="${2:-approval}"
inlab sh -c 'apt-get install -y -qq --no-install-recommends \
mosquitto mosquitto-clients python3-paho-mqtt iptables >/dev/null 2>&1'
guard
inlab sh -c 'mkdir -p /opt/pc-test'
ssh -o BatchMode=yes "${SRC%%:*}" "cd ${SRC#*:} && tar cf - src" \
| docker exec -i "$NAME" sh -c 'cd /opt/pc-test && tar xf -'
echo " coordinator source copied from the control computer"
docker exec -i "$NAME" sh -c 'cat > /opt/pc-test/mosquitto.conf' <<CONF
# Loopback only. Nothing published here can leave the container.
listener 1883 127.0.0.1
allow_anonymous true
persistence false
CONF
docker exec -i "$NAME" sh -c 'cat > /opt/pc-test/coordinator.env' <<ENV
MQTT_HOST=127.0.0.1
MQTT_PORT=1883
MQTT_CLIENT_ID=parent-call-lab
TOPIC_ROOT=$ROOT
PROPRESENTER_BASE_URL=http://127.0.0.1:1025
PROPRESENTER_MESSAGE='Parent Caller'
PROPRESENTER_CHILD_TOKEN=Name
PROPRESENTER_ROOM_TOKEN=Room
PROPRESENTER_TIMEOUT=4
PROPRESENTER_CLEAR_AFTER=20
ROOM_NAMES='nursery=Nursery,k2=K-2,older=Older Kids'
REQUEST_TTL=180
MAX_CHILD_LENGTH=40
MAX_ROOM_LENGTH=32
MAX_CLOCK_SKEW=120
DEFAULT_MODE=$mode
HEALTH_PORT=8099
ENV
docker exec -i "$NAME" sh -c 'cat > /opt/propresenter-mock.py' \
< "$(dirname "$0")/propresenter-mock.py"
# Debian's own mosquitto unit would listen where the lab does not want
# it to. The rig runs its own, on loopback, and nothing else.
inlab sh -c 'systemctl disable --now mosquitto >/dev/null 2>&1;
pkill -f propresenter-mock; pkill -f parent_call.main; pkill mosquitto;
fuser -k 1025/tcp 1883/tcp 2>/dev/null; true'
sleep 3
inlab sh -c 'setsid mosquitto -c /opt/pc-test/mosquitto.conf > /tmp/mosquitto.log 2>&1 &'
inlab sh -c 'setsid python3 /opt/propresenter-mock.py 1025 > /tmp/ppmock.log 2>&1 &'
sleep 2
inlab sh -c 'cd /opt/pc-test && set -a && . ./coordinator.env && set +a &&
setsid env PYTHONPATH=/opt/pc-test/src python3 -m parent_call.main \
> /tmp/coordinator.log 2>&1 &'
sleep 4
# The room points at the loopback broker, never at the church's.
# docker exec needs -i or the heredoc reaches nothing at all, which is
# how this silently left the room pointing nowhere.
docker exec -i "$NAME" python3 - <<'PY'
import pathlib
p = pathlib.Path("/etc/ekklesia-classroom/device.conf")
t = p.read_text()
t = t.replace("MQTT_ENABLED=false", "MQTT_ENABLED=true")
if "MQTT_HOST=127.0.0.1" not in t:
t = t.replace("MQTT_HOST=", "MQTT_HOST=127.0.0.1", 1)
if "\nROOM=" not in t:
t += "\n# Lab only.\nROOM=nursery\n"
p.write_text(t)
PY
"$0" mode "$mode"
inlab tail -3 /tmp/coordinator.log
echo " rig up in mode $mode"
;;
mode)
inlab mosquitto_pub -h 127.0.0.1 -t "$ROOT/mode/set" -m "${2:?mode}"
sleep 1
echo -n " mode is now: "
inlab timeout 3 mosquitto_sub -h 127.0.0.1 -t "$ROOT/mode" -C 1 || true
;;
approve|reject)
id=$(inlab timeout 3 mosquitto_sub -h 127.0.0.1 -t "$ROOT/pending" -C 1 |
python3 -c 'import json,sys; print(json.load(sys.stdin).get("id") or "")')
[ -n "$id" ] || { echo " nothing is waiting"; exit 0; }
inlab mosquitto_pub -h 127.0.0.1 -t "$ROOT/$1" -m "{\"id\": \"$id\"}"
echo " $1ed $id"
;;
watch)
inlab mosquitto_sub -h 127.0.0.1 -t "$ROOT/#" -v
;;
triggers)
inlab sh -c 'cat /tmp/propresenter-mock.log 2>/dev/null || echo "(none)"'
;;
log)
inlab tail -n "${2:-25}" /tmp/coordinator.log
;;
down)
inlab sh -c 'pkill -f parent_call.main; pkill -f propresenter-mock; pkill mosquitto; true'
echo " rig down"
;;
*)
sed -n '2,14p' "$0"
exit 1
;;
esac