diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index febf3f4..d101b42 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -22,8 +22,10 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - name: Check concurrent config, sources and history with ThreadSanitizer - run: python3 tests/run_config_tests.py --thread-sanitize + - name: Check concurrent config, sources, history and autoload with ThreadSanitizer + run: | + python3 tests/run_config_tests.py --thread-sanitize + python3 tests/run_autoload_tests.py --thread-sanitize frontend: runs-on: ubuntu-latest diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index f40efa0..703323b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -144,6 +144,22 @@ A multi-file settings request validates fully first, publishes lists before scal settings, and reports 500 if any publication fails. Earlier completed files stay published; per-file atomicity does not provide an all-or-nothing transaction. +Autoload now owns one joinable worker and returns a coherent locked snapshot. +Active reset preserves waiting/countdown/execution; terminal reset cannot rerun +it. Abort/stop interrupt delays and loader waits. Sequences are parsed once from +one regular file (4095 bytes, entries up to 511 bytes, delays up to one hour); +status retains that running sequence if the file is edited. Processed counts and +per-entry outcomes distinguish success/failure/skip. Anonymous/foreign status +reads remain passive; an authorized read explicitly signals frontend readiness. + +Loader connects time out after five seconds, and full transfers after thirty; +nonblocking/poll loops handle partial sends and cooperative cancellation. A +cancel cannot undo a payload already executed or bytes already sent. The actual +worker, socketpair loader recorder and real HTTP worker fixtures are part of +`make test-host`; `run_autoload_tests.py --thread-sanitize` covers concurrent +status/reset/start paths. The PS-button detector remains the existing headless +per-read implementation. + Collected arrays are limited to **4,096 items** and **64 MiB** of allocated array capacity, whichever is smaller for the item type. Repository parsing accepts up to **16 MiB** of input text. These bounds apply to the parser/scanner collections; @@ -182,7 +198,7 @@ build a candidate under `scratch/` rather than run `make clean`: ```bash mkdir -p scratch docker run --rm --network=none -v "$(pwd):/src" -w /src \ - ps5-payload-sdk-pldmgr make ELF=scratch/pldmgr-step5.elf + ps5-payload-sdk-pldmgr make ELF=scratch/pldmgr-candidate.elf ``` This command assumes the SDK image, frontend distribution, and embedded CA diff --git a/Makefile b/Makefile index 3548c04..99cb757 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,10 @@ test-host: HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_allocation_tests.py HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_integrity_tests.py HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_storage_tests.py + HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_autoload_tests.py + HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_launcher_tests.py HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_config_tests.py + HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_http_tests.py --autoload-only HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_http_tests.py --config-only HOST_CC="$(HOST_CC)" $(PYTHON) tests/run_http_tests.py diff --git a/frontend/src/components/views/AutoloadOverlay.jsx b/frontend/src/components/views/AutoloadOverlay.jsx index 3c920d1..c1073eb 100644 --- a/frontend/src/components/views/AutoloadOverlay.jsx +++ b/frontend/src/components/views/AutoloadOverlay.jsx @@ -3,12 +3,14 @@ import { CheckCircle2, AlertTriangle, Loader2 } from 'lucide-react' import { useTranslation } from 'react-i18next' import { cn } from '../../utils/helpers' import PayloadName from '../ui/PayloadName' +import { autoloadPhase, autoloadItemProgress } from '../../utils/autoloadProgress' const AutoloadOverlay = ({ status, onCancel, onFinish, isPS5 }) => { const { t } = useTranslation() - const isCountdown = status.remaining > 0 || (status.remaining === 0 && !status.current); - const isExecuting = status.remaining === 0 && !!status.current && status.current !== 'DONE'; - const isDone = status.current === 'DONE'; + const phase = autoloadPhase(status); + const isCountdown = phase === 'waiting' || phase === 'countdown'; + const isExecuting = phase === 'executing'; + const isDone = phase === 'done'; const payloadList = (typeof status.list === 'string') ? status.list.split(',').filter(p => p.trim() !== '') : []; const listRef = useRef(null); const displayTotal = status.total > 0 ? status.total : payloadList.length; @@ -139,7 +141,7 @@ const AutoloadOverlay = ({ status, onCancel, onFinish, isPS5 }) => { > {t("autoload_overlay.return_btn", "Return to Dashboard")} - ) : isCountdown ? ( + ) : (isCountdown || isExecuting) ? (