RKIK
May 11, 2026 · View on GitHub
Table of Contents
Architecture
rkik is a Rust CLI with a reusable library. The split is intentional and strict: no clap, console, or process::exit in library code.
The main execution path for an NTP probe:
CLI (legacy.rs / rkik.rs)
└─ services::query::query_one()
├─ adapters::resolver::resolve_ip() (DNS)
└─ adapters::ntp_client (rsntp → ProbeResult)
└─ [--nts] adapters::nts_client (rkik-nts → NtsTimeResult)
Compare mode runs all queries concurrently via futures::join_all.
Feature flags:
| Feature | Default | Description |
|---|---|---|
json | yes | serde::Serialize on domain types; JSON formatters |
nts | yes | NTS support via rkik-nts |
sync | yes | System clock sync (Unix, root) |
network-tests | no | Integration tests hitting real servers |
Code layout
src/
bin/rkik.rs # modern subcommand CLI (clap)
bin/rkik/
legacy.rs # legacy one-shot CLI (backwards compat)
config_store.rs # TOML-backed config + presets
lib.rs # public API re-exports
adapters/
resolver.rs # DNS resolution
ntp_client.rs # rsntp wrapper → ProbeResult
nts_client.rs # rkik-nts wrapper (feature nts)
domain/
ntp.rs # Target, ProbeResult
services/
query.rs # query_one()
compare.rs # compare_many()
fmt/
text.rs # terminal rendering
json.rs # JSON serialization
stats.rs # Stats, compute_stats()
sync/ # clock sync (feature sync)
error.rs # RkikError
tests/
integration.rs # basic lib integration tests
nts_test.rs # NTS rendering and validation tests
cli_test.rs # CLI smoke tests (assert_cmd)
Library API
Add to Cargo.toml:
[dependencies]
rkik = { version = "2", default-features = false, features = ["json"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
Types
pub struct Target {
pub name: String,
pub ip: std::net::IpAddr,
pub port: u16,
}
pub struct ProbeResult {
pub target: Target,
pub offset_ms: f64, // signed: positive = local clock ahead
pub rtt_ms: f64,
pub stratum: u8,
pub ref_id: String,
pub utc: chrono::DateTime<chrono::Utc>,
pub local: chrono::DateTime<chrono::Local>,
pub timestamp: i64,
pub authenticated: bool,
}
With the json feature, these derive serde::Serialize.
Functions
pub async fn query_one(
target: &str,
ipv6_only: bool,
timeout: std::time::Duration,
use_nts: bool,
nts_ke_port: u16,
) -> Result<ProbeResult, RkikError>;
pub async fn compare_many(
targets: &[String],
ipv6_only: bool,
timeout: std::time::Duration,
use_nts: bool,
nts_ke_port: u16,
) -> Result<Vec<ProbeResult>, RkikError>;
Example
use rkik::{query_one, compare_many};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Single probe
let r = query_one("time.google.com", false, Duration::from_secs(3), false, 4460).await?;
println!("{}: offset={:.3}ms rtt={:.3}ms", r.target.name, r.offset_ms, r.rtt_ms);
// Parallel compare
let targets = vec!["pool.ntp.org".into(), "time.cloudflare.com".into()];
let results = compare_many(&targets, false, Duration::from_secs(3), false, 4460).await?;
for p in &results {
println!("{}: {:.3}ms", p.target.name, p.offset_ms);
}
Ok(())
}
Building and testing
# Standard build
cargo build --release
# Run tests (no network)
cargo test
# Run with real NTP servers
cargo test --features network-tests
# Minimal build (no NTS, no sync)
cargo build --no-default-features --features json
# Lint
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
Run cargo test for unit and integration tests. Network integration tests (hitting real servers) require --features network-tests.
Packaging and releases
Packaging metadata lives in Cargo.toml under [package.metadata.deb] and [package.metadata.generate-rpm]. CI builds .deb, .rpm, and tar.gz artifacts and publishes them to GitHub Releases alongside a cargo publish for crates.io.
Distribution packages:
| Platform | Package | Link |
|---|---|---|
| Arch Linux | rkik-git (AUR) | https://aur.archlinux.org/packages/rkik-git |
| Nix / NixOS | rkik (nixpkgs) | https://search.nixos.org/packages?query=rkik |
| All Linux | .deb / .rpm / tar.gz | GitHub Releases |
Contributing
- Fork the repo and create a feature branch from
master. - Keep the library/CLI split: no
clap,console, orprocess::exitinsrc/lib.rsor anything it re-exports. - Run
cargo fmtandcargo clippy -- -D warningsbefore pushing. - Add or update tests for any behaviour change.
- Open a PR referencing the relevant issue. Commit messages follow the
type: descriptionconvention (feat:,fix:,docs:,chore:).
If you're looking for a starting point, check the good first issue label.