pub mod client;
mod server;
pub use server::DaemonServer;
use std::path::{Path, PathBuf};
#[must_use]
pub fn build_engine_handle(
profiles_dir: &Path,
) -> Option<crate::vortix_core::engine::EngineHandle> {
use crate::state::Protocol;
use crate::tunnel::{tunnel_for, TunnelKind};
use crate::vortix_config::profile_store::{FsProfileStore, ProfileStore};
use crate::vortix_core::engine::{Engine, EngineHandle};
use crate::vortix_core::profile::{ProfileId, ProtocolKind};
use crate::vortix_protocol_wireguard::WgTunnel;
let _runner = crate::vortix_process::global_runner().as_real()?;
let journal = crate::vortix_core::journal::global_journal().cloned()?;
let resolver_dir = profiles_dir.to_path_buf();
let resolver = move |id: &ProfileId| {
let store = FsProfileStore::new(resolver_dir.clone());
store.get(id).ok()
};
let factory_config_dir =
crate::utils::get_app_config_dir().unwrap_or_else(|_| PathBuf::from("/tmp"));
let factory = move |profile: &crate::vortix_core::profile::Profile| {
let proto = match profile.protocol {
ProtocolKind::OpenVpn => Protocol::OpenVPN,
_ => Protocol::WireGuard,
};
tunnel_for(proto, &factory_config_dir, "3", 30)
};
let initial_tunnel = TunnelKind::WireGuard(WgTunnel::new());
let engine = Engine::new(initial_tunnel, resolver).with_tunnel_factory(factory);
Some(EngineHandle::local(engine, journal))
}
#[must_use]
pub fn default_socket_path() -> PathBuf {
if let Ok(rt) = std::env::var("XDG_RUNTIME_DIR") {
if !rt.is_empty() {
return PathBuf::from(rt).join("vortix.sock");
}
}
if let Ok(tmp) = std::env::var("TMPDIR") {
if !tmp.is_empty() {
return PathBuf::from(tmp).join("vortix.sock");
}
}
PathBuf::from("/tmp/vortix.sock")
}
#[must_use]
pub fn daemon_socket_path_override() -> Option<PathBuf> {
match std::env::var("VORTIX_DAEMON_SOCKET") {
Ok(s) if !s.is_empty() => Some(PathBuf::from(s)),
_ => None,
}
}
#[must_use]
pub fn daemon_socket_path_if_present() -> Option<PathBuf> {
let candidate = daemon_socket_path_override().unwrap_or_else(default_socket_path);
if candidate.exists() && is_unix_socket(&candidate) {
Some(candidate)
} else {
None
}
}
#[cfg(unix)]
fn is_unix_socket(path: &Path) -> bool {
use std::os::unix::fs::FileTypeExt;
std::fs::metadata(path)
.map(|m| m.file_type().is_socket())
.unwrap_or(false)
}
#[cfg(not(unix))]
fn is_unix_socket(_path: &Path) -> bool {
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn regular_file_is_not_a_unix_socket() {
let tmp = tempfile::tempdir().unwrap();
let regular = tmp.path().join("not-a-socket");
std::fs::write(®ular, b"hello").unwrap();
assert!(!is_unix_socket(®ular));
}
#[test]
fn missing_path_is_not_a_unix_socket() {
let tmp = tempfile::tempdir().unwrap();
let missing = tmp.path().join("does-not-exist");
assert!(!is_unix_socket(&missing));
}
#[test]
fn bound_unix_socket_is_detected() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("sock");
let _listener = std::os::unix::net::UnixListener::bind(&path).unwrap();
assert!(is_unix_socket(&path));
}
}