Migration Guide: v0.1 → v0.2

v0.1v0.2

Migration Overview

VSTP v0.2 introduces a new simplified API that makes it much easier to build networked applications. This guide will help you migrate your existing v0.1 code to take advantage of the new features.

🎯 Migration Benefits

  • Simplified API: Less boilerplate code
  • Automatic Serialization: No manual frame handling
  • Better Error Handling: More descriptive error messages
  • Unified Interface: Same API for TCP and UDP
  • Built-in Timeouts: Automatic timeout handling

⚠️ Important Notes

  • v0.2 is not backward compatible with v0.1
  • The low-level API is still available for advanced use cases
  • All existing functionality is preserved
  • Migration should be straightforward for most applications

Breaking Changes

Here are the main breaking changes you need to be aware of when migrating from v0.1 to v0.2:

1. New Simplified API

v0.1 (Old)

// Manual frame creation
let frame = Frame::new(FrameType::Data)
    .with_payload(data);

// Manual serialization
let payload = serde_json::to_vec(&message)?;
frame.set_payload(payload);

// Manual client management
let client = VstpTcpClient::connect("127.0.0.1:8080").await?;
client.send(frame).await?;
let response = client.recv().await?;

v0.2 (New)

// Automatic serialization
let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;
client.send(message).await?;
let response: MyMessage = client.receive().await?;

2. Error Type Changes

// v0.1
VstpError::Timeout("ACK timeout".to_string())

// v0.2
VstpError::Timeout

3. Method Name Changes

v0.1v0.2Notes
client.send()client.send_frame()Low-level API only
client.recv()client.read_frame()Low-level API only
server.accept()server.run()New handler-based approach

New Features in v0.2

v0.2 introduces several new features that make VSTP easier to use:

1. Simplified Client API

// New easy-to-use client
use vstp::easy::VstpClient;

// TCP client
let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;

// UDP client
let client = VstpClient::connect_udp("127.0.0.1:8080").await?;

// Send any serializable type
client.send(MyMessage { data: "hello" }).await?;

// Receive with automatic deserialization
let response: MyMessage = client.receive().await?;

2. Simplified Server API

// New handler-based server
use vstp::easy::VstpServer;

let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;

server.serve(|msg: MyMessage| async move {
    println!("Received: {:?}", msg);
    Ok(msg) // Echo back
}).await?;

3. Automatic Timeout Handling

// Set custom timeout
let mut client = VstpClient::connect_tcp("127.0.0.1:8080").await?;
client.set_timeout(Duration::from_secs(5));

// All operations now respect the timeout
client.send(message).await?; // Will timeout after 5 seconds

4. Improved Error Types

// New error types
pub enum VstpError {
    // ... existing errors
    SerializationError(serde_json::Error),
    DeserializationError(serde_json::Error),
    InvalidAddress,
    UnexpectedFrameType,
}

Step-by-Step Migration

Follow these steps to migrate your application from v0.1 to v0.2:

Step 1: Update Dependencies

# Cargo.toml
[dependencies]
vstp = "0.2.1"  # Update version
serde = { version = "1.0", features = ["derive"] }  # Add if not present

Step 2: Update Imports

// Old imports
use vstp::{VstpTcpClient, VstpTcpServer, Frame, FrameType};

// New imports
use vstp::easy::{VstpClient, VstpServer};
use serde::{Serialize, Deserialize};

Step 3: Update Message Types

// Add serialization derives
#[derive(Serialize, Deserialize)]
struct MyMessage {
    data: String,
    timestamp: u64,
}

Step 4: Update Client Code

Before (v0.1)

let client = VstpTcpClient::connect("127.0.0.1:8080").await?;

let payload = serde_json::to_vec(&message)?;
let frame = Frame::new(FrameType::Data)
    .with_payload(payload);

client.send(frame).await?;
let response_frame = client.recv().await?;
let response: MyMessage = serde_json::from_slice(
    response_frame.payload()
)?;

After (v0.2)

let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;

client.send(message).await?;
let response: MyMessage = client.receive().await?;

Step 5: Update Server Code

Before (v0.1)

let server = VstpTcpServer::bind("127.0.0.1:8080").await?;

