diff --git a/docs/designs/badge-fetching-design.md b/docs/designs/badge-fetching-design.md new file mode 100644 index 0000000..9ae6d9c --- /dev/null +++ b/docs/designs/badge-fetching-design.md @@ -0,0 +1,119 @@ +# Badge Fetching Design (TODO-065) + +## Purpose + +Fetch, cache, and display TeamSpeak client badges. Badges are visual indicators (icons) shown next to client names in the UI. + +## Protocol Details + +**Source:** `badges-content.teamspeak.com/list` + +- **Format:** Protobuf (binary) +- **Refresh:** Every 24 hours +- **Cache location:** `cache/badges` (via cacache) + +**Protobuf structure (from YaTQA §8.9):** +1. `BigNum`: revision number +2. `BigNum`: Unix timestamp +3. Repeated badge entries: + - GUID (string) + - Name (string) + - URL base (string, used to construct icon URL) + - Description (string) + - Timestamp + - Unknown field (1-3 variants) + +**Badge references in protocol:** +- Server sends `client_badges` field in client info events +- Format: `overwolf=0:badges=GUID1=GUID2=...` +- Client looks up badge definitions by GUID, fetches icon by URL base + +## Architecture + +### New module: `crates/chanora_cache/src/badges.rs` + +``` +badges.rs +├── BadgeMeta { guid, name, url_base, description } +├── BadgeCache +│ ├── fetch_badge_list() -> Vec +│ ├── get_icon(guid) -> Option +│ ├── refresh_if_stale() +│ └── metadata: RwLock> +``` + +### Extend `chanora_cache/src/lib.rs` + +- Add `PREFIX_BADGE: &str = "bg_"` for badge icon blobs +- Update `validate_key()` to accept badge prefix (GUID format: 8-4-4-4-12 hex) + +## Data Flow + +``` +1. On connect → server sends client_badges (GUIDs) +2. BadgeCache.refresh_if_stale(): + - Check last_refresh timestamp + - If >24h: fetch badges-content.teamspeak.com/list + - Parse Protobuf → Vec + - Update metadata map +3. For each GUID in client_badges: + - Lookup BadgeMeta by GUID + - Fetch icon from url_base (HTTP GET) + - Cache icon blob in BlobCache (PREFIX_BADGE + guid) + - Return icon bytes to UI +4. Flutter UI displays badge icons in: + - Client info panel (profile) + - Chat message sender badges +``` + +## Dependencies + +| Crate | Status | Purpose | +|-------|--------|---------| +| `reqwest` | Already in `chanora_protocol` | HTTP fetch | +| `prost` | **Add** | Protobuf parsing | +| `cacache` | Already in `chanora_cache` | Blob storage | +| `tokio` | Already | Async runtime | + +**Cargo.toml additions for `chanora_cache`:** +```toml +reqwest = { version = "0.13", default-features = false, features = ["rustls-tls"] } +prost = "0.13" +``` + +## Integration Points + +| Component | Integration | +|-----------|-------------| +| `chanora_protocol/src/adapter.rs` | Parse `client_badges` from `notifyclientupdated` events | +| `chanora_bridge` | Expose `get_badge_icon(guid)` and `get_client_badges(client_id)` to Flutter | +| Flutter UI | Display badge icons in `ClientInfoPanel` and `ChatMessage` widgets | + +## Files to Create/Modify + +- **Create:** `crates/chanora_cache/src/badges.rs` +- **Modify:** `crates/chanora_cache/src/lib.rs` (add `PREFIX_BADGE`, export module) +- **Modify:** `crates/chanora_cache/Cargo.toml` (add reqwest, prost) +- **Modify:** `crates/chanora_protocol/src/adapter.rs` (parse client_badges) +- **Modify:** `crates/chanora_bridge/src/` (expose badge API to Flutter) + +## Error Handling + +- **Network failure:** Log warning, serve stale cache if available, retry on next refresh +- **Protobuf parse error:** Log error, keep previous badge data, alert user "badges unavailable" +- **Icon fetch failure:** Cache miss, show placeholder or skip badge display + +## Effort Estimate + +**L (3-5 days)** +- Day 1: Protobuf schema research, add prost dependency, parse badge list +- Day 2: BadgeCache implementation, icon fetch and caching +- Day 3: Protocol adapter integration (parse client_badges) +- Day 4: Flutter bridge API, UI display +- Day 5: Testing, error handling, edge cases + +## Open Questions + +1. **Protobuf schema:** Need to define `.proto` file or use dynamic parsing. Prost requires compile-time schema — may need to reverse-engineer from reference or use `protobuf` crate for runtime parsing. +2. **Icon URL construction:** Exact URL pattern for badge icons needs verification (likely `https://badges-content.teamspeak.com/{url_base}.png`). +3. **Offline mode:** Should we ship a static badge list as fallback? (YAGNI for now) diff --git a/docs/governance/master-todo-list-2026-06-11.md b/docs/governance/master-todo-list-2026-06-11.md index 7a8a30c..4a1b3be 100644 --- a/docs/governance/master-todo-list-2026-06-11.md +++ b/docs/governance/master-todo-list-2026-06-11.md @@ -345,6 +345,7 @@ - **Description:** Recent server management is partially implemented. Needs completion per spec. - **Effort:** M - **Dependencies:** None +- **Status:** VERIFIED COMPLETE — Auto-save on connect exists in chanora_core/src/lib.rs:629-650. Bookmark list UI shows all bookmarks with connect/delete. _reloadBookmarks() called on disconnect. (2026-06-11) ### TODO-043 — Implement event replay tool (SysRS-171, SRS-098) - **Priority:** P2 @@ -466,7 +467,7 @@ - **Description:** No full TS5 client protocol exists yet. Watch `tsdeclarations` repo for updates that may affect Chanora compatibility. - **Effort:** S - **Dependencies:** None (ongoing) -- **Status:** MONITORING — no TS5 protocol updates detected; `tsdeclarations` last checked 2026-06-11 +- **Status:** MONITORING — No TS5 updates detected. GitHub watch recommended. (2026-06-11) ### TODO-059 — Build auto-reconnect logic internally - **Priority:** P2 @@ -518,7 +519,7 @@ - Cross-verified against YaTQA §8.5 resolution order - **Effort:** M - **Dependencies:** None -- **Status:** VERIFIED COMPLETE — full resolution chain implemented (2026-06-11) +- **Status:** VERIFIED COMPLETE — Full chain implemented: DNS, TSDNS SRV, TSDNS TCP in chanora_resolver/src/lib.rs:178-387. First-wins semantics. (2026-06-11) ### TODO-063 — Verify tsclientlib encoding handling (UTF-8 vs UCS-2 vs CESU-8) - **Priority:** P1