| Crates.io | onionoo |
| lib.rs | onionoo |
| version | 0.1.0 |
| created_at | 2025-10-28 04:50:56.735241+00 |
| updated_at | 2025-10-28 04:50:56.735241+00 |
| description | Wrapper for the Onionoo Tor network status and metrics protocol, providing a convenient interface to query information about Tor relays and bridges. |
| homepage | |
| repository | https://gitlab.com/spacepirate/onionoo-rs |
| max_upload_size | |
| id | 1904173 |
| size | 119,259 |
A Rust wrapper for the Onionoo Tor network status protocol, providing a convenient and type-safe interface to query information about Tor relays and bridges.
Add this to your Cargo.toml:
[dependencies]
onionoo = "0.1.0"
Then, in your Rust file:
use onionoo::Client;
To start interacting with the Onionoo API, you first need to create a Client instance.
use onionoo::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new client with the default Onionoo URL
let client = Client::new();
// Or, if you want to use another url
let custom_client = Client::new_with_base_url("https://your-onionoo-instance.com");
Ok(())
}
Queries are built using the QueryParameters builder. This allows you to filter and customize the results returned by the API.
use onionoo::{Client, QueryParameters, parameters::selection::TypeValue, parameters::selection::BoolValue};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Build a query to get running relays located in the US, limited to 5 results
let params = QueryParameters::new()
.type_param(TypeValue::Relay)
.running(BoolValue::True)
.country("US")
.limit(5);
println!("Query string: {}", params.to_query_string()); // Example output: ?country=US&limit=5&running=true&type=relay
Ok(())
}
Once you have a client and query parameters, you can call one of the available endpoint functions. All endpoint functions return a Result containing either the successful response data or a ClientError.
use onionoo::{Client, QueryParameters, endpoints, parameters::selection::TypeValue};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let params = QueryParameters::new()
.type_param(TypeValue::Relay)
.limit(3);
// Call the summary endpoint
match endpoints::summary(&client, params).await {
Ok(summary_response) => {
println!("Successfully fetched summary data.");
println!("Version: {}", summary_response.version);
println!("Number of relays returned: {}", summary_response.relays.len());
println!("Number of bridges returned: {}", summary_response.bridges.len());
// Accessing data from relay summaries
if let Some(first_relay) = summary_response.relays.first() {
println!(
"First relay: Nickname={}, Fingerprint={}, Addresses={:?}, Running={}",
first_relay.n, first_relay.f, first_relay.a, first_relay.r
);
}
// Accessing data from bridge summaries
if let Some(first_bridge) = summary_response.bridges.first() {
println!(
"First bridge: Nickname={}, Hashed Fingerprint={}, Running={}",
first_bridge.n, first_bridge.h, first_bridge.r
);
}
}
Err(e) => {
eprintln!("Error fetching summary data: {}", e);
}
}
Ok(())
}
The response models (e.g., SummaryResponse, DetailsResponse) are structured to mirror the JSON responses from the Onionoo API. They contain common fields like version, relays_published, bridges_published, and vectors of relay-specific and bridge-specific data structures.
For example, a SummaryResponse contains:
relays: Vec<RelaySummary>bridges: Vec<BridgeSummary>A RelaySummary object has fields like n (nickname), f (fingerprint), a (addresses), and r (running status).
A BridgeSummary object has fields like n (nickname), h (hashed fingerprint), and r (running status).
You can access these fields directly as shown in the previous example. For more detailed information, refer to the structs in the models module.
The library provides functions for all major Onionoo endpoints. Each endpoint function takes a &Client and QueryParameters and returns a Result with the corresponding response type.
endpoints::summary(client, params):
Result<models::SummaryResponse, ClientError>.endpoints::details(client, params):
Result<models::DetailsResponse, ClientError>.endpoints::bandwidth(client, params):
Result<models::BandwidthResponse, ClientError>.endpoints::weights(client, params):
Result<models::WeightsResponse, ClientError>.endpoints::clients(client, params):
Result<models::ClientsResponse, ClientError>.endpoints::uptime(client, params):
Result<models::UptimeResponse, ClientError>.The library uses a custom ClientError enum to represent various errors that can occur during API interactions. You should handle these errors when calling endpoint functions.
The ClientError enum includes the following variants:
ClientError::Request(reqwest::Error):
reqwest::Error provides more specific details.ClientError::StatusCode(u16, String):
ClientError::Deserialization(String):
serde_json.ClientError::UrlConstruction(String):
/.ClientError::Other(String):
use onionoo::{Client, QueryParameters, endpoints, client::ClientError};
#[tokio::main]
async fn main() {
let client = Client::new();
let params = QueryParameters::new().limit(10); // Valid parameters
match endpoints::summary(&client, params).await {
Ok(response) => {
println!("Fetched {} relays.", response.relays.len());
}
Err(ClientError::Request(e)) => {
eprintln!("Network or HTTP request error: {}", e);
}
Err(ClientError::StatusCode(code, message)) => {
eprintln!("API returned error status {}: {}", code, message);
}
Err(ClientError::Deserialization(e)) => {
eprintln!("Failed to parse API response: {}", e);
}
Err(ClientError::UrlConstruction(e)) => {
eprintln!("URL construction error: {}", e);
}
Err(ClientError::Other(e)) => {
eprintln!("An unexpected error occurred: {}", e);
}
}
}
This project is not endorsed by or affiliated with the Tor Project or the Rust Foundation.