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}