loop {
    let mut client = server.accept().await?;
    
    tokio::spawn(async move {
        while let Ok(Some(frame)) = client.recv().await {
            let message: MyMessage = serde_json::from_slice(
                frame.payload()
            )?;
            
            let response = process_message(message).await?;
            let response_payload = serde_json::to_vec(&response)?;
            let response_frame = Frame::new(FrameType::Data)
                .with_payload(response_payload);
                
            client.send(response_frame).await?;
        }
    });
}

After (v0.2)

let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;

server.serve(|message: MyMessage| async move {
    let response = process_message(message).await?;
    Ok(response)
}).await?;

Step 6: Update Error Handling

// Update error handling
match client.receive::<MyMessage>().await {
    Ok(message) => {
        // Handle message
    }
    Err(VstpError::Timeout) => {
        // Handle timeout
    }
    Err(VstpError::SerializationError(e)) => {
        // Handle serialization error
    }
    Err(e) => {
        // Handle other errors
    }
}

Migration Examples

Here are complete examples showing how to migrate common patterns:

Echo Server Migration

v0.1 Echo Server

use vstp::{VstpTcpServer, Frame, FrameType};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = VstpTcpServer::bind("127.0.0.1:8080").await?;
    
    loop {
        let mut client = server.accept().await?;
        
        tokio::spawn(async move {
            while let Ok(Some(frame)) = client.recv().await {
                let response_frame = Frame::new(FrameType::Data)
                    .with_payload(frame.payload().to_vec());
                client.send(response_frame).await?;
            }
            Ok::<(), vstp::VstpError>(())
        });
    }
}

v0.2 Echo Server

use vstp::easy::VstpServer;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct EchoMessage {
    content: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = VstpServer::bind_tcp("127.0.0.1:8080").await?;
    
    server.serve(|msg: EchoMessage| async move {
        println!("Echoing: {}", msg.content);
        Ok(msg)
    }).await?;

    Ok(())
}

Chat Application Migration

v0.1 Chat Client

use vstp::{VstpTcpClient, Frame, FrameType};
use serde::{Serialize, Deserialize};

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = VstpTcpClient::connect("127.0.0.1:8080").await?;
    
    let msg = ChatMessage {
        from: "Alice".to_string(),
        content: "Hello!".to_string(),
    };
    
    let payload = serde_json::to_vec(&msg)?;
    let frame = Frame::new(FrameType::Data).with_payload(payload);
    
    client.send(frame).await?;
    
    let response_frame = client.recv().await?
        .ok_or("Connection closed")?;
    let response: ChatMessage = serde_json::from_slice(
        response_frame.payload()
    )?;
    
    println!("Received: {}", response.content);
    Ok(())
}

v0.2 Chat Client

use vstp::easy::VstpClient;
use serde::{Serialize, Deserialize};

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;
    
    let msg = ChatMessage {
        from: "Alice".to_string(),
        content: "Hello!".to_string(),
    };
    
    client.send(msg.clone()).await?;
    let response: ChatMessage = client.receive().await?;
    
    println!("Received: {}", response.content);
    Ok(())
}

Troubleshooting Migration Issues

Here are common issues you might encounter during migration and how to resolve them:

Compilation Errors

Error: "cannot find function `connect` in `VstpTcpClient`"

Solution: Use the new simplified API:

// Old
let client = VstpTcpClient::connect("127.0.0.1:8080").await?;

// New
let client = VstpClient::connect_tcp("127.0.0.1:8080").await?;

Error: "the trait `Serialize` is not implemented"

Solution: Add serialization derives:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct MyMessage {
    data: String,
}

Error: "expected function, found `VstpError::Timeout`"

Solution: Update error handling:

// Old
VstpError::Timeout("ACK timeout".to_string())

// New
VstpError::Timeout

Runtime Issues

Issue: Messages not being received

Solution: Ensure your message types match between client and server. The new API is more strict about type matching.

Issue: Timeout errors

Solution: The new API has a default 30-second timeout. Adjust it if needed:

let mut client = VstpClient::connect_tcp("127.0.0.1:8080").await?;
client.set_timeout(Duration::from_secs(60));

Need Help?

If you encounter issues during migration, here are some resources: