| Crates.io | alpine-protocol-sdk |
| lib.rs | alpine-protocol-sdk |
| version | 0.2.4 |
| created_at | 2025-11-30 12:55:35.261083+00 |
| updated_at | 2026-01-15 17:09:22.463737+00 |
| description | High-level SDK on top of the ALPINE protocol layer. |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1958196 |
| size | 272,278 |
alpine-protocol-sdk is a high-level wrapper around the published alpine-protocol-rs
protocol artifacts. It keeps discovery, handshake, and streaming lifecycles explicit so
application code can reason about each step without diving into the lower-level
protocol helpers.
alpine-protocol-rs) gives you access to every message, frame, and
handshake primitive and is useful if you already have a transport layer or
want to implement a custom state machine.alpine-protocol-sdk) builds on top of the protocol layer and manages sockets,
keep-alive, and profile lifetimes so you can focus on discovery → connect →
streaming flows.DiscoveryClient (low-level) to find devices.
The runner performs unicast/broadcast/cached fallbacks and optional subnet scans.AlpineClient::connect with the discovered identity, capability set,
and a credential pair; the SDK spins up the transport plus the keep-alive task.AlpineClient::start_stream, pass a StreamProfile, and track the
returned config_id.send_frame to push encoded FrameEnvelopes or send_control for
control envelopes.AlpineClient::ping, status, health, identity, or metadata to
send the corresponding control command and receive typed replies when the
device returns structured CBOR payloads.use alpine_protocol_sdk::{
AlpineClient,
DiscoveryRunOptions,
run_discovery_with_options,
TrustConfig,
load_or_fetch_trust_view,
};
use alpine_protocol_rs::{crypto::identity::NodeCredentials, messages::DeviceIdentity};
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
#[tokio::main]
async fn main() -> Result<(), alpine_protocol_sdk::AlpineSdkError> {
let trust = TrustConfig::new("https://panel.y-link.no/attesters/latest".into())
.with_root_pubkey(alpine_protocol_sdk::parse_root_pubkey_base64(
"BASE64_ED25519_ROOT_PUBKEY",
)?);
let trust_view = load_or_fetch_trust_view(&trust).await?;
let mut opts = DiscoveryRunOptions::default();
opts.attester_registry = Some(trust_view.registry.clone());
let outcome = run_discovery_with_options(
SocketAddr::new(IpAddr::V4(Ipv4Addr::BROADCAST), 19455),
opts,
)
.await?;
let remote = SocketAddr::new(outcome.peer.ip(), outcome.peer.port());
let identity = DeviceIdentity {
device_id: outcome.reply.device_id.clone(),
manufacturer_id: outcome.reply.manufacturer_id.clone(),
model_id: outcome.reply.model_id.clone(),
hardware_rev: outcome.reply.hardware_rev.clone(),
firmware_rev: outcome.reply.firmware_rev.clone(),
};
let credentials = NodeCredentials::load("path/to/credentials")?;
let capabilities = outcome.reply.capabilities.clone();
let mut client = AlpineClient::connect(
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
remote,
identity,
capabilities,
credentials,
)
.await?;
let config_id = client.start_stream(alpine_protocol_rs::profile::StreamProfile::auto())?;
println!("Streaming with config id {}", config_id);
Ok(())
}
The runner is designed to "just work" on most networks:
prefer_multicast = true).scan_subnets = true).These behaviors are explicit in DiscoveryRunOptions; aggressive scanning is opt-in.
If you need per-attempt visibility (e.g., broadcast blocked vs unicast denied), use the report helpers:
run_discovery_with_reportrun_discovery_with_options_reportThese return a DiscoveryRunReport with a result plus a list of DiscoveryAttempt
entries that include target, mode, local bind, and any error details observed.
Common discovery error hints:
discovery channel permission denied → UDP send/recv blocked by OS policy or firewall.broadcast discovery blocked → network policy prevents broadcast.multicast discovery unavailable → multicast not permitted on this network.discovery timed out → no replies observed before the timeout.Discovery trust state:
DiscoveryOutcome::trust_state() to get a strict DeviceTrustState enum
instead of parsing the optional attestation error string.DiscoveryOutcome::require_trusted() to obtain a TrustedDiscoveryOutcome
or a clear AlpineSdkError::UntrustedDevice.Discovery retries:
run_discovery_with_retry or run_discovery_with_options_retry with a
DiscoveryRetryPolicy to add exponential backoff across discovery runs.To verify device identity attestations, you must supply a root public key and bundle URL. The SDK does not auto-load environment variables; your application should configure them.
Recommended variables for your app or CLI:
ALPINE_ATTESTERS_URLALPINE_ROOT_PUBKEY_B64The ping, status, health, identity, and metadata helpers send a vendor
control command payload ({ "command": "status" }) via ControlOp::Vendor.
Ensure your device firmware responds to those vendor commands (not only get_status).
Use AlpineClient::probe_status() for a single canonical liveness + health check.
It runs ping, then status, and optionally health if status is unavailable.
The ProbeResult includes a normalized ProbeState (Online, Degraded, Offline)
along with per-step errors and round-trip timings.
Use ProbeResult::to_device_state(trust_state) to normalize probe + trust into a
DeviceState snapshot suitable for UI status badges.
Use AlpineClient::control_with_options with ControlOptions to add per-call
timeouts and retries. The retry policy uses exponential backoff capped by
backoff_max_ms.
Use connect_with_policy to enforce discovery → trust → handshake → first probe.
The default ConnectPolicy requires a trusted identity, probes after handshake,
and rejects Offline (and optionally Degraded) devices.
If you have a DiscoveryRunReport, use connect_with_policy_from_report to
include discovery attempt diagnostics in any discovery/probe failure.
Use DiscoveryRunOptions::defaults_for_lan() for a safe LAN baseline.
Use discover_with_cache or discover_with_cache_report to try cached targets
before falling back to broadcast.
Every exported module in this crate has /// documentation so the generated
docs on docs.rs describe the same lifecycle described here.
Use discovery_dry_run to inspect the computed interfaces and broadcast targets
without sending any packets. This is useful when debugging permissions or NIC
selection issues.
If your device implements the standard control op, call
AlpineClient::status_standard() (uses ControlOp::GetStatus).
If your device only implements vendor commands, call status_vendor() or
status() (vendor command payload).
SafeClient wraps an AlpineClient and enforces a probe before control or
stream calls. Use SafeClientOptions to require online or accept degraded.
SessionGuard tracks idle time and lets you expire or close sessions after
an inactivity timeout.
Use enforce_trust_policy with TrustPolicy to apply strict or warn-only
trust behavior based on DeviceTrustState.
Use init_pretty_logging() or init_json_logging() to set up a default
tracing subscriber with env-based filtering.
See sdk/docs/troubleshooting.md for common failure modes and debugging tips.
ALPINE_ROOT_PUBKEY_B64.status_vendor() or status() for vendor-only devices.ALPINE_VERSION.