Badge fetching design with Protobuf parsing, 24h cache refresh, cacache integration. Mark TODO-042 verified, TODO-058 monitoring, TODO-062 complete.
4.1 KiB
4.1 KiB
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):
BigNum: revision numberBigNum: Unix timestamp- 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_badgesfield 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<BadgeMeta>
│ ├── get_icon(guid) -> Option<bytes>
│ ├── refresh_if_stale()
│ └── metadata: RwLock<HashMap<Guid, BadgeMeta>>
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<BadgeMeta>
- 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:
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(addPREFIX_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
- Protobuf schema: Need to define
.protofile or use dynamic parsing. Prost requires compile-time schema — may need to reverse-engineer from reference or useprotobufcrate for runtime parsing. - Icon URL construction: Exact URL pattern for badge icons needs verification (likely
https://badges-content.teamspeak.com/{url_base}.png). - Offline mode: Should we ship a static badge list as fallback? (YAGNI for now)