Skip to main content

truffle_sidecar/
lib.rs

1//! # truffle-sidecar
2//!
3//! Provides the truffle mesh networking sidecar binary.
4//!
5//! This crate downloads the platform-specific Go sidecar binary at build time
6//! from truffle's GitHub releases. At runtime, [`sidecar_path`] resolves the
7//! binary location using a smart search order that works in both development
8//! (`cargo run`) and production (installed binary) scenarios.
9//!
10//! ## Usage
11//!
12//! ```rust,no_run
13//! use truffle_sidecar::sidecar_path;
14//!
15//! let path = sidecar_path();
16//! println!("Sidecar at: {}", path.display());
17//! ```
18//!
19//! ## Override
20//!
21//! Set `TRUFFLE_SIDECAR_PATH` environment variable at build time or runtime
22//! to use a custom sidecar binary:
23//!
24//! ```bash
25//! TRUFFLE_SIDECAR_PATH=/usr/local/bin/sidecar-slim cargo build
26//! ```
27//!
28//! Set `TRUFFLE_SIDECAR_SKIP_DOWNLOAD=1` to skip the build-time download
29//! (useful in CI where the sidecar is provided separately).
30
31use std::path::PathBuf;
32
33/// Known sidecar binary names (platform-aware).
34const SIDECAR_NAMES: &[&str] = if cfg!(windows) {
35    &[
36        "sidecar-slim.exe",
37        "truffle-sidecar.exe",
38        "sidecar-slim",
39        "truffle-sidecar",
40    ]
41} else {
42    &["sidecar-slim", "truffle-sidecar"]
43};
44
45/// Returns the path to the truffle sidecar binary.
46///
47/// Resolution order:
48/// 1. `TRUFFLE_SIDECAR_PATH` environment variable (runtime override)
49/// 2. Same directory as the current executable (production install)
50/// 3. Platform config directory (`~/.config/truffle/bin/` or equivalent)
51/// 4. System paths (`/usr/local/bin/` on Unix)
52/// 5. Build-time downloaded binary (development — `cargo run`)
53/// 6. Falls back to `"sidecar-slim"` (assumes on PATH)
54pub fn sidecar_path() -> PathBuf {
55    // 1. Runtime override
56    if let Ok(path) = std::env::var("TRUFFLE_SIDECAR_PATH") {
57        let p = PathBuf::from(&path);
58        if p.exists() {
59            return p;
60        }
61    }
62
63    // 2. Same directory as the current executable
64    let exe_dir = std::env::current_exe()
65        .ok()
66        .and_then(|p| p.parent().map(|d| d.to_path_buf()));
67
68    if let Some(ref dir) = exe_dir {
69        for name in SIDECAR_NAMES {
70            let candidate = dir.join(name);
71            if candidate.exists() {
72                return candidate;
73            }
74        }
75    }
76
77    // 3. Platform config directory
78    if let Some(config_dir) = config_bin_dir() {
79        for name in SIDECAR_NAMES {
80            let candidate = config_dir.join(name);
81            if candidate.exists() {
82                return candidate;
83            }
84        }
85    }
86
87    // 4. System paths (Unix only)
88    #[cfg(not(windows))]
89    {
90        for path in &["/usr/local/bin/sidecar-slim", "/usr/local/bin/truffle-sidecar"] {
91            let p = PathBuf::from(path);
92            if p.exists() {
93                return p;
94            }
95        }
96    }
97
98    // 5. Build-time path (set by build.rs via cargo:rustc-env)
99    let build_path = PathBuf::from(env!("TRUFFLE_SIDECAR_PATH"));
100    if build_path.exists() {
101        return build_path;
102    }
103
104    // 6. Fall back to PATH lookup at runtime
105    PathBuf::from("sidecar-slim")
106}
107
108/// Returns the version of the sidecar this crate was built to download.
109pub fn version() -> &'static str {
110    env!("CARGO_PKG_VERSION")
111}
112
113/// Platform config bin directory: `~/.config/truffle/bin/` (or equivalent).
114fn config_bin_dir() -> Option<PathBuf> {
115    // Use XDG_CONFIG_HOME on Linux, ~/Library/Application Support on macOS,
116    // %APPDATA% on Windows — via the same logic as the `dirs` crate but
117    // without adding a dependency.
118    #[cfg(target_os = "macos")]
119    {
120        std::env::var("HOME")
121            .ok()
122            .map(|h| PathBuf::from(h).join("Library/Application Support/truffle/bin"))
123    }
124
125    #[cfg(target_os = "linux")]
126    {
127        std::env::var("XDG_CONFIG_HOME")
128            .ok()
129            .map(PathBuf::from)
130            .or_else(|| std::env::var("HOME").ok().map(|h| PathBuf::from(h).join(".config")))
131            .map(|d| d.join("truffle/bin"))
132    }
133
134    #[cfg(target_os = "windows")]
135    {
136        std::env::var("APPDATA")
137            .ok()
138            .map(|d| PathBuf::from(d).join("truffle\\bin"))
139    }
140
141    #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
142    {
143        None
144    }
145}