Commit Graph
11 Commits
Author SHA1 Message Date
zarzet c10c0ab5f5 docs(rust): add module docs to large modules without one
More than half of the crate files had no module doc, so a contributor had to
read a large file top to bottom to learn what it owns. Every file over 300
lines now states its responsibility in one or two lines.
2026-10-19 00:56:51 +07:00
zarzet f7a15cbd43 refactor(rust): consolidate small duplicate helpers
Keep one copy of helpers that were implemented several times, each proven
equivalent to the copies it replaces by a test that runs the removed
implementation (kept inline in the test module) against the survivor:

- Go-style lexical path clean: new `core::fs::clean`, used by
  `isrc::native_files` and re-exported as `extensions::files::clean`.
- Dart `String.trim` whitespace: `path_keys::dart_whitespace` and
  `dart_trim` now back the lyrics parser's explicit character list and the
  playlist importer's private `trim`; the test compares every Unicode
  scalar value.
- `normalized()` (Dart trim then simple lowercase): the native backup
  importer uses the identical `native_library::normalized`.
- Lowercase hex encoding: `spotiflac_core::lower_hex` replaces the per-byte
  `format!` collectors in data_jobs and network_tags, the signed-session
  `hex` and the `hex` arm of `binary::encode`; checked for all 256 bytes.
- ID3 syncsafe decode: the tag writer's `size` reuses the reader's
  `tags::id3::syncsafe`; checked across the 0x7F/0x80 boundaries per byte.
- Bounded body reads: `HttpStream::read_limited` replaces the read-to-limit
  loops of the lyrics HTTP client, the resolver HTTP client and the
  extension registry reader. Callers keep their buffer sizes (16 KiB,
  16 KiB, 64 KiB), their own error mapping and their messages; a loopback
  test compares it with the previous loop at and around the limit.

The mobile ID3 `synchsafe` is not merged: it validates the length and the
high bits and returns `None`, unlike the core decoder.
2026-10-19 00:36:29 +07:00
zarzet 42c90dbf62 refactor(network): split client.rs into pool, stream, headers and tests, and factor execute_stream
client.rs held the connection pool, the streaming response type, header
helpers, tests and a 274-line execute_stream in one 1220-line file (audit
RS-15). Move the self-contained parts into client/ and break
execute_stream into phase helpers so the redirect loop reads top-down.

Pure moves (verbatim apart from pub(super) on items the parent uses):
- client/pool.rs: Connector and Pool.
- client/stream.rs: ResponseBody and HttpStream (re-exported from client,
  so crate::HttpStream is unchanged).
- client/headers.rs: update_explicit_cookies, forward_sensitive_headers
  and canonical_header. error_chain stays in client.rs; it is not a
  header helper.
- client/tests.rs: the existing unit tests.

execute_stream helpers (base line ranges refer to main:client.rs). Each
body is the statements it replaces; the loop, await points, error
mapping, redirect limit and header mutations stay in the same order:
- prepare_request: 720-769, request validation, method, body, headers,
  user agent, default JSON content type and explicit referer, returned
  as PreparedRequest. Only the mut markers moved to the call site.
- outgoing_headers: 773-802, per-attempt cookie header and gzip
  negotiation, returning (outgoing, gzip). header(&url) became
  header(url) because url is now a reference.
- send: 803-845, the request, its 45 s header timeout and the native
  HTTPS-to-HTTP fallback retry. The permit is passed by value and
  returned, so drop(permit) still runs before the retry acquires a new
  one. matches!(method, ..) became matches!(*method, ..).
- redirect_target: 862-869, Location resolution, credential rejection
  and redirect policy validation, returning the target.
- release_redirect_body: 906-928, the 20 ms drain of a small HTTP/1.1
  redirect body.
- response_reader: 932-959, discard eligibility and gzip decoder setup,
  returning (headers, small_http1, reader).
- canonical_headers: 960-970, canonical response header map.

The redirect request rewrite (871-905) stays inline: it updates the
loop-carried method, body and headers and reads six other values, so a
helper would need nine parameters or a state struct that rewrites every
statement in the loop.

hyper is not a direct dependency, so the response type is named through
the pooled client's tower Service implementation (HyperResponse).
No public path or signature changes.
2026-10-19 00:00:04 +07:00
zarzet 5dbf9e6c29 refactor(network): drop the ignored insecure_tls parameter inside Rust
NetworkService::set_network_compatibility_options ignored the
insecure_tls flag by design because TLS verification is never disabled.
Remove the parameter from the network service and the extension
environment so the dead flag no longer travels through internal layers.

The UniFFI method keeps its signature: Kotlin and Swift still pass the
flag, and the mobile binding accepts and ignores it until the binding
and channel cleanup lands separately.
2026-10-18 22:22:57 +07:00
zarzet 43f7257d3d docs(rust): say that Go is the retired backend in crate docs
Rust is the only backend and routes the app on Android and iOS. Rewrite
the migration-era crate, script and comment wording that implied Go still
runs, and note in each crate doc that Go mentions describe the retired
backend whose observable behavior remains a compatibility contract.
2026-10-18 22:02:52 +07:00
zarzet 5254760bbd build(rust): drop unused direct dependencies and centralize pins
Remove tokio from spotiflac-extensions and thiserror and the direct hyper
entry from spotiflac-network (hyper stays resolved through hyper-util).
Move roxmltree, rusqlite and libc into workspace.dependencies. libc already
resolves to 0.2.190, so the workspace pin uses that exact version. No
resolved version or enabled feature changes.
2026-10-18 22:02:35 +07:00
zarzet 39d856c44f chore(network): keep JSON dependency scoped to tests 2026-10-04 01:41:58 +07:00
zarzet 70f8bd7f35 feat(extensions): support personal account forms and direct downloads 2026-10-02 19:21:58 +07:00
zarzet 44b7ceb8e8 perf(download): reuse connections across probes and retries 2026-09-30 23:39:22 +07:00
zarzet eb717a6e7b fix(extensions): restore URL globals for provider link resolution 2026-09-15 21:44:11 +07:00
zarzet aa99726439 feat(backend): migrate production backend to Rust
Replace the Go backend with the Rust workspace and route Android/iOS through
UniFFI bindings. Include the migrated extension runtime, network, providers,
media metadata, downloads and library operations, with version 5.0.0+147.

Remove Go sources, adapters, native build selection and CI dependencies.
Build Rust unconditionally and lock the iOS Rust pod using a relative path.
Retain legacy source and migration evidence in a local ignored archive.

Validation: Android Kotlin compile and 53 native tests; Swift Rust-branch
equivalence and syntax; CocoaPods install; workflow, shell, Ruby, plist and
diff checks. Reuse the preceding 100 Rust tests, fmt/Clippy and five-ABI
build checkpoint; no new APK or iOS application build for this cleanup.

Known follow-up: URL/URLSearchParams globals are missing from the Rust JS
runtime. A controlled extension replay confirms a URL-resolution regression;
this commit does not fix that runtime gap.
2026-09-14 22:58:27 +07:00