Connecting
Build a node, connect it, keep it connected, and choose a TLS provider.
Building a node
Node::builder() collects what the node is before anything touches the network.
use zyris::{Node, NodeKind};
let node = Node::builder()
.name("my-node") // the name this connection asks for
.kind(NodeKind::Service) // Desktop, Server, Service or Cli
.capability(HelloServer(HelloWorld))
.build()?;| Method | What it does |
|---|---|
name(..) | The node name sent in the handshake. The server may suffix it (-2) if it is taken. |
name_from_hostname() | Name the node after the machine. The machine is already the system segment, so this yields paths like laptop/zyris-code/laptop. |
kind(..) | Desktop, Server, Service or Cli. A Cli peer only consumes capabilities and registers no node. |
capability(..) | Add a capability to serve — usually the …Server wrapper the macro generated. |
capability_arc(..) | The same, for an Arc<dyn ServeCapability> you already hold. |
on_connect(..) | Run an async hook on every established connection, including after each reconnect. |
connect and dial
let link = node.connect(zyris::DEFAULT_SERVER_URL, &credential).await?;connect returns a Link, which owns a dial-and-reconnect loop: backoff with jitter, reset
after a healthy connection. It returns as soon as the first dial has settled.
- A refusal that no retry can fix —
Revoked,Unauthorized,VersionMismatch,NoTlsProvider— is returned as that call's error. - Anything else — a network error, a server restart — is the link's problem, and it keeps trying.
Node::dial is the single attempt underneath, returning a Connection. Use it when you want to own
the retry loop yourself.
zyris::DEFAULT_SERVER_URL is wss://attacca.cc/api/zyris/v1/ws. To point a node somewhere else,
pass a different URL; the examples read it from ZYRIS_SERVER_URL.
Staying up and stopping
tokio::select! {
closed = link.wait_closed() => closed?, // the server gave up on us
_ = tokio::signal::ctrl_c() => link.disconnect().await,
}Link method | What it does |
|---|---|
wait_closed() | Resolves when the link is finished for good. |
disconnect() | Ends the link, giving the closing frame time to land. |
address() | The NodeAddress from the latest handshake — address.path() is system/program/node. |
node_id() | The current node id. New on every connect that did not resume. |
The library installs no signal handler and sets no exit code. When the process stops is the program's decision.
Consuming the other side
on_connect is the consume half of a node. It runs once per connection, concurrently with it, and
receives the Connection:
use std::time::Duration;
let node = Node::builder()
.name("my-node")
.capability(HelloServer(HelloWorld))
.on_connect(|conn| async move {
// Every capability the server announced, by descriptor.
for cap in conn.peer_descriptors() {
println!("server offers {} v{}", cap.name, cap.version);
}
})
.build()?;To call a peer's tools with types, ask the connection for the generated client:
conn.capability::<SomeClient>() returns it if it is announced now, and
conn.wait_capability::<SomeClient>(timeout) waits for the announcement. See
Consuming attacca_api for a full example.
TLS
Connecting to wss:// needs a TLS provider, and none is on by default, because both compile C
code. Pick exactly one:
zyris = { git = "https://github.com/attacca-cc/zyris-protocol", features = ["tls-ring"] }| Feature | Provider |
|---|---|
tls-ring | ring. Needs a working C compiler. Turned on by enroll. |
tls-aws-lc | aws-lc-rs. Needs cmake too on most targets. Wins if both are on. |
A build with neither fails the dial with ConnectError::NoTlsProvider before any socket is opened,
rather than panicking inside rustls. An application that installs a rustls CryptoProvider itself
is trusted and needs neither feature.
Handling connection errors
ConnectError separates what a person has to fix from what time will fix:
use zyris::ConnectError;
match error {
ConnectError::Revoked | ConnectError::Unauthorized => {
// The credential is revoked, retired or wrong. Forget it and enroll again.
}
ConnectError::VersionMismatch { ours, theirs } => {
// The two ends speak different major versions. Retrying will not help.
}
ConnectError::NoTlsProvider => {
// A build fault: add `tls-ring` or `tls-aws-lc`.
}
ConnectError::Unreachable(transport) => {
// Network trouble. Retrying is the whole answer.
}
}