- Added `NativeClient` for non-WASM environments with automatic reconnection and message handling. - Introduced `WasmClient` for WASM environments, supporting WebSocket communication and reconnection logic. - Created protocol definitions for `SignRequest` and `SignResponse` with serialization and deserialization. - Developed integration tests for the client functionality and sign request handling. - Implemented WASM-specific tests to ensure compatibility and functionality in browser environments.
134 lines
4.6 KiB
Rust
134 lines
4.6 KiB
Rust
//! Basic usage example for sigsocket_client
|
|
//!
|
|
//! This example demonstrates how to:
|
|
//! 1. Create a sigsocket client
|
|
//! 2. Set up a sign request handler
|
|
//! 3. Connect to a sigsocket server
|
|
//! 4. Handle incoming signature requests
|
|
//!
|
|
//! This example only runs on native (non-WASM) targets.
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
use sigsocket_client::{SigSocketClient, SignRequest, SignResponse, SignRequestHandler, Result, SigSocketError};
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
/// Example sign request handler
|
|
///
|
|
/// In a real application, this would:
|
|
/// - Present the request to the user
|
|
/// - Get user approval
|
|
/// - Use a secure signing method (hardware wallet, etc.)
|
|
/// - Return the signature
|
|
struct ExampleSignHandler;
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
impl SignRequestHandler for ExampleSignHandler {
|
|
fn handle_sign_request(&self, request: &SignRequest) -> Result<Vec<u8>> {
|
|
println!("📝 Received sign request:");
|
|
println!(" ID: {}", request.id);
|
|
println!(" Message (base64): {}", request.message);
|
|
|
|
// Decode the message to show what we're signing
|
|
match request.message_bytes() {
|
|
Ok(message_bytes) => {
|
|
println!(" Message (hex): {}", hex::encode(&message_bytes));
|
|
println!(" Message (text): {}", String::from_utf8_lossy(&message_bytes));
|
|
}
|
|
Err(e) => {
|
|
println!(" ⚠️ Failed to decode message: {}", e);
|
|
return Err(SigSocketError::Base64(e.to_string()));
|
|
}
|
|
}
|
|
|
|
// In a real implementation, you would:
|
|
// 1. Show this to the user
|
|
// 2. Get user approval
|
|
// 3. Sign the message using a secure method
|
|
|
|
println!("🤔 Would you like to sign this message? (This is a simulation)");
|
|
println!("✅ Auto-approving for demo purposes...");
|
|
|
|
// Simulate signing - in reality, this would be a real signature
|
|
let fake_signature = format!("fake_signature_for_{}", request.id);
|
|
Ok(fake_signature.into_bytes())
|
|
}
|
|
}
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
#[tokio::main]
|
|
async fn main() -> Result<()> {
|
|
// Initialize logging
|
|
env_logger::init();
|
|
|
|
println!("🚀 SigSocket Client Example");
|
|
println!("============================");
|
|
|
|
// Example public key (in a real app, this would be your actual public key)
|
|
let public_key = hex::decode("02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388")
|
|
.expect("Invalid public key hex");
|
|
|
|
println!("🔑 Public key: {}", hex::encode(&public_key));
|
|
|
|
// Create the client
|
|
let mut client = SigSocketClient::new("ws://localhost:8080/ws", public_key)?;
|
|
println!("📡 Created client for: {}", client.url());
|
|
|
|
// Set up the sign request handler
|
|
client.set_sign_handler(ExampleSignHandler);
|
|
println!("✅ Sign request handler configured");
|
|
|
|
// Connect to the server
|
|
println!("🔌 Connecting to sigsocket server...");
|
|
match client.connect().await {
|
|
Ok(()) => {
|
|
println!("✅ Connected successfully!");
|
|
println!("📊 Connection state: {:?}", client.state());
|
|
}
|
|
Err(e) => {
|
|
println!("❌ Failed to connect: {}", e);
|
|
println!("💡 Make sure the sigsocket server is running on localhost:8080");
|
|
return Err(e);
|
|
}
|
|
}
|
|
|
|
// Keep the connection alive and handle requests
|
|
println!("👂 Listening for signature requests...");
|
|
println!(" (Press Ctrl+C to exit)");
|
|
|
|
// In a real application, you might want to:
|
|
// - Handle reconnection
|
|
// - Provide a UI for user interaction
|
|
// - Manage multiple concurrent requests
|
|
// - Store and manage signatures
|
|
|
|
// For this example, we'll just wait
|
|
tokio::signal::ctrl_c().await.expect("Failed to listen for ctrl-c");
|
|
|
|
println!("\n🛑 Shutting down...");
|
|
client.disconnect().await?;
|
|
println!("✅ Disconnected cleanly");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Example of how you might manually send a response (if needed)
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
#[allow(dead_code)]
|
|
async fn send_manual_response(client: &SigSocketClient) -> Result<()> {
|
|
let response = SignResponse::new(
|
|
"example-request-id",
|
|
"dGVzdCBtZXNzYWdl", // "test message" in base64
|
|
"ZmFrZV9zaWduYXR1cmU=", // "fake_signature" in base64
|
|
);
|
|
|
|
client.send_sign_response(&response).await?;
|
|
println!("📤 Sent manual response: {}", response.id);
|
|
Ok(())
|
|
}
|
|
|
|
// WASM main function (does nothing since this example is native-only)
|
|
#[cfg(target_arch = "wasm32")]
|
|
fn main() {
|
|
// This example is designed for native use only
|
|
}
|