#[cfg(feature = "web")]
pub mod server;
#[cfg(feature = "tui")]
pub mod tui;
pub mod __internal;
pub mod diff;
pub mod state;
pub use lupa_macros::{inspect, snapshot, snapshot_diff};
pub use state::Snapshot;
#[cfg(feature = "tui")]
pub use tui::run as run_tui;
#[derive(Debug, Clone, Copy)]
pub enum RunMode {
Web,
Tui,
Both,
}
pub fn run() -> std::io::Result<()> {
match (cfg!(feature = "web"), cfg!(feature = "tui")) {
(true, false) => run_mode(RunMode::Web),
(false, true) => run_mode(RunMode::Tui),
(true, true) => run_mode(RunMode::Both),
(false, false) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
"at least one of 'web' or 'tui' features must be enabled",
)),
}
}
pub fn run_mode(mode: RunMode) -> std::io::Result<()> {
match mode {
RunMode::Web => {
#[cfg(feature = "web")]
{
keep_alive();
Ok(())
}
#[cfg(not(feature = "web"))]
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"web feature is not enabled",
))
}
RunMode::Tui => {
#[cfg(feature = "tui")]
{
tui::run()
}
#[cfg(not(feature = "tui"))]
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"tui feature is not enabled",
))
}
RunMode::Both => {
#[cfg(all(feature = "web", feature = "tui"))]
{
let _ = &*server::INSPECTOR_SERVER; tui::run() }
#[cfg(not(all(feature = "web", feature = "tui")))]
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"both web and tui features are required for Both mode",
))
}
}
}
#[cfg(feature = "web")]
pub fn keep_alive() {
let _ = &*server::INSPECTOR_SERVER;
let running = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
let r = running.clone();
ctrlc_install(move || r.store(false, std::sync::atomic::Ordering::SeqCst));
eprintln!("lupa: press Ctrl+C to exit…");
while running.load(std::sync::atomic::Ordering::SeqCst) {
std::thread::sleep(std::time::Duration::from_millis(100));
}
eprintln!("lupa: bye!");
}
#[cfg(unix)]
fn ctrlc_install(f: impl Fn() + Send + Sync + 'static) {
use std::os::raw::c_int;
unsafe extern "C" {
fn signal(sig: c_int, handler: extern "C" fn(c_int)) -> extern "C" fn(c_int);
}
static CB: std::sync::OnceLock<Box<dyn Fn() + Send + Sync>> = std::sync::OnceLock::new();
CB.set(Box::new(f)).ok();
extern "C" fn handler(_: c_int) {
if let Some(cb) = CB.get() { cb(); }
}
unsafe { signal(2, handler); }
}
#[cfg(windows)]
fn ctrlc_install(f: impl Fn() + Send + 'static) {
let _ = f;
}
#[cfg(not(any(unix, windows)))]
fn ctrlc_install(f: impl Fn() + Send + 'static) {
let _ = f;
}