Box 5: one browser profile, controls read even when Chromium calls its window hidden, the launcher never waits on itself
Found on the server's box after the update to 4: - Chromium called its whole window "not showing" (it took itself for minimized) while its page was on the screen; the reader (like XBot's) skipped anything not showing, so a page had no numbers. Now: visible with a place on the screen counts, containers are walked through, and only a page that isn't showing (a background tab) is left out. - Two browser profiles: Chromium's own (~/.config/chromium, where a person logged in by hand) and AnyBot's (~/.config/anybot-browser); the launcher used AnyBot's and Threads showed as logged out. One profile now (anybot-profile → Chromium's own; a box with only AnyBot's keeps that); both folders stay as they were. - The launcher's lock fd went to Chromium, which then held it for its whole life: the next start waited 30 s and failed. And its flags line had been lost in an edit. box_numbers_are_exact passes twice on a box from this image; the launcher answers in 0.09 s when the browser runs; box_screen_is_exact passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ac00aea265
commit
338c49b0ee
|
|
@ -27,6 +27,6 @@ RUN chmod +x /usr/local/bin/anybot-box-start /usr/local/bin/anybot-a11y /usr/loc
|
||||||
# Accessibility on for every app, including those started over `docker exec`.
|
# Accessibility on for every app, including those started over `docker exec`.
|
||||||
ENV DISPLAY=:1 SCREEN_SIZE=1280x800x24 GTK_MODULES=atk-bridge GTK_A11Y=atspi GNOME_ACCESSIBILITY=1 NO_AT_BRIDGE=0
|
ENV DISPLAY=:1 SCREEN_SIZE=1280x800x24 GTK_MODULES=atk-bridge GTK_A11Y=atspi GNOME_ACCESSIBILITY=1 NO_AT_BRIDGE=0
|
||||||
EXPOSE 6080
|
EXPOSE 6080
|
||||||
LABEL anybot.box.version="4"
|
LABEL anybot.box.version="5"
|
||||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||||
CMD ["/usr/local/bin/anybot-box-start"]
|
CMD ["/usr/local/bin/anybot-box-start"]
|
||||||
|
|
|
||||||
13
box/a11y
13
box/a11y
|
|
@ -4,7 +4,8 @@
|
||||||
in screen pixels. Web pages are in it too (Chromium runs with renderer accessibility on).
|
in screen pixels. Web pages are in it too (Chromium runs with renderer accessibility on).
|
||||||
AnyBot numbers them on the bot's picture; a click by number lands on the centre.
|
AnyBot numbers them on the bot's picture; a click by number lands on the centre.
|
||||||
|
|
||||||
Adapted from XBot's box/box-a11y. Usage: a11y [--limit N] [--budget SECONDS]
|
Adapted from XBot's box/box-a11y (which skips anything not "showing"; Chromium can say that of
|
||||||
|
its whole window). Usage: a11y [--limit N] [--budget SECONDS]
|
||||||
Exit 2 when AT-SPI itself is unreachable.
|
Exit 2 when AT-SPI itself is unreachable.
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
|
@ -92,10 +93,16 @@ def main():
|
||||||
except Exception: # noqa: BLE001
|
except Exception: # noqa: BLE001
|
||||||
return
|
return
|
||||||
st = state(node)
|
st = state(node)
|
||||||
if depth > 1 and (st is None or not (st.contains(Atspi.StateType.SHOWING) and st.contains(Atspi.StateType.VISIBLE))):
|
showing = bool(st and st.contains(Atspi.StateType.SHOWING))
|
||||||
|
visible = bool(st and st.contains(Atspi.StateType.VISIBLE))
|
||||||
|
# A page that isn't showing is a tab in the background: none of it is on the screen.
|
||||||
|
if role in ("document web", "document frame") and not showing:
|
||||||
return
|
return
|
||||||
|
# Otherwise "showing" isn't trusted: Chromium can call its whole window not showing (it
|
||||||
|
# took itself for minimized under this window manager) while its page is on the screen.
|
||||||
|
# Visible with a place on the screen is what counts; containers are walked through.
|
||||||
box = extents(node)
|
box = extents(node)
|
||||||
if depth > 1 and (box is None or not onscreen(box)):
|
if depth > 1 and (not visible or box is None or not onscreen(box)):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
name = (node.get_name() or "").strip()
|
name = (node.get_name() or "").strip()
|
||||||
|
|
|
||||||
26
box/browser
26
box/browser
|
|
@ -11,8 +11,18 @@ if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -r /tmp/anybot-dbus.env ]]; then
|
||||||
source /tmp/anybot-dbus.env
|
source /tmp/anybot-dbus.env
|
||||||
export DBUS_SESSION_BUS_ADDRESS
|
export DBUS_SESSION_BUS_ADDRESS
|
||||||
fi
|
fi
|
||||||
PROFILE=/home/bot/.config/anybot-browser
|
# One profile. The box used to have two: Chromium's own (~/.config/chromium, what its menu entry
|
||||||
mkdir -p "$PROFILE"
|
# opened, where a person logged in by hand) and AnyBot's (~/.config/anybot-browser, what the
|
||||||
|
# browser tools opened), so a site could be logged in in one and not the other. Chromium's own
|
||||||
|
# is the one now (the other stays as it was); a box that only has AnyBot's keeps that.
|
||||||
|
PROFILE=/home/bot/.config/anybot-profile
|
||||||
|
if [[ ! -e "$PROFILE" ]]; then
|
||||||
|
if [[ -d /home/bot/.config/chromium/Default || ! -d /home/bot/.config/anybot-browser/Default ]]; then
|
||||||
|
mkdir -p /home/bot/.config/chromium && ln -s /home/bot/.config/chromium "$PROFILE"
|
||||||
|
else
|
||||||
|
ln -s /home/bot/.config/anybot-browser "$PROFILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
FLAGS=(--no-sandbox --test-type --user-data-dir="$PROFILE" --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222
|
FLAGS=(--no-sandbox --test-type --user-data-dir="$PROFILE" --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222
|
||||||
--remote-allow-origins=* --force-renderer-accessibility --disable-blink-features=AutomationControlled
|
--remote-allow-origins=* --force-renderer-accessibility --disable-blink-features=AutomationControlled
|
||||||
--disable-dev-shm-usage --disable-gpu --use-angle=swiftshader --enable-unsafe-swiftshader --password-store=basic
|
--disable-dev-shm-usage --disable-gpu --use-angle=swiftshader --enable-unsafe-swiftshader --password-store=basic
|
||||||
|
|
@ -22,14 +32,16 @@ FLAGS=(--no-sandbox --test-type --user-data-dir="$PROFILE" --remote-debugging-ad
|
||||||
# over the profile ("in use"): one at a time until the first is listening.
|
# over the profile ("in use"): one at a time until the first is listening.
|
||||||
exec 9>/tmp/.anybot-browser.lock
|
exec 9>/tmp/.anybot-browser.lock
|
||||||
flock -w 30 9 || true
|
flock -w 30 9 || true
|
||||||
if pgrep -u bot -f -- "--user-data-dir=$PROFILE" >/dev/null; then
|
if pgrep -u bot -f -- "--user-data-dir=$PROFILE" >/dev/null || pgrep -u bot -f -- "--user-data-dir=$(readlink -f "$PROFILE")" >/dev/null; then
|
||||||
flock -u 9
|
flock -u 9
|
||||||
exec chromium "${FLAGS[@]}" "$@"
|
exec chromium "${FLAGS[@]}" "$@" 9>&-
|
||||||
fi
|
fi
|
||||||
# A profile from before this box (a new container) still names the old one in its lock.
|
# A profile from before this box (a new container) still names the old one in its lock.
|
||||||
rm -f "$PROFILE/SingletonLock" "$PROFILE/SingletonSocket" "$PROFILE/SingletonCookie"
|
rm -f "$PROFILE"/SingletonLock "$PROFILE"/SingletonSocket "$PROFILE"/SingletonCookie
|
||||||
setsid chromium "${FLAGS[@]}" "${@:-about:blank}" >/tmp/anybot-browser.log 2>&1 < /dev/null &
|
# (The lock's fd is not handed to the browser: it would hold the lock for its whole life, and the
|
||||||
for _ in $(seq 1 60); do
|
# next start would wait on it.)
|
||||||
|
setsid chromium "${FLAGS[@]}" "${@:-about:blank}" >/tmp/anybot-browser.log 2>&1 < /dev/null 9>&- &
|
||||||
|
for _ in $(seq 1 100); do
|
||||||
python3 -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:9222/json/version', timeout=1).close()" 2>/dev/null && break
|
python3 -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:9222/json/version', timeout=1).close()" 2>/dev/null && break
|
||||||
sleep 0.25
|
sleep 0.25
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -2003,7 +2003,7 @@ mod tests {
|
||||||
assert!(!in_schedule_window("03:00", t("02:59")));
|
assert!(!in_schedule_window("03:00", t("02:59")));
|
||||||
assert!(in_schedule_window("23:30", t("00:10")));
|
assert!(in_schedule_window("23:30", t("00:10")));
|
||||||
assert!(!in_schedule_window("bad", t("00:10")));
|
assert!(!in_schedule_window("bad", t("00:10")));
|
||||||
assert_eq!(wanted_version(), "4");
|
assert_eq!(wanted_version(), "5");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue