Per the robustness plan's §6: fallback_mode and source_selection_mode
were closed sets compared as string literals scattered across match
arms. Parse each once where the raw string enters real decision logic
instead of re-comparing spellings everywhere a typo could hide.
player_policy.rs: DvFallbackMode enum (Off/Auto/Dv8/ConvertDv81/Hdr10)
replaces the String field on DvProxyPlanRequest, deserialized directly
via serde (snake_case matches the existing wire strings exactly).
Caught a real bug in the process: the existing test suite already
covered "hdr10" as a value real requests send (matching the field's
own doc comment, which the string-comparison code had silently drifted
from — "hdr10" never hit any specific match arm, just fell through to
the same catch-all as "off"). Missing that variant broke a passing
test immediately, which is exactly the point of parsing at the
boundary: a typo/missed variant now fails loudly in one place instead
of silently in whichever comparison forgot about it.
stream_policy.rs: SourceSelectionMode enum (Regex/First/Manual) via an
infallible `From<&str>` (unlike DV mode, any unrecognized value should
keep behaving as "manual" like it always has, not become a hard
parse error) replaces the STREAM_SOURCE_MODE_* string constants in
select_stream_index/select_stream_index_values. Callers (jni.rs,
player_flow.rs) now convert with `.into()` at the same point they used
to pass the raw string through.
Scope notes for what's NOT done here, and why:
- Did not change EffectEnvelope.kind from String to EffectKind as §6
also suggests. EffectEnvelope is embedded in EngineState.pending_effects,
which round-trips through create_headless_engine's
serde_json::from_str(initial_json). Today an unrecognized kind string
in restored state is survivable (kind is a plain String; only the
from_str() lookup in complete_effect can fail, and it already drops
that one stale effect gracefully). Making kind a strict enum would
make one unrecognized effect kind fail deserialization of the entire
restored EngineState instead of just that effect — a resilience
regression across app-version upgrades that remove/rename a variant,
which runs directly against this plan's own goal. Left as String
pending a design for tolerant partial-state restore.
- scrobble action_name and auth provider/mode enums, and the ~80
json!({...}) payload literals in headless_engine, are deferred to a
follow-up pass — each is mechanical but independent of this change.
|
||
|---|---|---|
| .github/workflows | ||
| benches | ||
| docs | ||
| fluxa-streaming-engine | ||
| fuzz | ||
| src | ||
| tests/wire | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
| uniffi-bindgen.rs | ||
| uniffi.toml | ||
fluxa-core
The platform-agnostic Rust core behind Fluxa, a media-streaming app.
State management · Stream policy · Addon protocol · Effect-driven I/O
What it does
fluxa-core holds all of Fluxa's domain logic — content discovery, stream selection,
playback state, profiles, library, calendar, and external sync with Trakt/Simkl — so the
same Rust codebase can run unmodified on Android, desktop, and (via WASM) the web. It
contains no platform-specific code and never performs I/O itself: it takes an action and
returns state plus a list of typed effects, and the host platform executes those
effects and reports results back.
Host → dispatch(action_json)
← { state, effects: [{ id, type, payload }] }
Host → executes each effect (HTTP / storage / player / ...)
→ completeEffect({ effectId, result })
← { state, effects: [...] }
This repo also contains a companion crate, fluxa-streaming-engine/, which handles
the runtime streaming side: torrent download (via librqbit), local HTTP proxying, and
Dolby Vision / HDR10+ stream rewriting.
Who uses this
| Platform | Repo | How it links |
|---|---|---|
| Android (mobile + TV) | Fluxa | JNI (primary, ~157 functions) + a small UniFFI surface |
| Desktop (Linux/macOS/Windows) | FluxaDesktop | Plain Rust dependency — calls FluxaCore/core_invoke directly, no FFI marshaling |
| iOS / tvOS | not in this workspace | UniFFI (bindings/uniffi.rs) |
| webOS | not in this workspace | WASM (bindings/wasm.rs, wasm feature) |
See docs/integrating.md for how each platform actually wires
this crate in, including how to add a new capability for a given platform.
Architecture
headless_engine/— the primary state machine. State is a typedEngineStatestruct made of per-feature sub-structs (home, detail, player, library, search, ...); cross-module writes go throughpub(super)setters, never raw field access.app_state.rs— a second, simpler engine for overlapping concerns, used by Android via UniFFI. The split is intentional, not duplication to be cleaned up.- Three uncoordinated exposure mechanisms, one per platform's needs:
core_api::FluxaCore(minimal, desktop-only),ffi::core_invoke(string-routed dispatcher, desktop + Swift), andbindings/jni.rs(Android, no equivalent elsewhere).
Full architecture notes, the effect catalog, and the wire-format reference live in
docs/:
docs/overview.md— architecture, state engines, module mapdocs/effect-loop.md— the dispatch/effect/completeEffect cycledocs/effects.md— everyEffectKindand its payload shapedocs/integrating.md— per-platform integration guidedocs/building.md— features, commands, cross-compilation
Building from source
git clone https://github.com/KhooLy/fluxa-core.git
cd fluxa-core
cargo build # default (native) features — what Android uses
cargo test --lib # ~190 tests, fast
Prerequisites
- Rust stable
- For Android cross-compilation:
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
cargo check --no-default-features --features wasm # sanity-check the webOS/WASM path
cd fluxa-streaming-engine && cargo build # the companion crate builds independently
See docs/building.md for the full feature matrix, UniFFI binding
generation, and release-build details.
Repo layout
src/ domain logic, headless_engine, FFI bindings
fluxa-streaming-engine/ torrent + Dolby Vision/HDR10+ stream rewriting (separate crate)
fuzz/ cargo-fuzz targets for parsers (episode matching, manifests, percent-decode)
docs/ architecture, effects reference, integration guide
Stack
Rust · JNI · UniFFI · wasm-bindgen · axum · tokio · librqbit · dolby_vision · serde
Legal — fluxa-core is a domain-logic library for a client-side interface to user-installed Stremio addons. It does not host, serve, or distribute any media content, and never makes a network call itself — all I/O is performed by the host platform. Fluxa is not affiliated with any addon developer, repository, or content provider. Users are responsible for ensuring they have the right to access what they stream.
Related projects
- Fluxa for Android — the Android counterpart consuming this crate
- FluxaDesktop — the desktop counterpart consuming this crate