System Overview
pwr-bot is built with Rust using an event-driven architecture. The application consists of several key components that work together to provide Discord bot functionality, feed subscriptions, and voice tracking.Core Components
Bot Layer
The bot layer (src/bot/) handles all Discord interactions using the Serenity and Poise frameworks.
Key responsibilities:
- Discord gateway connection
- Command registration and handling
- User interface views and interactions
- Event forwarding to the event bus
src/main.rs:133-159
Services
Services (src/service/) contain the business logic and orchestrate interactions between repositories and external systems.
FeedSubscriptionService
FeedSubscriptionService
Manages feed subscriptions, checks for updates, and handles subscription lifecycle.Location: Key methods:
src/service/feed_subscription_service.rssubscribe()- Create feed subscriptionunsubscribe()- Remove feed subscriptioncheck_feed_update()- Poll feed for new contentget_or_create_feed()- Fetch or create feed entity
VoiceTrackingService
VoiceTrackingService
Tracks user voice channel activity and provides leaderboard data.Location:
src/service/voice_tracking_service.rsFeatures:- Session start/end tracking
- Leaderboard queries with time filters
- Partner leaderboard (who you talked with most)
- Daily activity statistics
SettingsService
SettingsService
Manages server-specific configuration and settings.Location:
src/service/settings_service.rsHandles:- Per-guild settings storage
- Feature flags and preferences
- Channel configurations
InternalService
InternalService
Provides bot metadata and internal state management.Location:
src/service/internal_service.rsManages:- Bot startup timestamps
- Crash recovery metadata
- Internal versioning
src/main.rs:104-106
Repositories
Repositories (src/repository/) provide data access abstraction over SQLite using SQLx.
Structure:
Repository- Root struct holding all table accessors- Table implementations using
impl_table!macro - Type-safe database operations with compile-time SQL checking
src/repository/table.rs
FeedTable- Feed metadataFeedItemTable- Feed update historySubscriberTable- Subscription targets (users/guilds)FeedSubscriptionTable- Many-to-many feed subscriptionsVoiceSessionsTable- Voice activity recordsServerSettingsTable- Guild configurationBotMetaTable- Internal metadata
Event Bus
The event bus (src/event/event_bus.rs) implements a publish-subscribe pattern for decoupled event handling.
Design:
- Type-safe event publishing
- Async subscriber registration
- Automatic event distribution to all subscribers
FeedUpdateEvent- New feed content availableVoiceStateEvent- Voice channel state change
src/main.rs:47, src/event/event_bus.rs
Subscribers
Subscribers (src/subscriber/) respond to events published on the event bus.
DiscordDmSubscriber
DiscordDmSubscriber
Sends feed updates to users via direct messages.Location:
src/subscriber/discord_dm_subscriber.rsFlow:- Receives
FeedUpdateEvent - Queries subscribers of type
Dm - Sends DM to each subscriber
DiscordGuildSubscriber
DiscordGuildSubscriber
Posts feed updates to guild channels.Location:
src/subscriber/discord_guild_subscriber.rsFlow:- Receives
FeedUpdateEvent - Queries subscribers of type
Guild - Posts message to configured channel
VoiceStateSubscriber
VoiceStateSubscriber
Handles voice channel join/leave events.Location:
src/subscriber/voice_state_subscriber.rsResponsibilities:- Track session start/end times
- Update voice session records
- Calculate session duration
src/main.rs:161-178
Tasks
Background tasks (src/task/) run continuously to perform periodic operations.
SeriesFeedPublisher
SeriesFeedPublisher
Polls feeds for updates and publishes events when new content is detected.Location:
src/task/series_feed_publisher.rsAlgorithm:- Get all feeds tagged with “series”
- For each feed, check for updates
- If updated, publish
FeedUpdateEvent - Distribute checks evenly across poll interval
VoiceHeartbeatManager
VoiceHeartbeatManager
Periodically updates voice session timestamps and handles crash recovery.Location:
src/task/voice_heartbeat.rsResponsibilities:- Update active session timestamps
- Detect and recover from bot crashes
- Close orphaned sessions
Design Patterns
Event-Driven Architecture
pwr-bot uses an event-driven architecture to decouple components:- Loose coupling between components
- Easy to add new event handlers
- Testable in isolation
ViewEngine Pattern
UI interactions use a ViewEngine pattern for stateful Discord views: Components:Action- Trait for action enumsViewRender<T>- Renders UI components and embedsViewHandler<T>- Handles user interactions and state transitionsViewEngine<T, H>- Manages the interaction event loop
src/bot/views.rs
This pattern is used extensively in commands with interactive UI like settings and welcome card configuration.
Repository Pattern
Data access is abstracted through the repository pattern:- Centralized data access
- Type-safe queries
- Compile-time SQL verification with SQLx
Service Layer Pattern
Business logic is isolated in service classes:- Reusable business logic
- Easier testing
- Clear separation of concerns
Initialization Flow
The application initializes components in a specific order:Initialize services
Service layer is constructed with database and platform dependencies.Location:
src/main.rs:104-106Setup voice tracking
Voice heartbeat manager starts and performs crash recovery.Location:
src/main.rs:108-131Register subscribers
Event subscribers are registered to the event bus.Location:
src/main.rs:161-178Module Structure
The codebase is organized into logical modules:Testing Strategy
- Unit tests: Test individual functions and methods
- Integration tests: Test component interactions
- Common utilities: Shared test helpers in
tests/common/