steam-client-rs 0.2.0

Steam client for Rust - Individual and Anonymous user account types
Documentation
//! Steam-User Example - Chat Bot
//!
//! A simple chat bot that responds to messages from friends.
//!
//! # Usage
//! ```bash
//! REFRESH_TOKEN="your_refresh_token" cargo run --example chat_bot
//! ```

use std::time::Duration;

use steam_client::{AuthEvent, ChatEvent, ConnectionEvent, EPersonaState, LogOnDetails, SteamClient, SteamError, SteamEvent};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();

    let refresh_token = std::env::var("REFRESH_TOKEN").expect("Please set REFRESH_TOKEN environment variable");

    let mut client = SteamClient::new(Default::default());

    println!("🤖 Chat Bot Starting...");

    // Log on
    let response = client.log_on(LogOnDetails { refresh_token: Some(refresh_token), ..Default::default() }).await?;

    println!("✅ Logged in as {}", response.steam_id.steam3());

    // Set online status
    client.set_persona(EPersonaState::Online, None).await?;
    println!("👤 Now online and ready to chat!\n");

    // Chat commands
    println!("📝 Available commands:");
    println!("   !ping     - Responds with 'Pong!'");
    println!("   !time     - Shows current time");
    println!("   !help     - Shows this help message");
    println!("   !echo <x> - Echoes back the message\n");

    // Event loop
    loop {
        match client.poll_event_timeout(Duration::from_secs(60)).await {
            Ok(Some(event)) => match event {
                // Handle incoming chat messages
                SteamEvent::Chat(ChatEvent::FriendMessage { sender, message, timestamp, .. }) => {
                    println!("💬 [{}] {} says: {}", format_timestamp(timestamp), sender.steam3(), message);

                    // Process commands
                    let response = handle_command(&message);
                    if let Some(reply) = response {
                        if let Err(e) = client.send_friend_message(sender, &reply).await {
                            println!("❌ Failed to send message: {:?}", e);
                        } else {
                            println!("📤 Replied: {}", reply);
                        }
                    }
                }

                // Handle typing notifications
                SteamEvent::Chat(ChatEvent::FriendTyping { sender }) => {
                    println!("✏️ {} is typing...", sender.steam3());
                }

                // Handle disconnection
                SteamEvent::Connection(ConnectionEvent::Disconnected { reason, will_reconnect }) => {
                    if will_reconnect {
                        println!("🔄 Disconnected ({:?}), reconnecting...", reason);
                    } else {
                        println!("❌ Disconnected permanently");
                        break;
                    }
                }

                // Handle logout
                SteamEvent::Auth(AuthEvent::LoggedOff { result }) => {
                    println!("👋 Logged off: {:?}", result);
                    break;
                }

                _ => {}
            },
            Ok(None) => {
                // Timeout - still connected
            }
            Err(SteamError::NotConnected) => {
                println!("❌ Connection lost");
                break;
            }
            Err(e) => {
                println!("❌ Error: {:?}", e);
            }
        }
    }

    client.log_off().await?;
    Ok(())
}

fn handle_command(message: &str) -> Option<String> {
    let message = message.trim().to_lowercase();

    if message == "!ping" {
        Some("Pong! 🏓".to_string())
    } else if message == "!time" {
        // Get current time without external dependency
        Some(format!("🕐 Current time: {} (Unix timestamp)", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_secs()))
    } else if message == "!help" {
        Some(
            "🤖 Available commands:\n\
            • !ping - Pong!\n\
            • !time - Current time\n\
            • !echo <text> - Echo back\n\
            • !help - This message"
                .to_string(),
        )
    } else if message.starts_with("!echo ") {
        let echo_text = message.strip_prefix("!echo ")?;
        Some(format!("📢 {}", echo_text))
    } else if message.starts_with("!") {
        Some("❓ Unknown command. Type !help for available commands.".to_string())
    } else {
        None // Don't respond to non-commands
    }
}

fn format_timestamp(timestamp: u32) -> String {
    // Simple timestamp formatting without external dependency
    format!("{}", timestamp)
}