[ MIRROR ] Customisable, minimalist screen locker for Wayland git.ngill.net/nlock.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187// SPDX-License-Identifier: GPL-3.0-or-later// Copyright (C) 2026, Nathan Gill
use std::{ marker::PhantomData, os::fd::{AsFd, OwnedFd},};
use anyhow::{Result, anyhow};use nix::errno::Errno;
use crate::auth::AuthState;
/// A one-way pipe based communication channelpub struct PipeCommChannel<T> { tx: OwnedFd, rx: OwnedFd, _marker: PhantomData<T>,}
impl<T> PipeCommChannel<T>where T: AsBytes + FromBytes,{ pub fn new() -> Result<Self> { let p = nix::unistd::pipe()?; Ok(Self { tx: p.1, rx: p.0, _marker: PhantomData, }) }
pub fn write(&self, msg: T) -> Result<()> { let msg_buf = msg.as_bytes(); let size_buf = msg_buf.len().to_ne_bytes();
write(&self.tx, &size_buf)?; write(&self.tx, &msg_buf)?;
Ok(()) }
pub fn read(&self) -> Result<T> { let mut size_buf = [0u8; std::mem::size_of::<usize>()]; read(&self.rx, &mut size_buf)?;
let size = usize::from_ne_bytes(size_buf); let mut msg_buf = vec![0u8; size]; read(&self.rx, &mut msg_buf)?;
let msg = T::from_bytes(&msg_buf).ok_or(anyhow!("Failed to convert message"))?;
Ok(msg) }
pub fn tx(&self) -> &OwnedFd { &self.tx }
pub fn rx(&self) -> &OwnedFd { &self.rx }}
/// Wrapper of `nix::unistd::read` which re-tries on interruptfn read<Fd>(fd: Fd, buf: &mut [u8]) -> Result<usize>where Fd: AsFd,{ loop { match nix::unistd::read(&fd, buf) { Ok(sz) => return Ok(sz), Err(Errno::EINTR) => continue, Err(e) => return Err(anyhow!("read failed: {e}")), } }}
/// Wrapper of `nix::unistd::write` which re-tries on interruptfn write<Fd>(fd: Fd, buf: &[u8]) -> Result<usize>where Fd: AsFd,{ loop { match nix::unistd::write(&fd, buf) { Ok(sz) => return Ok(sz), Err(Errno::EINTR) => continue, Err(e) => return Err(anyhow!("write failed: {e}")), } }}
pub trait AsBytes { /// Convert to a bytes-like representation of the object fn as_bytes(&self) -> Vec<u8>;}
impl AsBytes for String { fn as_bytes(&self) -> Vec<u8> { self.as_bytes().to_vec() }}
impl AsBytes for bool { fn as_bytes(&self) -> Vec<u8> { match self { false => vec![0u8], true => vec![1u8], } }}
impl AsBytes for AuthState { fn as_bytes(&self) -> Vec<u8> { match self { Self::Idle => vec![0u8], Self::Success => vec![1u8], Self::Fail => vec![2u8], } }}
impl AsBytes for () { fn as_bytes(&self) -> Vec<u8> { vec![0u8] }}
pub trait FromBytes { /// Convert from a bytes-like representation of the object fn from_bytes(bytes: &[u8]) -> Option<Self> where Self: Sized;}
impl FromBytes for String { fn from_bytes(bytes: &[u8]) -> Option<Self> where Self: Sized, { Self::from_utf8(bytes.to_vec()).ok() }}
impl FromBytes for bool { fn from_bytes(bytes: &[u8]) -> Option<Self> where Self: Sized, { if bytes.len() != 1 { return None; } match bytes[0] { 0u8 => Some(false), 1u8 => Some(true), _ => None, } }}
impl FromBytes for AuthState { fn from_bytes(bytes: &[u8]) -> Option<Self> where Self: Sized, { if bytes.len() != 1 { return None; } match bytes[0] { 0u8 => Some(Self::Idle), 1u8 => Some(Self::Success), 2u8 => Some(Self::Fail), _ => None, } }}
impl FromBytes for () { fn from_bytes(_: &[u8]) -> Option<Self> where Self: Sized, { Some(()) }}