Commit Graph
151 Commits
Author SHA1 Message Date
phantomptrandClaude Fable 5.1 44e0aba609 Connections: WebDAV and WebDAV (HTTPS) servers (#442)
PROPFIND listings, ranged GET reads, Basic auth, optional self-signed certificate per
connection. Same read-only RemoteFs as SMB/FTP/SFTP, so uploads and installs stream from
the server. Loopback-server test covers sign-in, listing, walk and ranged reads.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EU1Z2mdhAxBrH1yb48pxik
2026-10-11 10:26:11 -07:00
phantomptr d14718960d Merge branch 'main' into pr-441 2026-10-11 10:14:36 -07:00
phantomptrandClaude Fable 5.1 5d41f564e2 Volumes: Eject a USB drive (usb.eject, method 144)
A plain unmount first; FW 13.60's shell keeps /mnt/usbN open, so the app offers
"Eject anyway", which syncs and force-unmounts. Verified on the Phat: /mnt/usb0
gone and stayed gone, helper unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EU1Z2mdhAxBrH1yb48pxik
2026-10-11 10:02:51 -07:00
phantomptrandClaude Fable 5.1 051ea1cc81 Payloads: a Payload Manager tab (list, launch, delete, boot list) and "Store in Payload Manager"; catalogue + scene-tool entries for Payload Manager and LZ4 Compression
Engine routes /api/ps5/pldmgr{,/launch,/delete,/autoload,/store} over Payload Manager's
own HTTP API (:8084). Storing into an existing folder is confirmed first, since Payload
Manager's import removes that folder's other files. Scene-tool pills with a web page
(Payload Manager :8084, LZ4 Compression :5920) open it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EU1Z2mdhAxBrH1yb48pxik
2026-10-11 09:52:30 -07:00
Aleksey Zelenskiy 5dac982774 fix(webui): serve local game cover (sce_sys/icon0.png) from the engine 2026-10-11 12:19:41 +02:00
phantomptr 82e86c63b5 Release v7.0.8 2026-10-11 02:44:28 -07:00
phantomptrandClaude Opus 5.5 92ed5c2af1 Upload: the "network" label for an idle console no longer changes how lanes grow (#437)
cea5c5c2 made a credit wait with an idle console report BN_NETWORK, and
the governor grows lanes (and caps the chunk) on BN_NETWORK, so it began
trying an extra lane where 7.0.6 held. Unintended: more lanes cannot
fetch credit the console has not granted. Control is back to 7.0.6's
rule; only the reported label says "network". A test pins it: a credit
wait with an idle console steers lanes and chunks tick for tick like a
credit wait with no word from the console. The throughput gates measure
the same with the old and new governor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-11 02:15:49 -07:00
phantomptr fed3cf2146 Release v7.0.7 2026-10-11 01:32:20 -07:00
phantomptrandClaude Opus 5.5 ece147d720 Games: hide a title's icon from the PS5 home screen, and show it again (#407)
For shortcuts and loaders that, once set up, only clutter the home
screen. ⋯ → "Hide from home screen" on a Games card; a "Hidden" badge
marks it, "N hidden from the home screen" at the top filters to them,
and ⋯ → "Show on home screen" puts it back.

How: every user's icon table in app.db (tbl_iconinfo_<user>) has a
`visible` flag; the system hides some of its own apps with it. The
helper (app.icon_set, app.hidden_list) flips only that flag: nothing is
deleted, the title stays installed and playable. Guards: title ids only,
system apps (NPXS) refused, tables found by shape (titleId + visible),
app.db backed up once to /data/ps5upload/app.db.before-hide before the
first change, BEGIN IMMEDIATE (fails before any change if the system
holds the lock), and rolled back unless at least one and at most one
row per table changed. The hidden list is read live from app.db, so it
cannot drift from the console, and leaves out the system's own hidden
apps. The home screen redraws when an app is next opened and closed;
the console shows a notification saying so.

Verified on the Phat (FW 13.60): WebKit Autoloader hidden, listed, shown
again; a system app and an unknown id refused; the backup written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-11 00:36:44 -07:00
phantomptrandClaude Opus 5.5 ba48655988 Lab: the late-listener port test reserves its ports instead of releasing them
wait_for_ports_waits_for_listeners_that_appear_late picked ports by
binding and dropping them, so on CI (1,500 tests in parallel) another
test could take one and answer on it before the test listened: CI saw
'ready' after 452 ms when the second listener only opened at 800 ms.
The ports are now bound and held without listening (socket2, already in
the lockfile) and start listening on cue. 12 parallel copies pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-11 00:21:49 -07:00
phantomptrandClaude Opus 5.5 cea5c5c264 Upload: "Limited by: console memory" when the console was idle was really the network (#437)
The sender called any wait for the console's credit "console memory"
unless the console reported its disk or workers as the limit. When the
console reports its queue ran dry, it is idle, waiting for data: the
credit is slow in transit (here a Windows Internet Connection Sharing
bridge on a CPU busy converting), so the cause is the network.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-11 00:18:56 -07:00
phantomptr 2ace14e90f Release v7.0.6 2026-10-10 23:26:42 -07:00
phantomptrandClaude Opus 5.5 eac9f670a4 Changelog for 7.0.6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 23:21:56 -07:00
phantomptrandClaude Opus 5.5 516bfee468 A console whose address changed is found and offered (#430)
When the router hands the PS5 a new address, the saved one stops
answering and the app said the helper was not running. Now, while the
active console is down, the desktop and Android apps scan the network
(at most every five minutes) and ask the engine about each PS5 running
our helper: POST /api/ava1/same-console {old, new} connects to the new
address expecting the key pinned for the old one and answers same,
different or unknown. Only "same" shows a banner: "Your PS5 now answers
at X", with Switch (re-points the console, keeping its name and history)
and Dismiss. Another PS5 is never offered; the check pins nothing.

Tested against the C server (same at a new address, another console, no
pin, nothing answering) and against the real consoles: the Pro's key
pinned under a made-up old address matches the Pro and not the Phat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 23:21:44 -07:00
phantomptr 6cd4f021d8 Release v7.0.5 2026-10-10 23:11:20 -07:00
phantomptr 9e17809797 Release v7.0.4 2026-10-10 23:05:52 -07:00
phantomptrandClaude Opus 5.5 d2dc3f703c 7z on 32-bit Android: archives over 4 GiB no longer fail with "dist overflow" (#434)
sevenz-rust2 turns 7z sizes (u64 in the format) into usize before using
them as read limits: a block's packed size caps the decoder's input, and
block and file unpacked sizes cap the output and the CRC check. On the
32-bit Android build (armv7, in the APK next to arm64) usize is 32 bits,
so a limit past 4 GiB wraps: a 4.7 GB block was cut to 405 MB of input,
the LZMA decoder ran out inside a chunk and said "dist overflow", and any
file over 4 GiB was cut short. Game backups are tens of GB in one block.

sevenz-rust2 0.23.0 is vendored in third_party/ (as unrar is) with those
sizes kept u64 end to end; nothing changes on 64-bit. 0.24.0 still has
the casts. Verified on linux/arm/v7: a 4.7 GB single-block archive failed
after 405 MB before and decodes in full with its CRC after, and 6 GiB of
LZMA-coded output decodes correctly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 23:03:10 -07:00
phantomptr c7fa4d068a Release v7.0.3 2026-10-10 22:49:21 -07:00
phantomptr 72fe7f84d8 Release v7.0.2 2026-10-10 22:33:31 -07:00
phantomptr bc973486ad Release v7.0.1 2026-10-10 19:19:38 -07:00
phantomptrandClaude Opus 5.5 f8906c3271 Collection: show a scan's progress, and join a running scan instead of failing
The engine reports what a scan is doing (finding, reading, naming, saving),
which folder and item, and how many games are named; the screen shows it as a
progress card with the item being read and the time so far, and a last-scanned
line afterwards. A second scan request joins the running one: the Collection is
one per computer, and pressing Scan during the automatic refresh used to show
'The collection could not be read: a scan is already running'.

Also removes Import from PS Game Library (the engine route, its code and the
menu items): that tool was never public.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 19:15:50 -07:00
phantomptrandClaude Opus 5.5 90489a84a2 Android: install and download from a link, install from a saved server, and the online title lookup work in the Android build
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 16:07:54 -07:00
phantomptrandClaude Opus 5.5 493fec8e7a Android: the community cheat search and download work in the Android build
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 16:07:54 -07:00
phantomptrandClaude Opus 5.5 d89eabe0bb Drop-downs draw their own chevron; Bug report fills the page; no Android build warnings
Also restores the lockfile's libc fields lost when the bundled font was removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:18:55 -07:00
phantomptrandClaude Opus 5.5 a72912a547 ava1: a job cancelled on the console ends its sender, and a sender never waits forever
job.cancel stopped a job on the console without telling the session it
was attached to: the session stayed up, so the sender waited for a
JobDone that never came. The console now tells that session first
(JobDone with ERR_CANCELLED for a job it receives, JobCancel for one it
sends).

The engine's sender also bounds the wait: a receiver that says nothing
about the job for 10 minutes on a live session (no Status, no other
frame) gets JobCancel{ERR_STALLED} and the job fails. The wait for the
map is bounded the same way and honours the cancel flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:43:32 -07:00
phantomptr f2cddc0a28 Merge branch 'fix-payload' 2026-10-10 13:15:04 -07:00
phantomptr 769195f496 Merge branch 'fix-engine' 2026-10-10 13:14:53 -07:00
phantomptrandClaude Opus 5.5 d88d330870 payload/ava1: console-to-console audit fixes
- A JobCancel reaches a job only when it is parked or attached to the
  session the cancel came on, so a late cancel from an old direct send
  no longer stops the upload the relay re-attached. The sending
  console's watcher only hangs up when its job was replaced.
- c2c.send replaces only an earlier send the same device started;
  any other job under that id is left alone (ERR_BUSY, before dialling).
- A live ticket decides even for a paired key: the session is the
  ticket's restricted one, owned by the ticket's owner.
- A session's terms (restricted/outbound/r_job/r_owner/r_root) are
  written in the locked section that publishes it.
- FileRetry is de-duplicated per file and capped at the manifest size.
- c2c.send checks the read policy before stat; a dial that succeeds
  with some lanes failing no longer leaves a stale reason; a stale
  comment and an unused include are gone.

SPEC.md §11 and §18 say the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:14:38 -07:00
phantomptrandClaude Opus 5.5 3d89a27854 engine: test that a path named twice is previewed for the trash once
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:14:13 -07:00
phantomptrandClaude Opus 5.5 d421f84262 engine: clippy fixes for the new code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:09:19 -07:00
phantomptrandClaude Opus 5.5 94c4217f23 engine: job file lists are shared, not copied under the lock; finalize I/O off async workers
/api/jobs/{id}/files clones an Arc under the jobs lock and serializes
after releasing it. The install history write, the source-copy removal and
the organizer's folder stats run off the async workers. The icon cache
recounts its size every 256 writes so the running total cannot drift.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:05:46 -07:00
phantomptrandClaude Opus 5.5 373bb1cf88 engine: bound the failure-log map and the helper log carry; journal prunes on a clock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:03:14 -07:00
phantomptrandClaude Opus 5.5 f7af95c050 fpkg: a homebrew with a minimal param.json is a game, not DLC
The DLC rule (no applicationCategoryType and no applicationDrmType) also
matched a homebrew's minimal param.json. A DLC carries no eboot.bin, so
the rule now requires that too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:02:05 -07:00
phantomptrandClaude Opus 5.5 04e522f71b engine: job events are sent under the jobs lock, so 'running' never follows the end
The progress ticker built its snapshot under the lock but sent it after;
a job finishing in between let a stale 'running' reach clients after
'done'. Both the ticker and set_job now send while holding the lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:59:53 -07:00
phantomptrandClaude Opus 5.5 6d3cedeaf5 engine: install slots ignore name case, ended installs are pruned, sizes promote
One console is one install slot whatever the case of its host name. An
install that ended without reaching Done or Failed is now pruned like a
finished one instead of being kept until restart. iec_bytes no longer
prints "1024.0 KiB": a value that rounds to 1024 of a unit moves up one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:58:35 -07:00
phantomptrandClaude Opus 5.5 67f52766d4 fpkg: an AMPR pack manifest whose pack count overflows its layout is refused
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:56:47 -07:00
phantomptrandClaude Opus 5.5 920c0d788c engine: no panic on a non-ASCII app folder or a huge pack field width
An app folder name of nine bytes with a multi-byte character was sliced
mid-character; title ids are now checked by bytes. A pack_pattern field
wider than 64 ("{id:065536}") is a profile error (400) instead of a
format! panic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:56:05 -07:00
phantomptrandClaude Opus 5.5 9b67a7c4a6 engine: a remote fetch refuses sizes that overflow instead of wrapping
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:54:47 -07:00
phantomptrandClaude Opus 5.5 c1701d091d engine: the bandwidth cap reaches relays and is never lost to rounding
A console-to-console relay now honours the outbound cap (the request's
bandwidth_cap_mbps, else the environment's) like an upload; the direct
route is not paced since its bytes never cross this computer. A tiny cap
no longer rounds to 0 (= no cap), and a lane cancelled while waiting on
the pacer gives its reserved budget back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:54:17 -07:00
phantomptrandClaude Opus 5.5 961f2a4674 ava1: a direct console-to-console send always gives up, and frees the receiver
An unreadable job status skipped both the give-up and the stall checks, so
a direct send could poll forever. After falling back to the relay, the
engine now also cancels the receiving console's half of the direct job (it
owns it; the journal stays for the resume), and a relay still refused as
busy says why the direct route was given up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:51:34 -07:00
phantomptrandClaude Opus 5.5 89a8445973 Collection covers: a cover read out again shows, instead of the one cached before
A deep rescan can read a new cover out of a game whose files did not
change, and the cover's URL was versioned only by those files, so the old
image stayed (and the data-URL cache, keyed by game only, answered with the
old bytes too). The engine now records the saved cover's size and modified
time (cover_stamp, an optional index field) and the game page's cover URL
carries it; the client folds it into the cover version and keys the
data-URL cache by version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:50:48 -07:00
phantomptrandClaude Opus 5.5 f78cb43dfb engine: a second build of the same output is refused, not raced
Builds claim their .partial (and LZ4 spool) before the job exists; a second
build of the same output gets 409 instead of deleting and overwriting the
first one's file. The image writer no longer removes a .partial blindly,
never removes one it could not create, and a cancel that lands after the
image was finished no longer reports it cancelled. The handlers' file
checks run off the async workers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:50:10 -07:00
phantomptrandClaude Opus 5.5 f35455afe8 engine: a link download's partial belongs to its worker and its own link
Cancel no longer deletes the .partial under a running worker or a live
retry: the worker removes its own partial on exit, and a cancelled entry
stays live until then. A partial is resumed only when its sidecar
(<name>.partial.json: host, path, size, ETag/Last-Modified) names the same
link and both its head and tail bytes match. Stopped downloads are pruned
from the registry after 30 minutes or beyond 64, and the start route's
file work runs off the async workers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:47:35 -07:00
phantomptrandClaude Opus 5.5 fe3e088381 engine: destructive routes and pairing require the console they act on
Twelve routes (write-bytes, app lifecycle/register, sdk patch/restore,
unmount, chmod, copy, cleanup, health fix, SMP image-rw, profile activate)
and four pairing routes still fell back to the default console when addr
was missing. They now answer 400. An addr with an empty host (":1234")
also counts as missing. Every client caller already sends addr.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:47:35 -07:00
phantomptrandClaude Opus 5.5 5d50108823 engine: keep collection ids, covers, trash and organizer moves inside their folders
A package's titleId and an imported library index both became file paths
unchecked. Ids must now be a bare Game ID, an import drops games with a bad
id and re-derives covers, a cover is served only by a bare file name, trash
takes only paths strictly inside a current local root (and de-duplicates),
and organizer moves refuse any path that leaves their folder. The undo log
is rewritten as a run goes and undo replays moves a crash left unrecorded;
same-named folders get their own undo logs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 12:44:16 -07:00
phantomptrandClaude Opus 5.5 1d47c778f5 7.0.0: a new look for the whole app, and fixes that make it faster and sturdier
Not tagged or published yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 11:36:53 -07:00
phantomptrandClaude Opus 5.5 fc67febd7f Link downloads: follow a duplicate, Resume/Replace a taken name; Convert shows its target
- Engine: /api/pkg/remote/download/start takes `existing: resume|replace` for a
  different file already under the download's name (resume moves it to the
  .partial, whose tail is checked against the link; replace deletes it), and
  its 409 carries the file's path and sizes. A live download of the same name
  is answered before anything is taken over.
- Client starts link downloads over the engine API (lib/linkDownload) so the
  409s keep their fields: a duplicate attaches to the running download, and
  Install Package asks Resume (when the file is shorter than the link) or
  Replace instead of the old 'Move or delete it first'.
- Convert & install shows 'Will install on {console}' while it runs; 'Show in
  folder' is hidden where no file manager can open it and says so when
  opening fails.
- Install Package says a refresh is held for the running install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 10:59:27 -07:00
phantomptrandClaude Opus 5.5 154b195c5c Destructive routes: the addr check returns an Option (clippy result_large_err)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 10:28:01 -07:00
phantomptrandClaude Opus 5.5 77f5364069 Engine sizes in IEC units from one formatter
The link-copy space check said 'GB' for 10^9 bytes while the collection export and
the health checks said 'GB' for 2^30. ps5upload_core::units::iec_bytes is now the
one formatter (KiB, MiB, GiB), used by all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 10:25:02 -07:00
phantomptrandClaude Opus 5.5 abda7b524c Engine: disk I/O off async workers, quieter log tail, per-console failure dedup, addr required for destructive routes
- Artwork cache reads/writes run on the blocking pool; the cache size is tracked
  instead of walking the folder on every write; concurrent writes of one entry use
  unique temp names.
- Server-folder copies write on the blocking pool and fail on a failed sync.
- Debug/trace lines keep their own 500-line ring, so per-request and per-range
  lines no longer push warnings out of the log tail; the pkg-host per-range line is
  debug.
- Repeated-failure collapsing is keyed by route and console.
- Delete, move, unregister, process kill, power, user delete, backup restore/delete
  and cheat delete answer 400 without an addr instead of acting on the default
  console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
2026-10-10 10:23:27 -07:00