# volt-client-grpc
A Rust client library for connecting to TDX Volt servers via gRPC.
## Overview
This library provides a Rust implementation for:
- Authenticating with Volt servers (direct and relayed connections)
- Managing persistent connections with automatic reconnection
- Making unary and streaming gRPC calls
- Resource management operations
- File operations
- Database operations
- Y.js/yrs document synchronization via SyncProvider
## Proto File Compilation
This package includes protobuf definitions in the `proto/volt_api/` directory. The build script uses `tonic-build` to compile these into Rust code.
```
packages/volt-client-grpc/
├── proto/
│ ├── sync.proto # Sync protocol definitions
│ └── volt_api/
│ └── tdx/volt_api/
│ ├── volt/ # Main Volt API
│ ├── data/ # Database API
│ ├── relay/ # Relay API
│ └── proto_db_sync/ # DB sync protocol
├── src/
└── build.rs
```
The proto files are automatically compiled during the build process.
### Generated Types
The following modules are generated from proto files:
- `proto::volt` - Main Volt API (authentication, resources, connections)
- `proto::data` - Database API (SQLite operations)
- `proto::relay` - Relay API (for relayed connections through cloud relay)
- `proto::proto_db_sync` - Database sync protocol
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
volt-client-grpc = { path = "path/to/volt-client-grpc" }
```
## Usage
### Basic Connection
```rust
use volt_client_grpc::{VoltClient, VoltClientConfig, InitialiseOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load configuration from file
let mut client = VoltClient::new()?;
client.initialise(
"volt.config.json".into(),
InitialiseOptions::default()
).await?;
// Connect to the Volt
let mut events = client.connect(None).await?;
// Handle connection events
tokio::spawn(async move {
while let Some(event) = events.recv().await {
match event {
volt_client_grpc::volt_connection::ConnectionEvent::Connected(id) => {
println!("Connected with ID: {}", id);
}
volt_client_grpc::volt_connection::ConnectionEvent::Disconnected => {
println!("Disconnected");
}
volt_client_grpc::volt_connection::ConnectionEvent::Ping(ts) => {
println!("Ping: {}", ts);
}
_ => {}
}
}
});
// Make API calls
let resources = client.get_resources(serde_json::json!({})).await?;
println!("Resources: {:?}", resources);
// Disconnect when done
client.disconnect().await;
Ok(())
}
```
### Configuration
Configuration can be provided in several ways:
```rust
use volt_client_grpc::{VoltClient, VoltClientConfig, VoltConfig, ConfigSource};
// From a file
let source: ConfigSource = "volt.config.json".into();
// From a config struct
let config = VoltClientConfig {
client_name: "my-client".to_string(),
volt: VoltConfig {
id: "did:volt:example".to_string(),
address: Some("localhost:8080".to_string()),
ca_pem: Some("-----BEGIN CERTIFICATE-----...".to_string()),
..Default::default()
},
..Default::default()
};
let source: ConfigSource = config.into();
// From JSON
let source: ConfigSource = serde_json::json!({
"client_name": "my-client",
"volt": {
"id": "did:volt:example",
"address": "localhost:8080"
}
}).into();
```
### Configuration File Format
```json
{
"client_name": "my-rust-client",
"volt": {
"id": "did:volt:your-volt-id",
"address": "volt.example.com:443",
"ca_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
},
"auto_reconnect": true,
"ping_interval": 10000,
"reconnect_interval": 5000,
"timeout_interval": 60000
}
```
### Authentication Options
```rust
use volt_client_grpc::InitialiseOptions;
// Default DID-based authentication
let options = InitialiseOptions::default();
// Session-only authentication (no DID)
let options = InitialiseOptions::new().with_no_did();
// Manage your own DID
let options = InitialiseOptions::new().with_own_did();
// Use an exchange token
let options = InitialiseOptions::new()
.with_exchange_token("your-token".to_string());
// Custom DID registries
let options = InitialiseOptions::new()
.with_did_registries(vec![
"https://custom-registry.example.com".to_string()
]);
```
### Resource Operations
```rust
// Get a resource
let resource = client.get_resource(serde_json::json!({
"resource_id": "resource-123"
})).await?;
// Save a resource
let result = client.save_resource(serde_json::json!({
"id": "resource-123",
"name": "My Resource",
"type": "custom"
})).await?;
// Delete a resource
let result = client.delete_resource(serde_json::json!({
"resource_id": "resource-123"
})).await?;
// Request access to a resource
use volt_client_grpc::VoltAccessType;
let granted = client.request_access_blocking(
"resource-123",
VoltAccessType::Read
).await?;
```
### Database Operations
```rust
// Create a database
let result = client.create_database(serde_json::json!({
"name": "my-database"
})).await?;
// Bulk update
let result = client.bulk_update(serde_json::json!({
"database_id": "db-123",
"statement": ["INSERT INTO users (name) VALUES ('Alice')"]
})).await?;
```
## API Reference
### VoltClient
The main client struct for interacting with a Volt server.
#### Methods
- `new()` - Create a new client
- `initialise(config, options)` - Initialize with configuration
- `initialise_and_connect(config, options, hello)` - Initialize and connect
- `connect(hello)` - Connect to the server
- `disconnect()` - Disconnect from the server
- `is_connected()` - Check connection status
- `close()` - Close and release resources
#### Resource Management
- `can_access_resource(request)` - Check resource access
- `delete_resource(request)` - Delete a resource
- `get_resource(request)` - Get a resource
- `get_resources(request)` - Get multiple resources
- `save_resource(request)` - Save a resource
- `request_access(request)` - Request resource access
#### File Operations
- `get_file_content(request)` - Get file content
- `set_file_content(request)` - Set file content
- `get_file_descendants(request)` - Get file descendants
#### Database Operations
- `create_database(request)` - Create a database
- `bulk_update(request)` - Bulk update
### VoltCredential
Manages authentication credentials.
### VoltConnection
Manages the persistent connection with automatic reconnection.
## Examples
See the `examples/` directory for complete working examples:
| `grpc-client` | Basic gRPC client connection |
| `grpc-create-resource` | Create resources via gRPC |
| `sync-provider` | Y.js document synchronization |
| `sync-provider-with-subdocs` | Subdocument sync with events |
| `sync-manager-example` | High-level SyncManager API |
| `subdoc-writer` | Interactive subdocument editing |
Run an example:
```bash
cd examples/sync-provider
cargo run
```
## Features
- **Async/Await**: Built on Tokio for async operations
- **TLS Support**: Secure connections using rustls
- **Auto-Reconnect**: Automatic reconnection on disconnect
- **DID Support**: Decentralized identifier authentication
- **Streaming**: Support for bidirectional streaming RPCs
## Comparison with JavaScript Version
| Runtime | Node.js | Tokio |
| gRPC | @grpc/grpc-js | tonic |
| TLS | Node crypto | rustls |
| Crypto | Node crypto | ring, ed25519-dalek |
| Events | EventEmitter | mpsc channels |
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.