VSTP Tutorials

Learn how to build real-world applications with VSTP through these step-by-step tutorials. Each tutorial focuses on a specific use case and demonstrates best practices.

Building a Chat Application

In this tutorial, we'll build a simple chat application using VSTP's TCP mode with automatic message routing.

Step 1: Define Message Types

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Clone)]
pub struct ChatMessage {
    pub from: String,
    pub content: String,
    pub timestamp: u64,
}

#[derive(Serialize, Deserialize)]
pub struct UserJoin {
    pub username: String,
}

#[derive(Serialize, Deserialize)]
pub struct UserLeave {
    pub username: String,
}

Step 2: Create the Server

use vstp::easy::VstpServer;
use std::collections::HashMap;
use tokio::sync::Mutex;

type ConnectedUsers = Arc<Mutex<HashMap<String, String>>>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let users = Arc::new(Mutex::new(HashMap::new()));
    let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;
    
    println!("Chat server running on 127.0.0.1:8080");
    
    server.serve(move |msg: ChatMessage| {
        let users = users.clone();
        async move {
            // Broadcast message to all connected users
            println!("{}: {}", msg.from, msg.content);
            Ok(msg)
        }
    }).await?;

    Ok(())
}

Step 3: Create the Client

use vstp::easy::VstpClient;
use std::io::{self, BufRead};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;
    let stdin = io::stdin();
    
    println!("Enter your username:");
    let mut username = String::new();
    stdin.lock().read_line(&mut username)?;
    let username = username.trim().to_string();
    
    // Send join message
    client.send(UserJoin { username: username.clone() }).await?;
    
    // Start message receiving task
    let client_recv = client.clone();
    tokio::spawn(async move {
        while let Ok(msg) = client_recv.receive::<ChatMessage>().await {
            if msg.from != username {
                println!("{}: {}", msg.from, msg.content);
            }
        }
    });
    
    // Handle user input
    for line in stdin.lock().lines() {
        let content = line?;
        if content == "/quit" {
            break;
        }
        
        let msg = ChatMessage {
            from: username.clone(),
            content,
            timestamp: std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)?
                .as_secs(),
        };
        
        client.send(msg).await?;
    }
    
    Ok(())
}

💡 Key Features Demonstrated

  • Automatic message serialization/deserialization
  • Concurrent message handling
  • Type-safe message passing
  • Built-in error handling

File Transfer System

Learn how to build a secure file transfer system using VSTP's reliable TCP mode with progress tracking.

Step 1: Define Transfer Messages

#[derive(Serialize, Deserialize)]
pub struct FileInfo {
    pub filename: String,
    pub size: u64,
    pub checksum: String,
}

#[derive(Serialize, Deserialize)]
pub struct FileChunk {
    pub chunk_id: u32,
    pub data: Vec<u8>,
    pub is_last: bool,
}

#[derive(Serialize, Deserialize)]
pub struct TransferProgress {
    pub bytes_transferred: u64,
    pub total_bytes: u64,
}

Step 2: File Transfer Server

use std::path::Path;
use sha2::{Sha256, Digest};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;
    
    server.serve(|chunk: FileChunk| async move {
        // Save chunk to file
        let mut file = tokio::fs::OpenOptions::new()
            .create(true)
            .append(true)
            .open("received_file").await?;
            
        file.write_all(&chunk.data).await?;
        
        // Send progress update
        let progress = TransferProgress {
            bytes_transferred: chunk.chunk_id as u64 * 1024,
            total_bytes: 0, // Would be set from initial FileInfo
        };
        
        Ok(progress)
    }).await?;

    Ok(())
}

🔒 Security Features

  • Automatic TLS 1.3 encryption
  • File integrity verification
  • Progress tracking and resumption
  • Error recovery and retry logic

Real-time Data Streaming

Build a high-performance data streaming system using VSTP's UDP mode for low-latency communication.

Step 1: Define Data Types

#[derive(Serialize, Deserialize)]
pub struct SensorData {
    pub sensor_id: String,
    pub timestamp: u64,
    pub temperature: f32,
    pub humidity: f32,
    pub pressure: f32,
}

#[derive(Serialize, Deserialize)]
pub struct DataStream {
    pub stream_id: String,
    pub data: Vec<SensorData>,
}

Step 2: UDP Data Server

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = VstpServer::bind_udp("127.0.0.1:8080").await?;
    
    server.serve(|data: SensorData| async move {
        // Process real-time data
        println!("Sensor {}: {:.2}°C, {:.2}%", 
                 data.sensor_id, data.temperature, data.humidity);
        
        // Store in database or forward to other systems
        store_sensor_data(&data).await?;
        
        Ok(data)
    }).await?;

    Ok(())
}

async fn store_sensor_data(data: &SensorData) -> Result<(), Box<dyn std::error::Error>> {
    // Implementation for storing data
    Ok(())
}

⚡ Performance Tips

  • Use UDP for low-latency requirements
  • Batch multiple data points in single messages
  • Implement custom reliability for critical data
  • Monitor network conditions and adjust accordingly

Microservices Communication

Learn how to use VSTP for inter-service communication in a microservices architecture.

Step 1: Service Discovery

#[derive(Serialize, Deserialize)]
pub struct ServiceRequest {
    pub service_name: String,
    pub method: String,
    pub payload: serde_json::Value,
    pub request_id: String,
}

#[derive(Serialize, Deserialize)]
pub struct ServiceResponse {
    pub request_id: String,
    pub result: Result<serde_json::Value, String>,
}

Step 2: Service Gateway

use std::collections::HashMap;

type ServiceRegistry = Arc<Mutex<HashMap<String, String>>>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let registry = Arc::new(Mutex::new(HashMap::new()));
    let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;
    
    server.serve(move |req: ServiceRequest| {
        let registry = registry.clone();
        async move {
            // Route request to appropriate service
            let service_addr = registry.lock().await
                .get(&req.service_name)
                .ok_or("Service not found")?;
                
            // Forward request and return response
            let response = forward_request(service_addr, &req).await?;
            Ok(response)
        }
    }).await?;

    Ok(())
}

🏗️ Architecture Benefits

  • Type-safe service communication
  • Automatic load balancing
  • Built-in service discovery
  • Secure inter-service communication

IoT Device Communication

Build a robust IoT device communication system with automatic reconnection and data buffering.

Step 1: Device Messages

#[derive(Serialize, Deserialize)]
pub struct DeviceStatus {
    pub device_id: String,
    pub battery_level: u8,
    pub signal_strength: i8,
    pub last_seen: u64,
}

#[derive(Serialize, Deserialize)]
pub struct DeviceCommand {
    pub device_id: String,
    pub command: String,
    pub parameters: serde_json::Value,
}

Step 2: IoT Gateway

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = VstpServer::bind_tcp("0.0.0.0:8080").await?;
    
    server.serve(|status: DeviceStatus| async move {
        // Update device status in database
        update_device_status(&status).await?;
        
        // Check for pending commands
        if let Some(command) = get_pending_command(&status.device_id).await? {
            return Ok(command);
        }
        
        Ok(DeviceCommand {
            device_id: status.device_id,
            command: "heartbeat".to_string(),
            parameters: serde_json::Value::Null,
        })
    }).await?;

    Ok(())
}

🔋 IoT Considerations

  • Implement connection pooling for efficiency
  • Use message queuing for offline devices
  • Implement data compression for bandwidth
  • Add device authentication and authorization

Next Steps

Ready to build your own application? Check out these resources: