ZyrisDocs

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()?;
MethodWhat 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 methodWhat 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"] }
FeatureProvider
tls-ringring. Needs a working C compiler. Turned on by enroll.
tls-aws-lcaws-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.
    }
}

On this page