| Crates.io | ziti-sdk |
| lib.rs | ziti-sdk |
| version | 0.1.0 |
| created_at | 2025-08-04 06:15:28.869524+00 |
| updated_at | 2025-08-04 06:15:28.869524+00 |
| description | Ziti Rust SDK - High-performance, async-first implementation for secure, zero-trust networking |
| homepage | https://github.com/jaschadub/ziti-rust |
| repository | https://github.com/jaschadub/ziti-rust |
| max_upload_size | |
| id | 1780379 |
| size | 1,596,470 |
A high-performance, async-first Rust implementation that provides secure, zero-trust networking capabilities through the OpenZiti platform. This is an unofficial SDK.
Add this to your Cargo.toml:
[dependencies]
ziti-sdk = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
Before using the Ziti Rust SDK, you'll need:
.json) with appropriate service policiesuse ziti_sdk::{Context, ZitiResult};
#[tokio::main]
async fn main() -> ZitiResult<()> {
// Load identity from file
let context = Context::from_file("identity.json").await?;
// Connect to a service
let mut stream = context.dial("echo-service").await?;
// Use the stream for communication
// (implements standard Rust AsyncRead + AsyncWrite traits)
Ok(())
}
use ziti_sdk::{Context, ZitiResult};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> ZitiResult<()> {
// Create context from identity file
let context = Context::from_file("client-identity.json").await?;
// Connect to the service
let mut stream = context.dial("my-service").await?;
// Send data
stream.write_all(b"Hello, Ziti!").await?;
// Read response
let mut buffer = [0; 1024];
let n = stream.read(&mut buffer).await?;
println!("Received: {}", String::from_utf8_lossy(&buffer[..n]));
Ok(())
}
use ziti_sdk::{Context, ZitiResult};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> ZitiResult<()> {
// Create context from identity file
let context = Context::from_file("server-identity.json").await?;
// Start listening on a service
let mut listener = context.listen("my-service").await?;
println!("Listening on service: {}", listener.service_name());
// Accept incoming connections
loop {
match listener.accept().await {
Ok(mut stream) => {
// Handle connection in a separate task
tokio::spawn(async move {
let mut buffer = [0; 1024];
match stream.read(&mut buffer).await {
Ok(n) => {
println!("Received: {}", String::from_utf8_lossy(&buffer[..n]));
// Echo back the data
let _ = stream.write_all(&buffer[..n]).await;
}
Err(e) => eprintln!("Error reading from stream: {}", e),
}
});
}
Err(e) => {
eprintln!("Error accepting connection: {}", e);
break;
}
}
}
Ok(())
}
use ziti_sdk::{Context, ZitiResult, DialOptions, ListenOptions};
use std::time::Duration;
#[tokio::main]
async fn main() -> ZitiResult<()> {
let context = Context::from_file("identity.json").await?;
// Dial with custom options
let dial_options = DialOptions {
timeout: Some(Duration::from_secs(30)),
identity: Some("specific-identity".to_string()),
};
// Note: Context-level dialing doesn't currently use DialOptions,
// but this shows the intended API pattern
// Listen with custom options
let listen_options = ListenOptions {
identity: Some("server-identity".to_string()),
cost: Some(100),
precedence: Some("high".to_string()),
};
let listener = context.listen_with_options("my-service", &listen_options).await?;
Ok(())
}
Ziti identity files are JSON documents containing certificates and configuration:
{
"ztAPI": "https://controller.example.com:1280",
"id": {
"cert": "-----BEGIN CERTIFICATE-----\n...",
"key": "-----BEGIN PRIVATE KEY-----\n...",
"ca": "-----BEGIN CERTIFICATE-----\n..."
}
}
use ziti_sdk::{Context, ContextBuilder, ZitiConfig};
// Method 1: Load from file (recommended)
let context = Context::from_file("identity.json").await?;
// Method 2: Build programmatically (future feature)
let context = ContextBuilder::new()
.with_config(config)
.build()
.await?;
The SDK respects these environment variables:
ZITI_IDENTITY_FILE: Default path to identity fileZITI_LOG_LEVEL: Logging level (error, warn, info, debug, trace)The SDK provides comprehensive error types for different scenarios:
use ziti_sdk::{ZitiError, ZitiResult};
async fn handle_connection() -> ZitiResult<()> {
let context = Context::from_file("identity.json").await?;
match context.dial("service-name").await {
Ok(stream) => {
// Handle successful connection
Ok(())
}
Err(ZitiError::ServiceNotFound { service_name }) => {
eprintln!("Service '{}' not found or not accessible", service_name);
Err(ZitiError::ServiceNotFound { service_name })
}
Err(ZitiError::ConnectionFailed(reason)) => {
eprintln!("Connection failed: {}", reason);
// Potentially retry with backoff
Err(ZitiError::ConnectionFailed(reason))
}
Err(ZitiError::ApiSessionExpired) => {
eprintln!("Session expired, will be renewed automatically");
// The SDK handles session renewal internally
Err(ZitiError::ApiSessionExpired)
}
Err(e) => {
eprintln!("Unexpected error: {}", e);
Err(e)
}
}
}
The SDK provides helper methods for error categorization:
use ziti_sdk::ZitiError;
fn handle_error(error: &ZitiError) {
if error.is_recoverable() {
println!("This error can be retried");
}
if error.requires_session_renewal() {
println!("Session needs renewal");
}
if error.is_configuration_error() {
println!("Check your configuration");
}
}
use ziti_sdk::{Context, IdentityManager, SessionManager};
// Create context with existing managers
let identity_manager = IdentityManager::load_from_file("identity.json").await?;
let session_manager = SessionManager::new(identity_manager.clone());
let context = Context::from_managers(identity_manager, session_manager);
// Access underlying managers
let identity = context.identity_manager();
let sessions = context.session_manager();
use ziti_sdk::{Context, ZitiStream};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
async fn connection_lifecycle() -> ZitiResult<()> {
let context = Context::from_file("identity.json").await?;
// Establish connection
let mut stream = context.dial("my-service").await?;
// Use connection
stream.write_all(b"Hello").await?;
let mut response = String::new();
stream.read_to_string(&mut response).await?;
// Connection automatically closed when stream is dropped
Ok(())
}
Context - Main SDK entry pointZitiStream - Bidirectional communication streamZitiListener - Server listener for incoming connectionsDialOptions - Options for outbound connectionsListenOptions - Options for service hostingZitiConfig - SDK configurationZitiError - Comprehensive error enumerationZitiResult<T> - Result type aliasSee the examples/ directory for complete working examples:
simple_client.rs - Basic client connectionsimple_server.rs - Basic server implementationecho_server.rs - Echo server with error handlinghttp_proxy.rs - HTTP proxy over ZitiWe welcome contributions! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License - see the LICENSE file for details.
Documentation: https://docs.rs/ziti-sdk
Issues: GitHub Issues