Skip to Content
docsClient-APIsRust

Last Updated: 3/9/2026


Skip to main content

Rust Client

A Rust client for interacting with the Pie server.

Installation

Add to your Cargo.toml:

[dependencies][dependencies]pie-client = "0.1"pie-client = "0.1"tokio = { version = "1", features = ["full"] }tokio = { version = "1", features = ["full"] }anyhow = "1"anyhow = "1"

Quick Start

use pie_client::{Client, InstanceEvent}; use pie_client::{Client, InstanceEvent}; use anyhow::Result; use anyhow:: Result; #[tokio::main] #[tokio::main] async fn main() -> Result<()> { async fn main() -> Result<()> { // Connect to server // Connect to server let client = Client::connect("ws://127.0.0.1:8080").await?; let client = Client:: connect("ws://127.0.0.1:8080"). await?; // Authenticate // Authenticate client.authenticate("username", &None).await?; client. authenticate("username", & None). await?; // Launch an inferlet from registry // Launch an inferlet from registry let mut instance = client.launch_instance_from_registry( let mut instance = client. launch_instance_from_registry( "text-completion".to_string(), "text-completion". to_string(), vec!["--prompt".to_string(), "Hello, world!".to_string()], vec!["--prompt". to_string(), "Hello, world!". to_string()], false, // not detached false, // not detached ).await?; ). await?; // Receive output // Receive output loop { loop { match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Stdout(text) => print!("{}", text), InstanceEvent:: Stdout(text) => print!("{}", text), InstanceEvent::Completed(_) => break, InstanceEvent:: Completed(_) => break, InstanceEvent::Exception(msg) => { InstanceEvent:: Exception(msg) => { eprintln!("Error: {}", msg); eprintln!("Error: {}", msg); break; break; } } _ => {} _ => {} } } } } client.close()?; client. close()?; Ok(()) Ok(()) } }

Client

The main client struct for connecting to a Pie server.

Construction

let client = Client::connect("ws://127.0.0.1:8080").await?; let client = Client:: connect("ws://127.0.0.1:8080"). await?;

Methods

MethodReturnsDescription
connect(ws_host)Result<Client>Connect to server
close(self)Result<()>Close connection
authenticate(username, key)Result<()>Authenticate with server
internal_authenticate(token)Result<()>Internal token auth
upload_program(bytes)Result<()>Upload WASM program
program_exists(hash)Result<bool>Check if program exists
launch_instance(hash, args, detached)Result<Instance>Launch by hash
launch_instance_from_registry(name, args, detached)Result<Instance>Launch from registry
attach_instance(id)Result<Instance>Attach to existing
list_instances()Result<Vec<InstanceInfo>>List instances
terminate_instance(id)Result<()>Terminate instance
ping()Result<()>Check connectivity

Authentication

use pie_client::crypto::ParsedPrivateKey; use pie_client:: crypto:: ParsedPrivateKey; // With SSH key // With SSH key let key = ParsedPrivateKey::from_file("~/.ssh/id_ed25519")?; let key = ParsedPrivateKey:: from_file("~/.ssh/id_ed25519")?; client.authenticate("username", &Some(key)).await?; client. authenticate("username", & Some(key)). await?; // Without key (when server auth is disabled) // Without key (when server auth is disabled) client.authenticate("username", &None).await?; client. authenticate("username", & None). await?;

Instance

Represents a running program instance.

Methods

MethodReturnsDescription
id()InstanceIdGet instance ID
send(message)Result<()>Send string message
upload_blob(bytes)Result<()>Upload binary data
recv()Result<InstanceEvent>Receive next event

Example

let mut instance = client.launch_instance_from_registry(let mut instance = client. launch_instance_from_registry( "chat".to_string(), "chat". to_string(), vec![], vec![], false, false, ).await?; ). await?; // Send a message // Send a message instance.send("What is 2 + 2?")?; instance. send("What is 2 + 2?")?; // Receive response // Receive response match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Message(text) => println!("{}", text), InstanceEvent:: Message(text) => println!("{}", text), InstanceEvent::Stdout(text) => print!("{}", text), InstanceEvent:: Stdout(text) => print!("{}", text), _ => {} _ => {} } }

InstanceEvent

Events received from instances:

