Skip to content

feat(discordsh): wire bevy_chat IRC client with graceful degradation#9892

Merged
h0lybyte merged 2 commits intodevfrom
trunk/discord-irc-integration-1775767643
Apr 9, 2026
Merged

feat(discordsh): wire bevy_chat IRC client with graceful degradation#9892
h0lybyte merged 2 commits intodevfrom
trunk/discord-irc-integration-1775767643

Conversation

@h0lybyte
Copy link
Copy Markdown
Member

@h0lybyte h0lybyte commented Apr 9, 2026

Summary

Connects the Discord bot to ergo IRC via bevy_chat::ChatClient for cross-platform world events (#9850). Gracefully handles unavailable IRC — no crash, no blocked startup.

Startup behavior

Condition Result
IRC_HOST set, ergo reachable Connected, events enabled
IRC_HOST set, ergo unreachable Warning logged, irc: None, events silently disabled
IRC_HOST not set Info logged, skipped entirely

World events emitted to #world-events

Event Trigger IRC Format
Boss killed Boss HP reaches 0 [EVENT:KILL] Player@discord: Player defeated Glass Golem
Victory Dungeon cleared [EVENT:VICTORY] Player@discord: Player cleared depth 7
Death Player defeated [EVENT:DEATH] Player@discord: Player was slain

Events include JSON payload for structured consumption by isometric game.

New module

discord/game/irc_events.rs — 5 emit functions (boss_killed, rare_drop, player_death, victory, quest_complete), all fire-and-forget via tokio::spawn.

Changes

  • AppState::new() is now async (for IRC connect)
  • AppState.irc: Option<ChatClient> field
  • Router emits IRC events after action processing

All 701 tests pass. IRC is None in test environment.

Test plan

  • All 701 tests pass
  • Pre-commit hooks pass (rustfmt)
  • Deploy with IRC_HOST unset — verify clean startup with "IRC not configured" log
  • Deploy with IRC_HOST=ergo-irc-service.irc.svc.cluster.local — verify connection
  • Defeat a boss — verify #world-events receives event

…radation (#9850)

Connects the Discord bot to the existing ergo IRC server via bevy_chat::ChatClient
for cross-platform world events. Gracefully degrades if IRC is unavailable.

Startup:
- If IRC_HOST is set, attempts ChatClient::from_env() connection
- On success: stored as Some(ChatClient) in AppState
- On failure: logs warning, stores None — all IRC features silently disabled
- If IRC_HOST not set: logs info, skips entirely

World event emission (fire-and-forget via tokio::spawn):
- Boss killed → #world-events [EVENT:KILL] player defeated boss
- Dungeon victory → #world-events [EVENT:VICTORY] player cleared depth N
- Player death → #world-events [EVENT:DEATH] player was slain
- All events include structured JSON payload for isometric game consumption

New module: discord/game/irc_events.rs
- emit_boss_killed(), emit_rare_drop(), emit_player_death()
- emit_victory(), emit_quest_complete()
- Each checks Option<ChatClient>, no-ops on None

AppState changes:
- new() is now async (for IRC connect)
- irc: Option<ChatClient> field added

All 701 tests pass (IRC is None in test environment).
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 3 package(s) with unknown licenses.
See the Details below.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA a3ba85d.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

License Issues

packages/rust/bevy/bevy_chat/Cargo.toml

PackageVersionLicenseIssue Type
js-sys>= 0.3.0, < 0.4.0NullUnknown License
wasm-bindgen>= 0.2.0, < 0.3.0NullUnknown License
web-sys>= 0.3.0, < 0.4.0NullUnknown License

OpenSSF Scorecard

PackageVersionScoreDetails
cargo/js-sys >= 0.3.0, < 0.4.0 UnknownUnknown
cargo/wasm-bindgen >= 0.2.0, < 0.3.0 UnknownUnknown
cargo/web-sys >= 0.3.0, < 0.4.0 UnknownUnknown

Scanned Files

  • packages/rust/bevy/bevy_chat/Cargo.toml

…#9850)

WASM clients (isometric game in browser) can't do raw TCP to ergo. They
connect via WebSocket to chat.kbve.com (irc-gateway → ergo:8080).

Transport is selected at compile time via cfg(target_arch):
- Native (not wasm32): tokio TcpStream → ergo:6667 (unchanged)
- WASM (wasm32): web_sys::WebSocket → wss://chat.kbve.com

Public API is identical on both platforms:
- ChatClient::new(config) / connect() / send() / disconnect()
- Native: subscribe() returns broadcast::Receiver (async)
- WASM: drain_incoming() returns Vec (polled each frame by Bevy plugin)

WASM client features:
- Automatic IRC registration on WebSocket open (NICK/USER/JOIN)
- PING/PONG keepalive handling
- PRIVMSG parsing with structured ChatMessage decode
- Closures leaked for WebSocket lifetime (standard WASM pattern)
- Non-Send (Rc<RefCell>) — must run on main thread

File structure:
- client_native.rs — tokio TCP (was client.rs)
- client_wasm.rs — web_sys::WebSocket (new)
- lib.rs — conditional export based on target_arch

Cargo.toml changes:
- tokio moved to cfg(not(wasm32)) target dependency
- Added wasm-bindgen, web-sys, js-sys as cfg(wasm32) dependencies
@h0lybyte h0lybyte merged commit 638dd8b into dev Apr 9, 2026
1 check passed
@h0lybyte h0lybyte deleted the trunk/discord-irc-integration-1775767643 branch April 9, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant