atagen

roundabout

public
Star0
Watch0
9117440444eb609ecea8476b5a62b03917077591
1
ssh://brewery@pls.lobotomise.me:33/atagen/roundabout.git

Blame: src/client.rs

6f5b84fad3efatagen2026-09-27 03:59 UTC1
use std::{
6f5b84fad3efatagen2026-09-27 03:59 UTC2
    fs::{self, File, OpenOptions},
6f5b84fad3efatagen2026-09-27 03:59 UTC3
    io,
6f5b84fad3efatagen2026-09-27 03:59 UTC4
    os::unix::{fs::OpenOptionsExt, net::UnixStream, process::CommandExt},
6f5b84fad3efatagen2026-09-27 03:59 UTC5
    process::{Command, Stdio},
6f5b84fad3efatagen2026-09-27 03:59 UTC6
    thread,
6f5b84fad3efatagen2026-09-27 03:59 UTC7
    time::Duration,
6f5b84fad3efatagen2026-09-27 03:59 UTC8
};
6f5b84fad3efatagen2026-09-27 03:59 UTC9
6f5b84fad3efatagen2026-09-27 03:59 UTC10
use crate::paths;
6f5b84fad3efatagen2026-09-27 03:59 UTC11
6f5b84fad3efatagen2026-09-27 03:59 UTC12
pub struct Flock(File);
6f5b84fad3efatagen2026-09-27 03:59 UTC13
6f5b84fad3efatagen2026-09-27 03:59 UTC14
impl Flock {
6f5b84fad3efatagen2026-09-27 03:59 UTC15
    pub fn exclusive(file: File) -> io::Result<Self> {
6f5b84fad3efatagen2026-09-27 03:59 UTC16
        use std::os::fd::AsRawFd;
6f5b84fad3efatagen2026-09-27 03:59 UTC17
        if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX) } != 0 {
6f5b84fad3efatagen2026-09-27 03:59 UTC18
            return Err(io::Error::last_os_error());
6f5b84fad3efatagen2026-09-27 03:59 UTC19
        }
6f5b84fad3efatagen2026-09-27 03:59 UTC20
        Ok(Self(file))
6f5b84fad3efatagen2026-09-27 03:59 UTC21
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC22
6f5b84fad3efatagen2026-09-27 03:59 UTC23
    pub fn try_exclusive(file: File) -> Option<Self> {
6f5b84fad3efatagen2026-09-27 03:59 UTC24
        use std::os::fd::AsRawFd;
6f5b84fad3efatagen2026-09-27 03:59 UTC25
        (unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) } == 0)
6f5b84fad3efatagen2026-09-27 03:59 UTC26
            .then_some(Self(file))
6f5b84fad3efatagen2026-09-27 03:59 UTC27
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC28
}
6f5b84fad3efatagen2026-09-27 03:59 UTC29
6f5b84fad3efatagen2026-09-27 03:59 UTC30
impl Drop for Flock {
6f5b84fad3efatagen2026-09-27 03:59 UTC31
    fn drop(&mut self) {
6f5b84fad3efatagen2026-09-27 03:59 UTC32
        use std::os::fd::AsRawFd;
6f5b84fad3efatagen2026-09-27 03:59 UTC33
        unsafe { libc::flock(self.0.as_raw_fd(), libc::LOCK_UN) };
6f5b84fad3efatagen2026-09-27 03:59 UTC34
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC35
}
6f5b84fad3efatagen2026-09-27 03:59 UTC36
6f5b84fad3efatagen2026-09-27 03:59 UTC37
pub fn spawn_lock() -> io::Result<Flock> {
6f5b84fad3efatagen2026-09-27 03:59 UTC38
    let file = OpenOptions::new()
6f5b84fad3efatagen2026-09-27 03:59 UTC39
        .create(true)
6f5b84fad3efatagen2026-09-27 03:59 UTC40
        .truncate(false)
6f5b84fad3efatagen2026-09-27 03:59 UTC41
        .write(true)
6f5b84fad3efatagen2026-09-27 03:59 UTC42
        .mode(0o600)
6f5b84fad3efatagen2026-09-27 03:59 UTC43
        .open(paths::spawn_lock())?;
6f5b84fad3efatagen2026-09-27 03:59 UTC44
    Flock::exclusive(file)
6f5b84fad3efatagen2026-09-27 03:59 UTC45
}
6f5b84fad3efatagen2026-09-27 03:59 UTC46
6f5b84fad3efatagen2026-09-27 03:59 UTC47
pub fn connect() -> Option<UnixStream> {
6f5b84fad3efatagen2026-09-27 03:59 UTC48
    UnixStream::connect(paths::socket()).ok()
6f5b84fad3efatagen2026-09-27 03:59 UTC49
}
6f5b84fad3efatagen2026-09-27 03:59 UTC50
6f5b84fad3efatagen2026-09-27 03:59 UTC51
pub fn connect_or_spawn() -> io::Result<UnixStream> {
6f5b84fad3efatagen2026-09-27 03:59 UTC52
    if let Some(s) = connect() {
6f5b84fad3efatagen2026-09-27 03:59 UTC53
        return Ok(s);
6f5b84fad3efatagen2026-09-27 03:59 UTC54
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC55
    let _lock = spawn_lock()?;
6f5b84fad3efatagen2026-09-27 03:59 UTC56
    if let Some(s) = connect() {
6f5b84fad3efatagen2026-09-27 03:59 UTC57
        return Ok(s);
6f5b84fad3efatagen2026-09-27 03:59 UTC58
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC59
    let _ = fs::remove_file(paths::socket());
6f5b84fad3efatagen2026-09-27 03:59 UTC60
    let log = OpenOptions::new()
6f5b84fad3efatagen2026-09-27 03:59 UTC61
        .create(true)
6f5b84fad3efatagen2026-09-27 03:59 UTC62
        .append(true)
6f5b84fad3efatagen2026-09-27 03:59 UTC63
        .open(paths::state_dir().join("daemon.log"))?;
6f5b84fad3efatagen2026-09-27 03:59 UTC64
    let mut cmd = Command::new(std::env::current_exe()?);
6f5b84fad3efatagen2026-09-27 03:59 UTC65
    cmd.arg("daemon")
6f5b84fad3efatagen2026-09-27 03:59 UTC66
        .stdin(Stdio::null())
6f5b84fad3efatagen2026-09-27 03:59 UTC67
        .stdout(Stdio::null())
6f5b84fad3efatagen2026-09-27 03:59 UTC68
        .stderr(log);
6f5b84fad3efatagen2026-09-27 03:59 UTC69
    unsafe {
6f5b84fad3efatagen2026-09-27 03:59 UTC70
        cmd.pre_exec(|| {
6f5b84fad3efatagen2026-09-27 03:59 UTC71
            libc::setsid();
6f5b84fad3efatagen2026-09-27 03:59 UTC72
            Ok(())
6f5b84fad3efatagen2026-09-27 03:59 UTC73
        });
6f5b84fad3efatagen2026-09-27 03:59 UTC74
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC75
    let mut child = cmd.spawn()?;
6f5b84fad3efatagen2026-09-27 03:59 UTC76
    for _ in 0..200 {
6f5b84fad3efatagen2026-09-27 03:59 UTC77
        if let Some(s) = connect() {
6f5b84fad3efatagen2026-09-27 03:59 UTC78
            let _ = child.wait();
6f5b84fad3efatagen2026-09-27 03:59 UTC79
            return Ok(s);
6f5b84fad3efatagen2026-09-27 03:59 UTC80
        }
6f5b84fad3efatagen2026-09-27 03:59 UTC81
        if let Ok(Some(status)) = child.try_wait()
6f5b84fad3efatagen2026-09-27 03:59 UTC82
            && !status.success()
6f5b84fad3efatagen2026-09-27 03:59 UTC83
        {
6f5b84fad3efatagen2026-09-27 03:59 UTC84
            return Err(io::Error::other(format!(
6f5b84fad3efatagen2026-09-27 03:59 UTC85
                "daemon died on startup ({status}), see {}",
6f5b84fad3efatagen2026-09-27 03:59 UTC86
                paths::state_dir().join("daemon.log").display()
6f5b84fad3efatagen2026-09-27 03:59 UTC87
            )));
6f5b84fad3efatagen2026-09-27 03:59 UTC88
        }
6f5b84fad3efatagen2026-09-27 03:59 UTC89
        thread::sleep(Duration::from_millis(10));
6f5b84fad3efatagen2026-09-27 03:59 UTC90
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC91
    Err(io::Error::other("daemon never showed up"))
6f5b84fad3efatagen2026-09-27 03:59 UTC92
}