use crate::VERSION;
use lazy_static::lazy_static;
use msgbox::IconType;
use std::sync::mpsc::sync_channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::RecvTimeoutError;
use std::sync::mpsc::SendError;
use std::sync::mpsc::SyncSender;
use std::sync::Mutex;
use std::thread;
use std::thread::sleep;
use std::time::Duration;
lazy_static! {
static ref MESSAGE_CHANNEL: (SyncSender<String>, Mutex<Receiver<String>>) = {
let (tx, rx) = sync_channel(QUEUE_LEN);
(tx, Mutex::new(rx))
};
}
lazy_static! {
static ref DIALOG_TITLE_LINE: String = format!(
"{} (v{})",
&DIALOG_TITLE,
VERSION.unwrap_or("unknown")
);
}
lazy_static! {
static ref BUSY_LOCK: Mutex<()> = Mutex::new(());
}
pub const QUEUE_LEN: usize = 30;
const DIALOG_TITLE: &str = "Tp-Note";
#[cfg(feature = "message-box")]
const KEEP_ALIVE: u64 = 1000;
const FLUSH_TIMEOUT: u64 = 10;
pub struct AlertService {}
impl AlertService {
pub fn init() {
lazy_static::initialize(&MESSAGE_CHANNEL);
thread::spawn(move || {
AlertService::run();
});
}
fn run() {
let (_, rx) = &*MESSAGE_CHANNEL;
let rx = rx.lock().unwrap();
let mut opt_guard = None;
loop {
let msg = if opt_guard.is_none() {
Some(rx.recv().unwrap())
} else {
match rx.recv_timeout(Duration::from_millis(KEEP_ALIVE)) {
Ok(s) => Some(s),
Err(RecvTimeoutError::Timeout) => None,
Err(RecvTimeoutError::Disconnected) => panic!(),
}
};
match msg {
Some(s) => {
if opt_guard.is_none() {
opt_guard = BUSY_LOCK.try_lock().ok();
}
Self::print_error(&s);
}
None => {
opt_guard = None;
}
}
}
}
pub fn flush() {
sleep(Duration::from_millis(FLUSH_TIMEOUT));
let _res = BUSY_LOCK.lock();
}
#[inline]
pub fn push_str(msg: String) -> Result<(), SendError<String>> {
let (tx, _) = &*MESSAGE_CHANNEL;
tx.send(msg)
}
#[inline]
fn print_error(msg: &str) {
let _ = msgbox::create(&*DIALOG_TITLE_LINE, msg, IconType::Info);
}
}