use super::protocol::IpcRequest;
use std::sync::{
Arc, Mutex, OnceLock,
atomic::{AtomicBool, Ordering},
};
static HEADLESS_SHUTDOWN: OnceLock<Arc<AtomicBool>> = OnceLock::new();
static IPC_RECEIVER: OnceLock<Mutex<Option<std::sync::mpsc::Receiver<IpcRequest>>>> =
OnceLock::new();
static R_IS_AT_PROMPT: OnceLock<AtomicBool> = OnceLock::new();
static IN_ALTERNATE_MODE: AtomicBool = AtomicBool::new(false);
static BREAK_SIGNAL: OnceLock<Arc<AtomicBool>> = OnceLock::new();
pub(super) fn r_is_at_prompt() -> &'static AtomicBool {
R_IS_AT_PROMPT.get_or_init(|| AtomicBool::new(false))
}
pub fn set_r_at_prompt(at_prompt: bool) {
r_is_at_prompt().store(at_prompt, Ordering::Release);
}
pub fn set_in_alternate_mode(active: bool) {
IN_ALTERNATE_MODE.store(active, Ordering::Release);
}
pub fn is_in_alternate_mode() -> bool {
IN_ALTERNATE_MODE.load(Ordering::Acquire)
}
pub fn break_signal() -> Arc<AtomicBool> {
BREAK_SIGNAL
.get_or_init(|| Arc::new(AtomicBool::new(false)))
.clone()
}
pub(super) fn fire_break_signal() {
if let Some(signal) = BREAK_SIGNAL.get() {
signal.store(true, Ordering::Relaxed);
}
}
pub fn set_headless_shutdown(flag: Arc<AtomicBool>) {
let _ = HEADLESS_SHUTDOWN.set(flag);
}
pub fn trigger_headless_shutdown() -> bool {
if let Some(flag) = HEADLESS_SHUTDOWN.get() {
flag.store(true, Ordering::Release);
true
} else {
false
}
}
pub fn has_headless_shutdown_handler() -> bool {
HEADLESS_SHUTDOWN.get().is_some()
}
pub fn headless_shutdown_requested() -> bool {
HEADLESS_SHUTDOWN
.get()
.is_some_and(|flag| flag.load(Ordering::Acquire))
}
pub(super) fn install_receiver(rx: std::sync::mpsc::Receiver<IpcRequest>) -> std::io::Result<()> {
match IPC_RECEIVER.get() {
Some(existing) => {
*existing.lock().unwrap() = Some(rx);
}
None => {
IPC_RECEIVER
.set(Mutex::new(Some(rx)))
.map_err(|_| std::io::Error::other("IPC receiver already initialized"))?;
}
}
Ok(())
}
pub(super) fn clear_receiver() {
if let Some(receiver) = IPC_RECEIVER.get() {
*receiver.lock().unwrap() = None;
}
}
pub(super) fn drain_requests(mut handle: impl FnMut(IpcRequest)) -> bool {
let receiver = match IPC_RECEIVER.get() {
Some(r) => r,
None => return false, };
let rx = match receiver.try_lock() {
Ok(rx) => rx,
Err(_) => return false,
};
let rx = match rx.as_ref() {
Some(rx) => rx,
None => return false, };
let mut processed = false;
for request in rx.try_iter().take(128) {
processed = true;
handle(request);
}
processed
}
pub(super) fn try_receive_request() -> Option<IpcRequest> {
let receiver = IPC_RECEIVER.get()?;
let guard = receiver.try_lock().ok()?;
guard.as_ref()?.try_recv().ok()
}