Let the extension update itself, and host the dashboard
Chrome has no update channel for an unpacked extension, so every pull left one manual step: click reload on its card. The dashboard now publishes the version its own checkout ships at /api/autobuyer/status, and the extension reloads itself when it is behind — chrome.runtime.reload() re-reads the folder from disk, which the update check has already pulled into. It only ever runs code that is on disk, so a reload that changes nothing is reported and waited out rather than repeated; a dashboard that is behind is ignored. Also adds the deploy stack for running the dashboard on the droplet, next to the autotrader one: it joins that nginx's network and renders a server block into its conf.d rather than standing up a second ingress. AUTOFIRMER_DB moves the SQLite file onto a volume, since the working directory in a container is replaced on every deploy. And waitFor gained `hidden`: an absent gate matched on DOM presence only, so a modal that closes by going display:none could never satisfy it. The extension grew a visibility probe for this — locate cannot answer it, because absent and hidden are both errors there and a wait gate has to tell them apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1f4459985a
commit
d1e8668440
+25
-6
@@ -34,7 +34,7 @@ HEARTBEAT_SECONDS = 2.0
|
||||
# Bumped whenever the step vocabulary or the locate protocol changes. Reported in
|
||||
# the heartbeat so the dashboard can say "restart your runner" instead of letting
|
||||
# a stale process fail on a step type it has never heard of.
|
||||
VERSION = "0.17.0"
|
||||
VERSION = "0.18.0"
|
||||
|
||||
# Shared with the heartbeat thread: whether a run is currently executing.
|
||||
_busy = threading.Event()
|
||||
@@ -80,9 +80,14 @@ def run_one_step(dash: Dashboard, step: dict, opts, rng, report, run_id: int | N
|
||||
# `absent`, until it is gone. Nothing is clicked or typed. Whatever has to
|
||||
# change the page — a person solving a challenge, a modal closing itself,
|
||||
# a slow server — happens outside this run.
|
||||
#
|
||||
# `hidden` widens an absent gate from "removed from the DOM" to "no
|
||||
# longer visible": a modal that closes by going display:none never stops
|
||||
# matching its selector, so the plain gate can only ever time out.
|
||||
selector = step["selector"]
|
||||
absent = bool(step.get("absent"))
|
||||
goal = "disappear" if absent else "appear"
|
||||
by_sight = absent and bool(step.get("hidden"))
|
||||
goal = "disappear from view" if by_sight else "disappear" if absent else "appear"
|
||||
timeout_s = float(step.get("timeoutSeconds", 120))
|
||||
deadline = time.time() + timeout_s
|
||||
announced = False
|
||||
@@ -93,10 +98,24 @@ def run_one_step(dash: Dashboard, step: dict, opts, rng, report, run_id: int | N
|
||||
raise actions.StepError("cancelled while waiting")
|
||||
|
||||
try:
|
||||
dash.locate(selector, int(step.get("index", 0)),
|
||||
step.get("urlPattern", "") or opts.url,
|
||||
opts.timeout, step.get("openUrl", "") or "")
|
||||
if not absent:
|
||||
seen = dash.locate(selector, int(step.get("index", 0)),
|
||||
step.get("urlPattern", "") or opts.url,
|
||||
opts.timeout, step.get("openUrl", "") or "",
|
||||
options={"op": "visible"} if by_sight else None)
|
||||
if by_sight:
|
||||
# An extension too old for the probe quietly does an ordinary
|
||||
# locate instead, whose result has no `visible` key — reading
|
||||
# that as "gone" would wave the gate through on a visible
|
||||
# element, so insist the answer is the one we asked for.
|
||||
if seen.get("op") != "visible":
|
||||
raise actions.StepError(
|
||||
"waitFor `hidden` needs AutoBuyer extension 0.12.0+ — "
|
||||
"reload it in chrome://extensions"
|
||||
)
|
||||
if not seen.get("visible"):
|
||||
report(f"{selector} is out of sight ({seen.get('reason') or 'hidden'})")
|
||||
break
|
||||
elif not absent:
|
||||
report(f"{selector} appeared")
|
||||
break
|
||||
# Still there. Keep waiting for it to go.
|
||||
|
||||
Reference in New Issue
Block a user