pub enum InstanceEvent {pub enum InstanceEvent { /// Text message from instance /// Text message from instance Message(String), Message(String), /// Instance completed successfully /// Instance completed successfully Completed(String), Completed(String), /// Instance was aborted /// Instance was aborted Aborted(String), Aborted(String), /// Instance raised an exception /// Instance raised an exception Exception(String), Exception(String), /// Server-side error /// Server-side error ServerError(String), ServerError(String), /// Resource limit reached /// Resource limit reached OutOfResources(String), OutOfResources(String), /// Binary data /// Binary data Blob(Vec<u8>), Blob(Vec< u8>), /// Streaming stdout /// Streaming stdout Stdout(String), Stdout(String), /// Streaming stderr /// Streaming stderr Stderr(String), Stderr(String), } }

Pattern Matching

loop {loop { match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Stdout(text) => { InstanceEvent:: Stdout(text) => { print!("{}", text); print!("{}", text); std::io::stdout().flush()?; std:: io:: stdout(). flush()?; } } InstanceEvent::Stderr(text) => { InstanceEvent:: Stderr(text) => { eprint!("{}", text); eprint!("{}", text); } } InstanceEvent::Completed(msg) => { InstanceEvent:: Completed(msg) => { println!("\nCompleted: {}", msg); println!("\nCompleted: {}", msg); break; break; } } InstanceEvent::Exception(err) => { InstanceEvent:: Exception(err) => { return Err(anyhow!("Inferlet error: {}", err)); return Err(anyhow!("Inferlet error: {}", err)); } } InstanceEvent::ServerError(err) => { InstanceEvent:: ServerError(err) => { return Err(anyhow!("Server error: {}", err)); return Err(anyhow!("Server error: {}", err)); } } _ => {} _ => {} } } } }

Upload Custom Inferlet

use pie_client::hash_blob; use pie_client:: hash_blob; // Read and upload // Read and upload let wasm_bytes = std::fs::read("my_inferlet.wasm")?; let wasm_bytes = std:: fs:: read("my_inferlet.wasm")?; client.upload_program(&wasm_bytes).await?; client. upload_program(& wasm_bytes). await?; // Get hash for launching // Get hash for launching let program_hash = hash_blob(&wasm_bytes); let program_hash = hash_blob(& wasm_bytes); // Launch // Launch let mut instance = client.launch_instance( let mut instance = client. launch_instance( program_hash, program_hash, vec!["--arg".to_string(), "value".to_string()], vec!["--arg". to_string(), "value". to_string()], false, false, ).await?; ). await?;

Detached Instances

// Launch detached // Launch detached let instance = client.launch_instance_from_registry( let instance = client. launch_instance_from_registry( "long-task".to_string(), "long-task". to_string(), vec![], vec![], true, // detached true, // detached ).await?; ). await?; let instance_id = instance.id(); let instance_id = instance. id(); // Later, reattach // Later, reattach let mut attached = client.attach_instance(&instance_id.to_string()).await?; let mut attached = client. attach_instance(& instance_id. to_string()). await?; let event = attached.recv().await?; let event = attached. recv(). await?;

Error Handling

use anyhow::{Result, Context}; use anyhow::{Result, Context}; async fn run() -> Result<()> { async fn run() -> Result<()> { let client = Client::connect("ws://127.0.0.1:8080") let client = Client:: connect("ws://127.0.0.1:8080") .await . await .context("Failed to connect to Pie server")?; . context("Failed to connect to Pie server")?; client.authenticate("username", &None) client. authenticate("username", & None) .await . await .context("Authentication failed")?; . context("Authentication failed")?; // ... // ... Ok(()) Ok(()) } }

Thread Safety

The Client is thread-safe and can be shared across tasks:

use std::sync::Arc; use std:: sync:: Arc; let client = Arc::new(Client::connect("ws://127.0.0.1:8080").await?); let client = Arc:: new(Client:: connect("ws://127.0.0.1:8080"). await?); let c1 = client.clone(); let c1 = client. clone(); let h1 = tokio::spawn(async move { let h1 = tokio:: spawn(async move { // Use c1 // Use c1 }); }); let c2 = client.clone(); let c2 = client. clone(); let h2 = tokio::spawn(async move { let h2 = tokio:: spawn(async move { // Use c2 // Use c2 }); }); h1.await?; h1. await?; h2.await?; h2. await?;