fm/event/
ipc_socket.rs

1use std::{
2    io::{Read, Write},
3    os::unix::{
4        fs::PermissionsExt,
5        net::{UnixListener, UnixStream},
6    },
7};
8
9use anyhow::{bail, Result};
10use clap::Parser;
11
12use crate::io::Args;
13
14/// filepath of the socked used
15/// If the user provided a filepath (will be the case if you use neovim
16/// companion plugin [fm-picker.nvim](https://github.com/qkzk/fm-picker.nvim))
17/// then we use it.
18/// Otherwise, it's `/tmp/fm-socket-{pid}.sock` where `pid` is the process
19/// identifier of the current process.
20pub fn build_input_socket_filepath() -> String {
21    let args = Args::parse();
22    if let Some(socket_adress) = args.input_socket {
23        crate::log_info!("Using socket provided in args : #{socket_adress}#");
24        socket_adress
25    } else {
26        format!("/tmp/fm-socket-{pid}.sock", pid = std::process::id())
27    }
28}
29
30/// Creates UNIX socket stream used by the application
31/// If the user provided an input socket from args, it will use it. Otherwise, it will use "/tmp/fm-socket-{pid}.sock"
32/// where pid is the process identifier of the application itself.
33/// Read timeout is set to 1_000_000 ns = 0.001 s
34/// Returns the pair "file_path, stream"
35pub fn create_stream() -> Result<(String, UnixListener)> {
36    let file_path = build_input_socket_filepath();
37    let stream = match UnixListener::bind(&file_path) {
38        Ok(stream) => stream,
39        Err(err) => {
40            crate::log_info!("Couldn't create stream. {file_path}");
41            bail!(err)
42        }
43    };
44    std::fs::set_permissions(&file_path, std::fs::Permissions::from_mode(0o600))?;
45    crate::log_info!("created output socket at {file_path}");
46    Ok((file_path, stream))
47}
48
49/// Read from an UNIX socket stream and return its output as a `String`.
50pub fn read_from_stream(stream: &mut UnixStream) -> Option<String> {
51    let mut buffer = String::new();
52    stream.read_to_string(&mut buffer).ok()?;
53    if !buffer.is_empty() {
54        crate::log_info!("read from socket: ####{buffer}");
55        Some(buffer)
56    } else {
57        None
58    }
59}
60
61/// Writes a string to an UNIX socket.
62///
63/// # Errors
64///
65/// May fail if the unix socket is closed or if the user can't write to it.
66pub fn write_to_stream(stream: &mut UnixStream, data: String) -> Result<()> {
67    stream.write_all(data.as_bytes())?;
68    Ok(())
69}
70
71pub fn remove_socket(socket_path: &str) {
72    std::fs::remove_file(socket_path).expect("Couldn't delete socket file");
73    crate::log_info!("Deleted socket {socket_path}");
74    crate::log_info!("terminating refresher");
75}