A library for accessing Admin API of Yggdrasil Network router.
It supports both sync and async environment. All you need is to provide
socket that implements either Read
and Write
traits from std
for synchronous
operations or AsyncRead
and AsyncWrite
traits from an async runtime.
Currently supported runtimes are tokio
and futures
. If your favorite
runtime is not in the list, consider creating an issue or pull request.
This library is backward-compatible with the most existing versions of yggdrasil-go
, and have a prospect of forward-compatibility.
Despite this, potential user should note that yggdrasil-go
is still an experimental software.
And there were seen breaking changes in the certain API calls, notably in versions 0.4.5
(October 2022), 0.5.0
(November 2023).
Nevertheless, this library was successfully tested for compatibility with yggdrasil-go
of versions: 0.4.4
, 0.4.7
, 0.5.1
, 0.5.4
, 0.5.5
, 0.5.6
.
You can test compatibility yourself by running the following command in the crate directory.
$ YGGDRASIL_SOCKET="/run/yggdrasil/yggdrasil.sock" cargo test -p yggdrasilctl
Add either line to your dependencies in Cargo.toml
# Use `std` (synchronous)
yggdrasilctl = "1"
# Use async runtime
# Available features: "use_tokio" or "use_futures"
yggdrasilctl = { version = "1", default-features = false, features = [ "use_tokio" ] }
Next:
use yggdrasilctl::Endpoint;
use std::os::unix::net::UnixStream;
// Create socket using your favorite runtime
let socket = UnixStream::connect("/run/yggdrasil/yggdrasil.sock")/*.await*/.unwrap();
// Attach endpoint to a socket
let mut endpoint = Endpoint::attach(socket);
// First you can get I/O or protocol parsing error
let maybe_error = endpoint.get_self()/*.await*/.unwrap();
// Then Admin API can return error (string) to your request
match maybe_error {
Ok(response) => println!("Yggdrasil address: {}", response.address),
Err(error) => println!("Admin API returned error: {error}"),
}
You may also want to perform debug_*
requests which are deliberately unimplemented in this library.
For this case yggdrasilctl
allows you to declare a structure of a response you expect to receive.
First, add crates serde
and serde_json
to your dependecies
# Imports derive macros for `Deserialize` trait
serde = { version = "1", features = [ "derive" ] }
# Imports enum `Value` that represents any possible json value
serde_json = "1"
Next:
use yggdrasilctl::Endpoint;
use serde::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::net::Ipv6Addr;
// Connect endpoint
use std::os::unix::net::UnixStream;
let socket = UnixStream::connect("/var/run/yggdrasil/yggdrasil.sock")/*.await*/.unwrap();
let mut endpoint = Endpoint::attach(socket);
let get_self = endpoint.get_self()/*.await*/.unwrap().unwrap();
// Declare a struct you expect to receive
#[derive(Deserialize)]
struct DebugRemoteGetSelfEntry {
coords: String,
key: String,
}
type DebugRemoteGetSelf = HashMap<Ipv6Addr, DebugRemoteGetSelfEntry>;
// Pass arguments to the request
let mut args = HashMap::<String, Value>::new();
args.insert("key".to_string(), Value::from(get_self.key.as_str()));
// Perform the request
let maybe_error = endpoint.request_args::<DebugRemoteGetSelf>("debug_remotegetself", args)/*.await*/.unwrap();
// Parse the request
match maybe_error {
Ok(response) =>
println!(
"Yggdrasil node coordinates: {:?}",
response[&get_self.address].coords
),
Err(error) => println!("Admin API returned error: {error}"),
}