15 Commits
Author SHA1 Message Date
AldySan e566676d42 chore(release): bump version to 0.0.3 (#17) 2026-10-28 19:57:10 +07:00
AldySan 9c691290ff docs(api): fix wire-format examples to match the actual responses (#16)
Full audit of every route and response shape in server.c against
docs/API.md, cross-checked with the original flatz implementation
(downloaded and diffed format string by format string). The code is
byte-compatible with the original; the docs were not:

- get_task_progress: lengths/counters/percent are unquoted JSON
  numbers (0x1A2B3C00, 120, 100), not strings
- is_exists: 'size' is an unquoted hex number
- error_code in failure bodies is an unquoted hex number
- document the 'GET /' alias of /api/v2/system
- clarify the is_exists / progress notes accordingly

No code changes — the implementation already matches the original
wire format exactly.
2026-10-28 19:55:58 +07:00
AldySan a33a011f09 fix(api): route POST /api/v2/jobs/<id>/{pause,resume,stop} (#15)
The v2 job-op endpoints were documented (README, docs/API.md) as POST
but route() only dispatched them under GET/HEAD, so POST fell through
to 404. Clients had to work around it by falling back to GET.

- dispatch POST /api/v2/jobs/<id>/<op> to handle_v2_job_op()
- keep GET on the same paths routed (backward compatibility with
  clients written against <= 0.0.2) and document that in API.md

No handler changes: pause/resume/stop semantics are unchanged.
2026-10-28 19:36:26 +07:00
AldySan f8024b09ba chore(release): bump version to 0.0.2 (#12) 2026-10-28 09:41:51 +07:00
AldySan 07f013f9d5 fix: second audit pass — proxy stream lifecycle, paused-state and queue-exit bugs (#11)
* fix(installer,http): accept long signed urls, init temp paths before early failure

- All url holders (registry, proxy pieces, prefetch) now store up to
  2048 chars (TASK_URL_MAX/PROXY_URL_MAX); silently truncated presigned
  S3/Azure urls (>511 chars) previously broke proxied installs.
- install_pieces validates url length up front with a clear error and
  initializes the temp manifest/icon paths so the early-failure paths
  (registry full, network down) cannot unlink() uninitialized stack
  garbage.

* fix(taskman): keep paused jobs paused, detect queue exit while paused

- The REGISTERED->RUNNING promotion no longer includes PAUSED: a paused
  task has transferred_total > 0, so the old condition flipped every
  pause back to RUNNING within one 1s poll (dashboard/API showed a
  paused download as running).
- A task that leaves the BGFT queue while PAUSED or REGISTERED (deleted
  from the console's download list, dropped by BGFT) is now detected and
  moved to a terminal state; previously such slots were stuck forever
  and could fill the 32-slot registry.

* fix(proxy,server): single-ownership stream lifecycle, stop streaming to dead clients

The proxy registry kept a pointer to the stream being served
(job->stream_pf) but the serving connection owned and freed it via
proxy_stream_close, leaving a dangling reference behind:

- piece change: proxy_stream_open retired (abort + prefetch_free) the
  already-freed previous stream -> use-after-free on every multi-piece
  proxied download;
- job teardown: the terminal event fired proxy_unregister, which freed
  the dangling stream a second time -> double free after every
  successful proxied install.

New ownership model: the serving connection remains the sole owner.
proxy_stream_close(job_id, stream) clears the registry's reference
under the registry lock before freeing; retiring a piece change and
unregistering a job only abort the stream (instant, and no longer
joins worker threads with the taskman poll lock held) - its owner
winds down and frees it. Dead-code proxy_get_piece and the unused
stream_open flag are gone.

conn_send now reports failure and the static/proxy serving loops stop
pulling data for a gone client, so an aborted/stopped download no
longer keeps transferring the whole piece from the origin.

* fix(server): null-check install url list allocations

A failed calloc in the legacy and v2 install handlers dereferenced
NULL while collecting package urls.
2026-10-28 09:40:24 +07:00
AldySan d604a6df56 feat: full pkg information on transfer cards — icon, version, expandable details (#10)
* feat(icon): add pkg icon loader with vendored stb_image

* feat(installer,taskman): track app version, content type and piece count

* feat(ui): pkg icons, version and expandable details on transfer cards

* feat(api,docs): expose pkg metadata in v2 jobs
2026-10-28 09:08:22 +07:00
AldySan d0b5968fe3 chore(release): bump version to 0.0.1 (#8) 2026-10-28 07:39:47 +07:00
AldySan 995d8831d7 fix: audit pass — 8 bug fixes + keep-alive session reuse in transfer engine (#7)
* fix: net stack teardown order and bounded SFO key reads

- netmon: sceNetPoolDestroy was called with the mem id after it was
  already reset to -1, so the real pool leaked at shutdown.
- sfo: key comparison read up to 64 bytes past the key table on
  malformed SFO data; bound it to the actual key length.

* fix(taskman): reclaim terminal job slots, release already-installed jobs

Terminal-state jobs kept their slots forever, so the registry filled up
after 32 installs and every new install failed until the app restarted.
When full, the oldest terminal slot is now reclaimed (the dashboard
keeps showing the most recent jobs).

ALREADY_INSTALLED jobs never fired the terminal event, so their proxy
slot and temp manifest/icon leaked per attempt; they are now cleaned up
and released when the BGFT task reports already-installed (task id -1).
Also documents that the event hook runs with the registry lock held.

* fix(server,installer): legacy error_code response for BGFT failures

The original responds {"status":"fail","error_code":...} (HTTP 200)
when BGFT task registration fails; the rewrite returned HTTP 500 with
an error message instead. The BGFT error code is now carried through
install_result_t and the legacy byte-compatible response is restored.

Also: bound the shutdown wait for in-flight connections (a send stuck
on a dead link could stall the netmon thread forever and block
network-up recovery) and drop a needless 16-byte copy in the
/api/v2/jobs/<id> route that truncated long ids.

* fix(ui): run the re-transfer pipeline off the UI thread

action_retry ran the full install prepare (pkg header, entry table,
SFO/icon fetches plus one probe per piece) on the UI thread, freezing
the dashboard and controller input for the duration; it now runs in a
detached worker thread with the URL copied out of the job snapshot.

* perf(http,prefetch): keep-alive session reuse, race-free teardown

Every 2 MiB prefetch chunk previously created and destroyed its own
template + connection, paying a full TCP/TLS handshake and slow start
per chunk (thousands per large package). Workers now hold a reusable
keep-alive session for the piece (one handshake), with a single retry
on a stale connection.

http_client_term() could destroy the HTTP context while prefetch
workers were mid-request (network drop mid-transfer = crash risk);
teardown is now deferred by an in-flight counter until the last
request/session finishes. One-shot requests keep the previous
behavior (fresh template per request).

Also hoists the duplicated worker_ctx typedef to file scope.
2026-10-28 07:30:25 +07:00
AldySan 71bce89abe docs: full API reference and README polish (#6)
Stage 6/6: docs/API.md (legacy wire-compatible formats + v2 API), README polish (controls table, examples, dev layout), roadmap complete.
2026-10-27 22:22:43 +07:00
AldySan a319cbd1d5 feat: live on-screen dashboard — transfer cards, controls, activity log (#5)
Stage 5/6: embedded bitmap font (generated, tintable atlas), dashboard with status strip + transfer cards (progress/speed/ETA) + activity log pane, controller controls incl. per-item pause/resume/stop/re-transfer, taskman is_ref.
2026-10-27 22:20:44 +07:00
AldySan c936025915 feat: HTTP server — legacy API 1:1, v2 API, accelerated piece proxy (#4)
Stage 4/6: threaded socket server, byte-compatible legacy API, v2 API (system/jobs/install/storage/logs), piece proxy streaming through the adaptive prefetch engine, log ring, netmon-driven server lifecycle.
2026-10-27 15:13:21 +00:00
AldySan d66f531ad0 feat: transfer engine — BGFT wrappers, task manager, installer, adaptive prefetch (#3)
Stage 3/6: BGFT wrappers (legacy already-installed semantics), AppInstUtil wrappers, task manager with 1 Hz progress poller + speed/percent + completion detection, full install pipeline (direct + ref_pkg_url), adaptive N-segment prefetch engine with shared chunk frontier, create-fself SDK-stub shim build fix.
2026-10-27 15:03:53 +00:00
AldySan c49fbab655 feat: core services — network monitor, storage, pkg/SFO parsing, HTTP client (#2) 2026-10-27 21:45:18 +07:00
AldySan 5aff112114 feat: project skeleton, build system, and CI (#1)
Stage 1/6: OpenOrbis Makefile (.pkg verified), SDL2 smoke screen, module loader, logging facade, cJSON + dbglogger vendored, GitHub Actions CI, assets. Title ID RPIN00001.
2026-10-27 21:20:11 +07:00
AldySan 5131eedfaa Initial commit 2026-10-27 20:03:40 +07:00