use std::io::Write;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Mutex;
use prost::Message;
use running_process::proto::daemon::{
DaemonRequest, RegisterRequest, RequestType, UnregisterRequest,
};
static TRACKING_CHECKED: AtomicBool = AtomicBool::new(false);
static TRACKING_DISABLED: AtomicBool = AtomicBool::new(false);
static REQUEST_ID: AtomicU64 = AtomicU64::new(1);
static CONNECTION: Mutex<Option<interprocess::local_socket::Stream>> = Mutex::new(None);
fn is_tracking_enabled() -> bool {
if !TRACKING_CHECKED.load(Ordering::Relaxed) {
let disabled = std::env::var("RUNNING_PROCESS_NO_TRACKING")
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false);
TRACKING_DISABLED.store(disabled, Ordering::Relaxed);
TRACKING_CHECKED.store(true, Ordering::Release);
}
!TRACKING_DISABLED.load(Ordering::Relaxed)
}
fn next_id() -> u64 {
REQUEST_ID.fetch_add(1, Ordering::Relaxed)
}
fn socket_path() -> String {
running_process::client::paths::socket_path(None)
}
fn make_socket_name(path: &str) -> std::io::Result<interprocess::local_socket::Name<'_>> {
running_process::client::paths::make_socket_name(path)
}
fn try_connect() -> Option<interprocess::local_socket::Stream> {
let path = socket_path();
let name = make_socket_name(&path).ok()?;
use interprocess::local_socket::traits::Stream as _;
interprocess::local_socket::Stream::connect(name).ok()
}
fn send_to_daemon(request: &DaemonRequest) {
if !is_tracking_enabled() {
return;
}
let mut guard = match CONNECTION.lock() {
Ok(g) => g,
Err(_) => return, };
if guard.is_none() {
*guard = try_connect();
}
let conn = match guard.as_mut() {
Some(c) => c,
None => return, };
let payload = request.encode_to_vec();
let len = (payload.len() as u32).to_be_bytes();
let ok =
conn.write_all(&len).is_ok() && conn.write_all(&payload).is_ok() && conn.flush().is_ok();
if !ok {
*guard = None;
}
}
pub fn daemon_register(pid: u32, created_at: f64, kind: &str, command: &str, cwd: Option<&str>) {
let request = DaemonRequest {
id: next_id(),
r#type: RequestType::Register as i32,
protocol_version: 1,
client_name: "running-process-py".to_string(),
register: Some(RegisterRequest {
pid,
created_at,
kind: kind.to_string(),
command: command.to_string(),
cwd: cwd.unwrap_or("").to_string(),
originator: String::new(),
containment: "contained".to_string(),
}),
..Default::default()
};
send_to_daemon(&request);
}
pub fn daemon_unregister(pid: u32) {
let request = DaemonRequest {
id: next_id(),
r#type: RequestType::Unregister as i32,
protocol_version: 1,
client_name: "running-process-py".to_string(),
unregister: Some(UnregisterRequest { pid }),
..Default::default()
};
send_to_daemon(&request);
}