sxmotify 0.1.1

Create, modify, and delete sxmo notifications
Documentation
use crate::notification_directory;
use std::{fs, io, path};

const NONEXISTENT_PATH: &str = "/no/such/file/at/all";

fn path_in_directory(file_name: String) -> path::PathBuf {
    let mut result = notification_directory();
    result.push(file_name);
    result
}

fn file_path(id: &str) -> path::PathBuf {
    path_in_directory(format!("{}", id))
}

fn temp_file_path(id: &str) -> path::PathBuf {
    path_in_directory(format!("{}~", id))
}

fn add_autoremoval(command: String, file_path: &path::Path) -> String {
    format!("rm -f {}; {}", file_path.display(), command)
}

fn format_notification(text: String, command: String, watched_file: &path::Path) -> String {
    format!(
        "{}\n{}\n{}\n",
        command,
        watched_file.to_string_lossy(),
        text
    )
}

/// Set the notification with the provided ID. This will override any previous notifications
/// with that ID.
pub fn set_notification(
    id: String,
    text: String,
    command: String,
    watched_file: Option<&path::Path>,
) -> io::Result<()> {
    let nonexistent_path = path::PathBuf::from(NONEXISTENT_PATH);
    let watched_file = match watched_file {
        Some(watched_file) => watched_file,
        None => &nonexistent_path,
    };
    let temp_file_name = temp_file_path(&id);
    let file_name = file_path(&id);
    let notification = format_notification(
        text,
        add_autoremoval(command, file_name.as_path()),
        watched_file,
    );
    fs::write(temp_file_name.as_path(), notification)?;
    fs::rename(temp_file_name, file_name)
}

/// Clear the notification with a given ID. If successful, it guarantees no notification with
/// this ID exists anymore.
pub fn clear_notification(id: String) -> io::Result<()> {
    let file_name = file_path(&id);
    match fs::remove_file(file_name) {
        Ok(()) => Ok(()),
        Err(e) => {
            if e.kind() == io::ErrorKind::NotFound {
                // Ignore not found, as the notification is cleared.
                Ok(())
            } else {
                Err(e)
            }
        }
    }
}