Files
chanora/crates/chanora_bridge/README.md
Edison Jwa 01a4a9ed28 docs: add README files to 9 crates and update verification plan (TODO-030,036)
Add purpose, architecture, and public API summary to each crate
README following chanora_resolver pattern. Update verification master
plan with new evidence sources and entry/exit criteria.
2026-06-11 11:09:12 +09:00

81 lines
4.7 KiB
Markdown

# chanora_bridge
Typed Flutter/Rust bridge — schema-controlled DTOs for commands, results, and events. Backed by `flutter_rust_bridge` 2.x per DEC-014.
## Architecture
- **`api` module** — all public functions exposed to Dart. Each function runs on a shared tokio runtime and delegates to `chanora_core::ChanoraSession`. Input/output types are owned primitives or `String`s — no backend types cross the boundary (SAD-067, SDD-079).
- **`frb_generated`** — auto-generated `flutter_rust_bridge` glue. Contains `unsafe` for the FFI boundary; hand-written code must not use `unsafe`.
- **`android_init`** (Android only) — NDK context initialization
- **`permission_jni`** (Android only) — JNI hook for Android permission state changes (SDD-106)
### DTO pattern
Every Dart-facing type is a `Bridge*` DTO with primitive fields. `From` impls convert between bridge DTOs and `chanora_core` types. Most types do not carry `serde` derives — FRB generates its own SSE encoders/decoders.
### Event streaming
`BridgeEvent` enum is streamed to Dart via FRB's `StreamSink`. Events include: Connected, Disconnected, Lost, Reconnecting, ChatMessage, VoiceState, AudioStarted/Stopped, ClientJoined/Left/Moved/Updated, ChannelAdded/Removed/Updated, PttCapability, PermissionState, ServerActivity, InterruptionState, AudioRouteChanged.
## Public API Summary
### Commands (api.rs)
| Command | Description |
|---|---|
| `bridge_init()` | One-time init: logging, panic hook |
| `connect(host, nickname, password)` | Connect to a server |
| `disconnect()` | Clean disconnect |
| `snapshot()` | Refresh server state |
| `client_profile(client_id)` | Rich profile for one client |
| `is_connected()` | Connection check |
| `prefetch_server(host)` | Warm server resolution |
| `voice_join(channel_id, password)` | Join voice channel |
| `voice_leave()` | Leave voice channel |
| `set_transmit_mode(mode)` | Ptt/Continuous/VoiceActivity |
| `get_transmit_mode()` | Read current mode |
| `set_hard_mute(muted)` | Hard-mute clamp |
| `set_ptt(active)` | Manual PTT press/release |
| `set_ptt_binding(input_class, platform_key)` | Bind a PTT key |
| `ptt_descriptor()` | Current PTT capability |
| `get_ptt_binding()` | Persisted PTT binding |
| `set_release_tail_ms(ms)` | Release-tail config |
| `get_release_tail_ms()` | Read release-tail |
| `move_to_channel(channel_id, password)` | Move to a channel |
| `set_input_muted(muted)` / `set_output_muted(muted)` | Server-side mute |
| `set_output_gain(gain)` | Master volume |
| `set_client_volume(client_id, volume)` | Per-client volume |
| `send_chat_message(message, target)` | Send text |
| `set_audio_processing_config(config)` | P1 audio processing |
| `get_audio_processing_config()` | Read P1 config |
| `audio_processing_stats()` | P1 telemetry |
| `enable_audio_debug_wav_dump(enabled)` | WAV dump toggle |
| `set_vad_model_path(path)` | Silero model path |
| `set_input_device(id)` / `set_output_device(id)` | Device selection |
| `export_diagnostics()` | Redacted export bundle (includes network stats) |
| `audio_stats()` | Audio subsystem statistics |
| `input_level_stream()` | Mic level metering stream |
| `events_stream()` | Bridge event stream |
| `log_file_path_str()` | Log file path for platform |
| `init_storage()` / `init_cache()` | Storage/cache initialization |
| `set_ios_voice_processing_mode(mode)` | iOS audio processing mode |
| `set_audio_output_route(route)` | Audio output route selection |
| `list_audio_devices()` | Enumerate audio devices |
| `list_bookmarks()` / `add_bookmark` / `update_bookmark` / `delete_bookmark` | Bookmark CRUD |
| `download_avatar(hash, uid)` / `download_icon(id)` | Avatar/icon download |
| `clear_file_cache()` / `file_cache_size()` | Cache management |
| `handle_route_change(route)` | iOS audio route change |
| `handle_media_services_reset_with_route(route_class)` | iOS media reset |
| `handle_interruption_began()` / `handle_interruption_ended(should_resume)` | iOS interruption |
| `lifecycle_event(state)` | Platform lifecycle |
### Bridge DTOs
`BridgeSnapshot`, `BridgeChannel`, `BridgeClient`, `BridgeClientProfile`, `BridgeAudioStats`, `BridgeAudioProcessingConfig`, `BridgeAudioProcessingStats`, `BridgeAudioRoute`, `BridgeTransmitMode`, `BridgePttInputClass`, `BridgePttDescriptor`, `BridgePttBinding`, `BridgeMessageTarget`, `BridgeBookmark`, `PermissionStateKind`, `BridgeError`.
## Platform notes
- Cannot use `#![forbid(unsafe_code)]` because FRB-generated glue legitimately uses `unsafe` for the FFI boundary.
- Android: includes `android_init` and `permission_jni` modules gated behind `cfg(target_os = "android")`.
- iOS: route-change and interruption handlers are synchronous (`#[frb(sync)]`), dispatched to the tokio runtime via an ordered channel.