poki_launcher_notifier/
lib.rs1use failure::Error;
18use std::fs::File;
19use std::io::prelude::*;
20use std::path::Path;
21use std::sync::mpsc::{self, Receiver};
22use std::thread;
23
24const LOCK_FILE_PATH: &str = "/tmp/poki-launcher.pid";
25
26pub enum Msg {
27 Show,
28 Exit,
29}
30
31pub fn is_running() -> bool {
32 Path::new(&LOCK_FILE_PATH).exists()
33}
34
35pub struct Notifier(Receiver<Msg>);
36
37impl Notifier {
38 pub fn start() -> Result<Notifier, Error> {
39 use nix::unistd::getpid;
40 use signal_hook::iterator::Signals;
41 use signal_hook::*;
42
43 let mut file = File::create(&LOCK_FILE_PATH)?;
44 write!(file, "{}", getpid())?;
45 drop(file);
46 let signals = Signals::new(&[SIGUSR1, SIGINT, SIGTERM, SIGQUIT])?;
47 let (tx, rx) = mpsc::channel();
48 thread::spawn(move || {
49 for signal in signals.forever() {
50 match signal {
51 SIGUSR1 => tx.send(Msg::Show).expect("Failed to send show message"),
52 SIGINT | SIGTERM | SIGQUIT => {
53 tx.send(Msg::Exit).expect("Failed to send show message");
54 break;
55 }
56 _ => (),
57 }
58 }
59 });
60 Ok(Notifier(rx))
61 }
62
63 pub fn recv(&self) -> Result<Msg, std::sync::mpsc::RecvError> {
64 self.0.recv()
65 }
66}
67
68impl Drop for Notifier {
69 fn drop(&mut self) {
70 if is_running() {
71 std::fs::remove_file(&LOCK_FILE_PATH).expect("Failed to delete lock file");
72 }
73 }
74}
75
76pub fn notify() -> Result<(), Error> {
77 use nix::sys::signal::{kill, Signal};
78 use nix::unistd::Pid;
79
80 let mut file = File::open(&LOCK_FILE_PATH)?;
81 let mut buf = String::new();
82 file.read_to_string(&mut buf)?;
83 kill(Pid::from_raw(buf.parse()?), Signal::SIGUSR1)?;
84 Ok(())
85}